projectLatestAlerts.spec.tsx 5.9 KB

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