edit.spec.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import {metric} from 'sentry/utils/analytics';
  4. import MetricRulesEdit from 'sentry/views/alerts/rules/metric/edit';
  5. import {AlertRuleTriggerType} from 'sentry/views/alerts/rules/metric/types';
  6. jest.mock('sentry/utils/analytics', () => ({
  7. metric: {
  8. startTransaction: jest.fn(() => ({
  9. setTag: jest.fn(),
  10. setData: jest.fn(),
  11. })),
  12. endTransaction: jest.fn(),
  13. },
  14. }));
  15. describe('MetricRulesEdit', function () {
  16. beforeEach(function () {
  17. MockApiClient.addMockResponse({
  18. url: '/organizations/org-slug/users/',
  19. body: [],
  20. });
  21. MockApiClient.addMockResponse({
  22. url: '/organizations/org-slug/tags/',
  23. body: [],
  24. });
  25. MockApiClient.addMockResponse({
  26. url: '/projects/org-slug/project-slug/environments/',
  27. body: [],
  28. });
  29. MockApiClient.addMockResponse({
  30. url: '/organizations/org-slug/events-stats/',
  31. body: null,
  32. });
  33. MockApiClient.addMockResponse({
  34. url: '/organizations/org-slug/events-meta/',
  35. body: {count: 5},
  36. });
  37. MockApiClient.addMockResponse({
  38. url: '/organizations/org-slug/alert-rules/available-actions/',
  39. body: [
  40. {
  41. allowedTargetTypes: ['user', 'team'],
  42. integrationName: null,
  43. type: 'email',
  44. integrationId: null,
  45. },
  46. ],
  47. });
  48. MockApiClient.addMockResponse({
  49. url: '/organizations/org-slug/members/',
  50. body: [TestStubs.Member()],
  51. });
  52. });
  53. afterEach(() => {
  54. MockApiClient.clearMockResponses();
  55. jest.clearAllMocks();
  56. });
  57. it('renders and edits trigger', async function () {
  58. const {organization, project} = initializeOrg();
  59. const rule = TestStubs.MetricRule();
  60. const onChangeTitleMock = jest.fn();
  61. const req = MockApiClient.addMockResponse({
  62. url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`,
  63. body: rule,
  64. });
  65. const editRule = MockApiClient.addMockResponse({
  66. url: `/projects/${organization.slug}/project-slug/alert-rules/${rule.id}/`,
  67. method: 'PUT',
  68. body: rule,
  69. });
  70. render(
  71. <MetricRulesEdit
  72. params={{
  73. projectId: project.slug,
  74. ruleId: rule.id,
  75. }}
  76. organization={organization}
  77. onChangeTitle={onChangeTitleMock}
  78. project={project}
  79. />
  80. );
  81. // has existing trigger
  82. expect(screen.getByTestId('critical-threshold')).toHaveValue('70');
  83. expect(screen.getByTestId('resolve-threshold')).toHaveValue('36');
  84. expect(req).toHaveBeenCalled();
  85. // Check correct rule name is called
  86. expect(onChangeTitleMock).toHaveBeenCalledWith(rule.name);
  87. await userEvent.clear(screen.getByTestId('resolve-threshold'));
  88. await userEvent.type(screen.getByTestId('resolve-threshold'), '7');
  89. // Create a new action
  90. await userEvent.click(screen.getByLabelText('Add Action'));
  91. // Save Trigger
  92. await userEvent.click(screen.getByLabelText('Save Rule'));
  93. expect(metric.startTransaction).toHaveBeenCalledWith({name: 'saveAlertRule'});
  94. expect(editRule).toHaveBeenCalledWith(
  95. expect.anything(),
  96. expect.objectContaining({
  97. data: expect.objectContaining({
  98. aggregation: 0,
  99. dataset: 'events',
  100. id: '4',
  101. name: 'My Incident Rule',
  102. projects: ['project-slug'],
  103. query: '',
  104. status: 0,
  105. timeWindow: 60,
  106. thresholdType: 0,
  107. resolveThreshold: 7,
  108. triggers: [
  109. expect.objectContaining({
  110. actions: [
  111. expect.objectContaining({
  112. integrationId: null,
  113. targetIdentifier: '',
  114. targetType: 'user',
  115. type: 'email',
  116. options: null,
  117. }),
  118. ],
  119. alertRuleId: '4',
  120. alertThreshold: 70,
  121. id: '1',
  122. }),
  123. ],
  124. }),
  125. method: 'PUT',
  126. })
  127. );
  128. // New Trigger should be in list
  129. // Has correct values
  130. expect(screen.getByTestId('critical-threshold')).toHaveValue('70');
  131. expect(screen.getByTestId('resolve-threshold')).toHaveValue('7');
  132. });
  133. it('removes warning trigger', async function () {
  134. const {organization, project} = initializeOrg();
  135. const rule = TestStubs.MetricRule();
  136. rule.triggers.push({
  137. label: AlertRuleTriggerType.WARNING,
  138. alertThreshold: 13,
  139. actions: [],
  140. });
  141. rule.resolveThreshold = 12;
  142. MockApiClient.addMockResponse({
  143. url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`,
  144. body: rule,
  145. });
  146. const editRule = MockApiClient.addMockResponse({
  147. url: `/projects/${organization.slug}/project-slug/alert-rules/${rule.id}/`,
  148. method: 'PUT',
  149. body: rule,
  150. });
  151. render(
  152. <MetricRulesEdit
  153. params={{
  154. orgId: organization.slug,
  155. projectId: project.slug,
  156. ruleId: rule.id,
  157. }}
  158. organization={organization}
  159. onChangeTitle={() => {}}
  160. project={project}
  161. />
  162. );
  163. // has existing trigger
  164. expect(screen.getByTestId('critical-threshold')).toHaveValue('70');
  165. expect(screen.getByTestId('warning-threshold')).toHaveValue('13');
  166. expect(screen.getByTestId('resolve-threshold')).toHaveValue('12');
  167. // Clear warning Trigger
  168. await userEvent.clear(screen.getByTestId('warning-threshold'));
  169. await userEvent.click(screen.getByLabelText('Save Rule'));
  170. expect(editRule).toHaveBeenCalledWith(
  171. expect.anything(),
  172. expect.objectContaining({
  173. data: expect.objectContaining({
  174. aggregation: 0,
  175. dataset: 'events',
  176. id: '4',
  177. name: 'My Incident Rule',
  178. projects: ['project-slug'],
  179. query: '',
  180. status: 0,
  181. timeWindow: 60,
  182. resolveThreshold: 12,
  183. thresholdType: 0,
  184. triggers: [
  185. expect.objectContaining({
  186. actions: [],
  187. alertRuleId: '4',
  188. alertThreshold: 70,
  189. id: '1',
  190. }),
  191. ],
  192. }),
  193. method: 'PUT',
  194. })
  195. );
  196. });
  197. it('renders 404', function () {
  198. const {organization, project} = initializeOrg();
  199. MockApiClient.addMockResponse({
  200. url: `/organizations/${organization.slug}/alert-rules/1234/`,
  201. statusCode: 404,
  202. body: {},
  203. });
  204. render(
  205. <MetricRulesEdit
  206. params={{
  207. orgId: organization.slug,
  208. projectId: project.slug,
  209. ruleId: '1234',
  210. }}
  211. organization={organization}
  212. project={project}
  213. />
  214. );
  215. expect(screen.getByText('This alert rule could not be found.')).toBeInTheDocument();
  216. });
  217. });