projectLatestAlerts.spec.tsx 5.9 KB

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