index.spec.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import {EventsStatsFixture} from 'sentry-fixture/events';
  2. import {GroupFixture} from 'sentry-fixture/group';
  3. import {IncidentFixture} from 'sentry-fixture/incident';
  4. import {MetricRuleFixture} from 'sentry-fixture/metricRule';
  5. import {ProjectFixture} from 'sentry-fixture/project';
  6. import {initializeOrg} from 'sentry-test/initializeOrg';
  7. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  8. import ProjectsStore from 'sentry/stores/projectsStore';
  9. import {trackAnalytics} from 'sentry/utils/analytics';
  10. import MetricAlertDetails from 'sentry/views/alerts/rules/metric/details';
  11. import {Dataset} from 'sentry/views/alerts/rules/metric/types';
  12. jest.mock('sentry/utils/analytics');
  13. describe('MetricAlertDetails', () => {
  14. const project = ProjectFixture({slug: 'earth', platform: 'javascript'});
  15. beforeEach(() => {
  16. act(() => ProjectsStore.loadInitialData([project]));
  17. MockApiClient.addMockResponse({
  18. url: '/organizations/org-slug/projects/',
  19. body: [project],
  20. });
  21. MockApiClient.addMockResponse({
  22. url: '/organizations/org-slug/users/',
  23. body: [],
  24. });
  25. MockApiClient.addMockResponse({
  26. url: '/organizations/org-slug/events-stats/',
  27. body: EventsStatsFixture(),
  28. });
  29. MockApiClient.addMockResponse({
  30. url: '/organizations/org-slug/issues/?end=2017-10-17T02%3A41%3A20&groupStatsPeriod=auto&limit=5&project=2&query=event.type%3Aerror&sort=freq&start=2017-10-10T02%3A41%3A20',
  31. body: [GroupFixture()],
  32. });
  33. });
  34. afterEach(() => {
  35. act(() => ProjectsStore.reset());
  36. jest.resetAllMocks();
  37. MockApiClient.clearMockResponses();
  38. });
  39. it('renders', async () => {
  40. const {routerContext, organization, routerProps} = initializeOrg();
  41. const incident = IncidentFixture();
  42. const rule = MetricRuleFixture({
  43. projects: [project.slug],
  44. latestIncident: incident,
  45. });
  46. MockApiClient.addMockResponse({
  47. url: `/organizations/org-slug/alert-rules/${rule.id}/`,
  48. body: rule,
  49. });
  50. MockApiClient.addMockResponse({
  51. url: `/organizations/org-slug/incidents/`,
  52. body: [incident],
  53. });
  54. render(
  55. <MetricAlertDetails
  56. organization={organization}
  57. {...routerProps}
  58. params={{ruleId: rule.id}}
  59. />,
  60. {context: routerContext, organization}
  61. );
  62. expect(await screen.findAllByText(rule.name)).toHaveLength(2);
  63. expect(screen.getByText('Change alert status to Resolved')).toBeInTheDocument();
  64. expect(screen.getByText(`#${incident.identifier}`)).toBeInTheDocument();
  65. // Related issues
  66. expect(screen.getByTestId('group')).toBeInTheDocument();
  67. expect(trackAnalytics).toHaveBeenCalledWith(
  68. 'alert_rule_details.viewed',
  69. expect.objectContaining({
  70. rule_id: Number(rule.id),
  71. alert: '',
  72. })
  73. );
  74. });
  75. it('renders selected incident', async () => {
  76. const {routerContext, organization, router, routerProps} = initializeOrg();
  77. const rule = MetricRuleFixture({projects: [project.slug]});
  78. const incident = IncidentFixture();
  79. MockApiClient.addMockResponse({
  80. url: `/organizations/org-slug/alert-rules/${rule.id}/`,
  81. body: rule,
  82. });
  83. const incidentMock = MockApiClient.addMockResponse({
  84. url: `/organizations/org-slug/incidents/${incident.id}/`,
  85. body: incident,
  86. });
  87. MockApiClient.addMockResponse({
  88. url: `/organizations/org-slug/incidents/`,
  89. body: [incident],
  90. });
  91. // Related issues to the selected incident
  92. const issuesRequest = MockApiClient.addMockResponse({
  93. url: '/organizations/org-slug/issues/?end=2016-04-26T19%3A44%3A05&groupStatsPeriod=auto&limit=5&project=2&query=event.type%3Aerror&sort=freq&start=2016-03-29T19%3A44%3A05',
  94. body: [GroupFixture()],
  95. });
  96. render(
  97. <MetricAlertDetails
  98. organization={organization}
  99. {...routerProps}
  100. location={{...router.location, query: {alert: incident.id}}}
  101. params={{ruleId: rule.id}}
  102. />,
  103. {context: routerContext, organization}
  104. );
  105. expect(await screen.findAllByText(rule.name)).toHaveLength(2);
  106. // Related issues
  107. expect(screen.getByTestId('group')).toBeInTheDocument();
  108. expect(trackAnalytics).toHaveBeenCalledWith(
  109. 'alert_rule_details.viewed',
  110. expect.objectContaining({
  111. rule_id: Number(rule.id),
  112. alert: '321',
  113. })
  114. );
  115. expect(incidentMock).toHaveBeenCalled();
  116. expect(issuesRequest).toHaveBeenCalled();
  117. });
  118. it('renders mute button for metric alert', async () => {
  119. const {routerContext, organization, routerProps} = initializeOrg();
  120. const incident = IncidentFixture();
  121. const rule = MetricRuleFixture({
  122. projects: [project.slug],
  123. latestIncident: incident,
  124. });
  125. MockApiClient.addMockResponse({
  126. url: `/organizations/org-slug/alert-rules/${rule.id}/`,
  127. body: rule,
  128. });
  129. MockApiClient.addMockResponse({
  130. url: `/organizations/org-slug/incidents/`,
  131. body: [incident],
  132. });
  133. const postRequest = MockApiClient.addMockResponse({
  134. url: `/projects/${organization.slug}/${project.slug}/alert-rules/${rule.id}/snooze/`,
  135. method: 'POST',
  136. });
  137. const deleteRequest = MockApiClient.addMockResponse({
  138. url: `/projects/${organization.slug}/${project.slug}/alert-rules/${rule.id}/snooze/`,
  139. method: 'DELETE',
  140. });
  141. render(
  142. <MetricAlertDetails
  143. {...routerProps}
  144. organization={organization}
  145. params={{ruleId: rule.id}}
  146. />,
  147. {context: routerContext, organization}
  148. );
  149. expect(await screen.findByText('Mute for me')).toBeInTheDocument();
  150. await userEvent.click(screen.getByRole('button', {name: 'Mute for me'}));
  151. expect(postRequest).toHaveBeenCalledTimes(1);
  152. expect(await screen.findByText('Unmute')).toBeInTheDocument();
  153. await userEvent.click(screen.getByRole('button', {name: 'Unmute'}));
  154. expect(deleteRequest).toHaveBeenCalledTimes(1);
  155. });
  156. it('renders open in discover button with dataset=errors for is:unresolved query', async () => {
  157. const {routerContext, organization, routerProps} = initializeOrg({
  158. organization: {features: ['discover-basic', 'metric-alert-ignore-archived']},
  159. });
  160. const rule = MetricRuleFixture({
  161. projects: [project.slug],
  162. dataset: Dataset.ERRORS,
  163. query: 'is:unresolved',
  164. });
  165. MockApiClient.addMockResponse({
  166. url: `/organizations/org-slug/alert-rules/${rule.id}/`,
  167. body: rule,
  168. });
  169. MockApiClient.addMockResponse({
  170. url: `/organizations/org-slug/incidents/`,
  171. body: [],
  172. });
  173. MockApiClient.addMockResponse({
  174. url: '/organizations/org-slug/issues/?end=2017-10-17T02%3A41%3A20&groupStatsPeriod=auto&limit=5&project=2&query=event.type%3Aerror%20is%3Aunresolved&sort=freq&start=2017-10-10T02%3A41%3A20',
  175. body: [],
  176. });
  177. render(
  178. <MetricAlertDetails
  179. organization={organization}
  180. {...routerProps}
  181. params={{ruleId: rule.id}}
  182. />,
  183. {context: routerContext, organization}
  184. );
  185. expect(await screen.findAllByText(rule.name)).toHaveLength(2);
  186. expect(screen.getByRole('button', {name: 'Open in Discover'})).toHaveAttribute(
  187. 'href',
  188. expect.stringContaining('dataset=errors')
  189. );
  190. });
  191. });