projectLatestAlerts.spec.tsx 5.9 KB

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