projectLatestAlerts.spec.jsx 5.2 KB

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