projectLatestAlerts.spec.jsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen} from 'sentry-test/reactTestingLibrary';
  3. import {textWithMarkupMatcher} from 'sentry-test/utils';
  4. import ProjectLatestAlerts from 'sentry/views/projectDetail/projectLatestAlerts';
  5. describe('ProjectDetail > ProjectLatestAlerts', function () {
  6. let endpointMock, rulesEndpointMock;
  7. const {organization, project, router, routerContext} = initializeOrg();
  8. beforeEach(function () {
  9. endpointMock = MockApiClient.addMockResponse({
  10. url: `/organizations/${organization.slug}/incidents/`,
  11. body: [
  12. TestStubs.Incident({id: 1, status: 20}), // critical
  13. TestStubs.Incident({id: 2, status: 10}), // warning
  14. TestStubs.Incident({id: 3, status: 2}), // closed
  15. ],
  16. });
  17. rulesEndpointMock = MockApiClient.addMockResponse({
  18. url: `/organizations/${organization.slug}/alert-rules/`,
  19. body: [TestStubs.MetricRule()],
  20. });
  21. });
  22. afterEach(function () {
  23. MockApiClient.clearMockResponses();
  24. });
  25. it('renders a list', function () {
  26. render(
  27. <ProjectLatestAlerts
  28. organization={organization}
  29. projectSlug={project.slug}
  30. location={router.location}
  31. isProjectStabilized
  32. />,
  33. {context: routerContext}
  34. );
  35. expect(endpointMock).toHaveBeenCalledTimes(2); // one for closed, one for open
  36. expect(rulesEndpointMock).toHaveBeenCalledTimes(0);
  37. expect(endpointMock).toHaveBeenCalledWith(
  38. expect.anything(),
  39. expect.objectContaining({
  40. query: {per_page: 3, status: expect.anything()},
  41. })
  42. );
  43. expect(screen.getByText('Latest Alerts')).toBeInTheDocument();
  44. expect(screen.getAllByText('Too many Chrome errors')).toHaveLength(3);
  45. expect(
  46. screen.getAllByRole('link', {name: 'Too many Chrome errors'})[0]
  47. ).toHaveAttribute(
  48. 'href',
  49. '/organizations/org-slug/alerts/123/'
  50. );
  51. expect(
  52. screen.getAllByText(textWithMarkupMatcher('Triggered 2 years ago'))
  53. ).toHaveLength(2);
  54. expect(
  55. screen.getByText(textWithMarkupMatcher('Resolved a year ago'))
  56. ).toBeInTheDocument();
  57. expect(screen.getByLabelText('Critical')).toBeInTheDocument();
  58. expect(screen.getByLabelText('Warning')).toBeInTheDocument();
  59. expect(screen.getByLabelText('Resolved')).toBeInTheDocument();
  60. });
  61. it('shows the empty state', async function () {
  62. MockApiClient.addMockResponse({
  63. url: `/organizations/${organization.slug}/incidents/`,
  64. body: [],
  65. });
  66. render(
  67. <ProjectLatestAlerts
  68. organization={organization}
  69. projectSlug={project.slug}
  70. location={router.location}
  71. isProjectStabilized
  72. />
  73. );
  74. expect(rulesEndpointMock).toHaveBeenCalledWith(
  75. expect.anything(),
  76. expect.objectContaining({
  77. query: {per_page: 1},
  78. })
  79. );
  80. expect(await screen.findByText('No alerts found')).toBeInTheDocument();
  81. });
  82. it('shows configure alerts buttons', async function () {
  83. MockApiClient.addMockResponse({
  84. url: `/organizations/${organization.slug}/incidents/`,
  85. body: [],
  86. });
  87. MockApiClient.addMockResponse({
  88. url: `/organizations/${organization.slug}/alert-rules/`,
  89. body: [],
  90. });
  91. render(
  92. <ProjectLatestAlerts
  93. organization={organization}
  94. projectSlug={project.slug}
  95. location={router.location}
  96. isProjectStabilized
  97. />,
  98. {context: routerContext}
  99. );
  100. expect(await screen.findByRole('button', {name: 'Create Alert'})).toHaveAttribute(
  101. 'href',
  102. `/organizations/${organization.slug}/alerts/wizard/?referrer=project_detail&project=project-slug`
  103. );
  104. expect(screen.getByRole('button', {name: 'Learn More'})).toHaveAttribute(
  105. 'href',
  106. 'https://docs.sentry.io/product/alerts-notifications/metric-alerts/'
  107. );
  108. });
  109. it('calls API with the right params', function () {
  110. render(
  111. <ProjectLatestAlerts
  112. organization={organization}
  113. projectSlug={project.slug}
  114. location={{
  115. query: {statsPeriod: '7d', environment: 'staging', somethingBad: 'nope'},
  116. }}
  117. isProjectStabilized
  118. />
  119. );
  120. expect(endpointMock).toHaveBeenCalledWith(
  121. expect.anything(),
  122. expect.objectContaining({
  123. query: {per_page: 3, statsPeriod: '7d', environment: 'staging', status: 'open'},
  124. })
  125. );
  126. });
  127. it('handles null dateClosed with resolved alerts', function () {
  128. MockApiClient.addMockResponse({
  129. url: `/organizations/${organization.slug}/incidents/`,
  130. body: [
  131. TestStubs.Incident({id: 1, status: 20}), // critical
  132. TestStubs.Incident({id: 2, status: 10}), // warning
  133. TestStubs.Incident({id: 3, status: 2, dateClosed: null}), // closed with null dateClosed
  134. ],
  135. });
  136. render(
  137. <ProjectLatestAlerts
  138. organization={organization}
  139. projectSlug={project.slug}
  140. location={router.location}
  141. isProjectStabilized
  142. />
  143. );
  144. expect(screen.getByText('Resolved')).toBeInTheDocument();
  145. });
  146. it('does not call API if project is not stabilized yet', function () {
  147. render(
  148. <ProjectLatestAlerts
  149. organization={organization}
  150. projectSlug={project.slug}
  151. location={router.location}
  152. isProjectStabilized={false}
  153. />
  154. );
  155. expect(endpointMock).toHaveBeenCalledTimes(0);
  156. });
  157. });