thresholdGroupRows.spec.tsx 6.8 KB

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