projectIssues.spec.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import {GroupFixture} from 'sentry-fixture/group';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import ProjectIssues from 'sentry/views/projectDetail/projectIssues';
  5. describe('ProjectDetail > ProjectIssues', function () {
  6. let endpointMock: ReturnType<typeof MockApiClient.addMockResponse>,
  7. filteredEndpointMock: ReturnType<typeof MockApiClient.addMockResponse>,
  8. newIssuesEndpointMock: ReturnType<typeof MockApiClient.addMockResponse>;
  9. const {organization, router, project, routerContext} = initializeOrg({
  10. organization: {
  11. features: ['discover-basic'],
  12. },
  13. });
  14. beforeEach(function () {
  15. endpointMock = MockApiClient.addMockResponse({
  16. url: `/organizations/${organization.slug}/issues/?limit=5&query=error.unhandled%3Atrue%20is%3Aunresolved&sort=freq&statsPeriod=14d`,
  17. body: [GroupFixture(), GroupFixture({id: '2'})],
  18. });
  19. filteredEndpointMock = MockApiClient.addMockResponse({
  20. url: `/organizations/${organization.slug}/issues/?environment=staging&limit=5&query=error.unhandled%3Atrue%20is%3Aunresolved&sort=freq&statsPeriod=7d`,
  21. body: [GroupFixture(), GroupFixture({id: '2'})],
  22. });
  23. newIssuesEndpointMock = MockApiClient.addMockResponse({
  24. url: `/organizations/${organization.slug}/issues/?limit=5&query=is%3Aunresolved%20is%3Afor_review&sort=freq&statsPeriod=14d`,
  25. body: [GroupFixture(), GroupFixture({id: '2'})],
  26. });
  27. MockApiClient.addMockResponse({
  28. url: `/organizations/${organization.slug}/users/`,
  29. body: [],
  30. });
  31. MockApiClient.addMockResponse({
  32. url: `/organizations/${organization.slug}/issues-count/?project=${project.id}&query=is%3Aunresolved%20is%3Afor_review&query=&query=is%3Aresolved&query=error.unhandled%3Atrue%20is%3Aunresolved&query=regressed_in_release%3Alatest&statsPeriod=14d`,
  33. body: {},
  34. });
  35. MockApiClient.addMockResponse({
  36. url: `/organizations/${organization.slug}/issues-count/?environment=staging&project=${project.id}&query=is%3Aunresolved%20is%3Afor_review&query=&query=is%3Aresolved&query=error.unhandled%3Atrue%20is%3Aunresolved&query=regressed_in_release%3Alatest&statsPeriod=7d`,
  37. body: {},
  38. });
  39. });
  40. afterEach(function () {
  41. MockApiClient.clearMockResponses();
  42. jest.clearAllMocks();
  43. });
  44. it('renders a list', async function () {
  45. MockApiClient.addMockResponse({
  46. url: `/organizations/org-slug/issues/?limit=5&query=error.unhandled%3Atrue%20is%3Aunresolved&sort=freq&statsPeriod=14d`,
  47. body: [GroupFixture(), GroupFixture({id: '2'})],
  48. });
  49. render(
  50. <ProjectIssues
  51. api={new MockApiClient()}
  52. organization={organization}
  53. location={router.location}
  54. projectId={parseInt(project.id, 10)}
  55. />,
  56. {
  57. context: routerContext,
  58. organization,
  59. }
  60. );
  61. expect(await screen.findAllByTestId('group')).toHaveLength(2);
  62. });
  63. it('renders a link to Issues', async function () {
  64. render(
  65. <ProjectIssues
  66. api={new MockApiClient()}
  67. organization={organization}
  68. projectId={parseInt(project.id, 10)}
  69. location={router.location}
  70. />,
  71. {
  72. context: routerContext,
  73. organization,
  74. }
  75. );
  76. const link = screen.getByLabelText('Open in Issues');
  77. expect(link).toBeInTheDocument();
  78. await userEvent.click(link);
  79. expect(router.push).toHaveBeenCalledWith({
  80. pathname: '/organizations/org-slug/issues/',
  81. query: {
  82. limit: 5,
  83. query: 'error.unhandled:true is:unresolved',
  84. sort: 'freq',
  85. statsPeriod: '14d',
  86. },
  87. });
  88. });
  89. it('renders a segmented control', async function () {
  90. render(
  91. <ProjectIssues
  92. api={new MockApiClient()}
  93. organization={organization}
  94. location={router.location}
  95. projectId={parseInt(project.id, 10)}
  96. />,
  97. {
  98. context: routerContext,
  99. organization,
  100. }
  101. );
  102. // "Unhandled" segment is selected
  103. const unhandledSegment = screen.getByRole('radio', {name: 'Unhandled 0'});
  104. expect(unhandledSegment).toBeInTheDocument();
  105. expect(unhandledSegment).toBeChecked();
  106. // Select "New Issues" segment
  107. const newIssuesSegment = screen.getByRole('radio', {name: 'New Issues 0'});
  108. expect(newIssuesSegment).toBeInTheDocument();
  109. expect(newIssuesSegment).not.toBeChecked();
  110. await userEvent.click(newIssuesSegment);
  111. await waitFor(() => expect(newIssuesSegment).toBeChecked());
  112. expect(newIssuesEndpointMock).toHaveBeenCalled();
  113. });
  114. it('renders a link to Discover', async function () {
  115. render(
  116. <ProjectIssues
  117. api={new MockApiClient()}
  118. organization={organization}
  119. location={router.location}
  120. projectId={parseInt(project.id, 10)}
  121. />,
  122. {
  123. context: routerContext,
  124. organization,
  125. }
  126. );
  127. const link = screen.getByLabelText('Open in Discover');
  128. expect(link).toBeInTheDocument();
  129. await userEvent.click(link);
  130. expect(router.push).toHaveBeenCalledWith({
  131. pathname: `/organizations/${organization.slug}/discover/results/`,
  132. query: {
  133. display: 'top5',
  134. field: ['issue', 'title', 'count()', 'count_unique(user)', 'project'],
  135. name: 'Frequent Unhandled Issues',
  136. query: 'event.type:error error.unhandled:true',
  137. sort: ['-count'],
  138. statsPeriod: '14d',
  139. },
  140. });
  141. });
  142. it('changes according to global header', async function () {
  143. render(
  144. <ProjectIssues
  145. organization={organization}
  146. api={new MockApiClient()}
  147. projectId={parseInt(project.id, 10)}
  148. location={{
  149. ...router.location,
  150. query: {statsPeriod: '7d', environment: 'staging', somethingBad: 'nope'},
  151. }}
  152. />,
  153. {context: routerContext, organization}
  154. );
  155. expect(endpointMock).toHaveBeenCalledTimes(0);
  156. expect(filteredEndpointMock).toHaveBeenCalledTimes(1);
  157. const link = screen.getByLabelText('Open in Issues');
  158. expect(link).toBeInTheDocument();
  159. await userEvent.click(link);
  160. expect(router.push).toHaveBeenCalledWith({
  161. pathname: `/organizations/${organization.slug}/issues/`,
  162. query: {
  163. limit: 5,
  164. environment: 'staging',
  165. statsPeriod: '7d',
  166. query: 'error.unhandled:true is:unresolved',
  167. sort: 'freq',
  168. },
  169. });
  170. });
  171. });