thresholdGroupRows.spec.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import {ProjectFixture} from 'sentry-fixture/project';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  4. import type {Organization} from 'sentry/types/organization';
  5. import {OrganizationContext} from 'sentry/views/organizationContext';
  6. import type {Threshold} from 'sentry/views/releases/utils/types';
  7. import {ThresholdGroupRows, type ThresholdGroupRowsProps} from './thresholdGroupRows';
  8. describe('ThresholdGroupRows', () => {
  9. const PROJECT_NAME = 'test-project';
  10. const {organization} = initializeOrg({
  11. organization: {
  12. name: 'test-org',
  13. slug: 'test-thresholds',
  14. features: [],
  15. },
  16. });
  17. const getThreshold = (thresholdData: Partial<Threshold> = {}): Threshold => ({
  18. id: '1',
  19. threshold_type: 'threshold_group',
  20. trigger_type: 'over',
  21. window_in_seconds: 3600,
  22. environment: {
  23. id: '1',
  24. name: 'production',
  25. displayName: 'Production',
  26. },
  27. project: ProjectFixture({slug: PROJECT_NAME}),
  28. value: 100,
  29. ...thresholdData,
  30. });
  31. const wrapper = (org: Organization = organization) => {
  32. return function WrappedComponent({children}) {
  33. return (
  34. <OrganizationContext.Provider value={org}>
  35. {children}
  36. </OrganizationContext.Provider>
  37. );
  38. };
  39. };
  40. type RenderProps = ThresholdGroupRowsProps & {org: Organization};
  41. const DEFAULT_PROPS: RenderProps = {
  42. allEnvironmentNames: ['test'],
  43. project: ProjectFixture(),
  44. refetch: () => {},
  45. setTempError: () => {},
  46. org: organization,
  47. threshold: undefined,
  48. };
  49. const renderComponent = (props: Partial<RenderProps> = DEFAULT_PROPS) => {
  50. const {org, ...thresholdProps} = props;
  51. const Wrapper = wrapper(org);
  52. return render(
  53. <Wrapper>
  54. <ThresholdGroupRows {...DEFAULT_PROPS} {...thresholdProps} />
  55. </Wrapper>
  56. );
  57. };
  58. const mockThresholdApis = (data = {}) => {
  59. const methods = ['POST', 'PUT', 'DELETE'];
  60. const mocks = {};
  61. methods.forEach(method => {
  62. // /projects/test-thresholds/test-project/release-thresholds/1/
  63. mocks[`${method}-threshold`] = MockApiClient.addMockResponse({
  64. url: `/projects/${organization.slug}/${PROJECT_NAME}/release-thresholds/${method !== 'POST' ? '1/' : ''}`,
  65. method,
  66. body: data,
  67. });
  68. mocks[`${method}-alert`] = MockApiClient.addMockResponse({
  69. url: `/organizations/${organization.slug}/alert-rules/${method !== 'POST' ? '1/' : ''}`,
  70. method,
  71. body: data,
  72. });
  73. });
  74. return mocks;
  75. };
  76. const editThreshold = async (threshold: Threshold) => {
  77. const editButton = screen.getByRole('button', {name: 'Edit threshold'});
  78. await userEvent.click(editButton);
  79. const saveButton = await screen.findByRole('button', {name: 'Save'});
  80. expect(saveButton).toBeInTheDocument();
  81. const spinButtons = screen.getAllByRole('spinbutton');
  82. const thresholdValueInput = spinButtons.find(
  83. button => parseInt((button as HTMLButtonElement).value, 10) === threshold.value
  84. );
  85. if (!thresholdValueInput) throw new Error('Could not find threshold value input');
  86. // update the value to 200
  87. await userEvent.clear(thresholdValueInput);
  88. await userEvent.type(thresholdValueInput, '200');
  89. await userEvent.click(saveButton);
  90. };
  91. const createThreshold = async () => {
  92. const addButton = screen.getByRole('button', {name: 'New Threshold'});
  93. await userEvent.click(addButton);
  94. const saveButton = await screen.findByRole('button', {name: 'Save'});
  95. expect(saveButton).toBeInTheDocument();
  96. /* since we don't have client side validation, we can just click save */
  97. await userEvent.click(saveButton);
  98. };
  99. afterEach(() => {
  100. MockApiClient.clearMockResponses();
  101. });
  102. it('invokes the release-threshold api when flag is disabled and editing a threshold', async () => {
  103. const threshold = getThreshold();
  104. const mocks = mockThresholdApis();
  105. renderComponent({threshold});
  106. expect(await screen.findByText(threshold.value)).toBeInTheDocument();
  107. await editThreshold(threshold);
  108. expect(mocks['PUT-alert']).not.toHaveBeenCalled();
  109. expect(mocks['PUT-threshold']).toHaveBeenCalled();
  110. });
  111. it('invokes the alert-rules api when flag is enabled and editing a threshold', async () => {
  112. const threshold = getThreshold();
  113. const {organization: org} = initializeOrg({
  114. organization: {
  115. name: 'test-org',
  116. slug: 'test-thresholds',
  117. features: ['activated-alert-rules'],
  118. },
  119. });
  120. const mocks = mockThresholdApis();
  121. renderComponent({threshold, org});
  122. expect(await screen.findByText(threshold.value)).toBeInTheDocument();
  123. await editThreshold(threshold);
  124. expect(mocks['PUT-alert']).toHaveBeenCalled();
  125. expect(mocks['PUT-threshold']).not.toHaveBeenCalled();
  126. });
  127. it('uses the release-threshold api when deleting and disabeld', async () => {
  128. const threshold = getThreshold();
  129. const mocks = mockThresholdApis();
  130. renderComponent({threshold});
  131. expect(await screen.findByText(threshold.value)).toBeInTheDocument();
  132. const editButton = screen.getByRole('button', {name: 'Edit threshold'});
  133. await userEvent.click(editButton);
  134. const deleteButton = await screen.findByRole('button', {name: 'Delete threshold'});
  135. await userEvent.click(deleteButton);
  136. expect(mocks['DELETE-alert']).not.toHaveBeenCalled();
  137. expect(mocks['DELETE-threshold']).toHaveBeenCalled();
  138. });
  139. it('uses the alert-rules api when deleting and enabled', async () => {
  140. const threshold = getThreshold();
  141. const {organization: org} = initializeOrg({
  142. organization: {
  143. name: 'test-org',
  144. slug: 'test-thresholds',
  145. features: ['activated-alert-rules'],
  146. },
  147. });
  148. const mocks = mockThresholdApis();
  149. renderComponent({threshold, org});
  150. expect(await screen.findByText(threshold.value)).toBeInTheDocument();
  151. const editButton = screen.getByRole('button', {name: 'Edit threshold'});
  152. await userEvent.click(editButton);
  153. const deleteButton = await screen.findByRole('button', {name: 'Delete threshold'});
  154. await userEvent.click(deleteButton);
  155. expect(mocks['DELETE-alert']).toHaveBeenCalled();
  156. expect(mocks['DELETE-threshold']).not.toHaveBeenCalled();
  157. });
  158. it('uses the release-threshold api when creating a new threshold and disabled', async () => {
  159. const threshold = getThreshold();
  160. const mockThreshold = MockApiClient.addMockResponse({
  161. url: '/projects/test-thresholds/project-slug/release-thresholds/',
  162. method: 'POST',
  163. body: {},
  164. });
  165. renderComponent({threshold});
  166. await createThreshold();
  167. expect(mockThreshold).toHaveBeenCalled();
  168. });
  169. it('uses the alert-rules api when creating a new threshold and enabled', async () => {
  170. const threshold = getThreshold();
  171. const mockApi = MockApiClient.addMockResponse({
  172. url: '/organizations/test-thresholds/alert-rules/',
  173. method: 'POST',
  174. body: {},
  175. });
  176. const {organization: org} = initializeOrg({
  177. organization: {
  178. name: 'test-org',
  179. slug: 'test-thresholds',
  180. features: ['activated-alert-rules'],
  181. },
  182. });
  183. renderComponent({threshold, org});
  184. await createThreshold();
  185. expect(mockApi).toHaveBeenCalled();
  186. });
  187. });