releaseIssues.spec.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import {GroupFixture} from 'sentry-fixture/group';
  2. import {LocationFixture} from 'sentry-fixture/locationFixture';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {ReleaseFixture} from 'sentry-fixture/release';
  5. import {initializeOrg} from 'sentry-test/initializeOrg';
  6. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  7. import {textWithMarkupMatcher} from 'sentry-test/utils';
  8. import ReleaseIssues from 'sentry/views/releases/detail/overview/releaseIssues';
  9. import {getReleaseBounds} from 'sentry/views/releases/utils';
  10. describe('ReleaseIssues', function () {
  11. let newIssuesEndpoint: jest.Mock;
  12. let resolvedIssuesEndpoint: jest.Mock;
  13. let unhandledIssuesEndpoint: jest.Mock;
  14. let allIssuesEndpoint: jest.Mock;
  15. const props = {
  16. orgId: 'org',
  17. organization: OrganizationFixture(),
  18. version: '1.0.0',
  19. location: LocationFixture({query: {}}),
  20. releaseBounds: getReleaseBounds(ReleaseFixture({version: '1.0.0'})),
  21. };
  22. beforeEach(function () {
  23. MockApiClient.clearMockResponses();
  24. MockApiClient.addMockResponse({
  25. url: `/organizations/${props.organization.slug}/users/`,
  26. body: [],
  27. });
  28. MockApiClient.addMockResponse({
  29. url: `/organizations/${props.organization.slug}/issues-count/?end=2020-03-24T02%3A04%3A59Z&query=first-release%3A%221.0.0%22%20is%3Aunresolved&query=release%3A%221.0.0%22%20is%3Aunresolved&query=error.handled%3A0%20release%3A%221.0.0%22%20is%3Aunresolved&query=regressed_in_release%3A%221.0.0%22&start=2020-03-23T01%3A02%3A00Z`,
  30. });
  31. MockApiClient.addMockResponse({
  32. url: `/organizations/${props.organization.slug}/issues-count/?query=first-release%3A%221.0.0%22%20is%3Aunresolved&query=release%3A%221.0.0%22%20is%3Aunresolved&query=error.handled%3A0%20release%3A%221.0.0%22%20is%3Aunresolved&query=regressed_in_release%3A%221.0.0%22&statsPeriod=24h`,
  33. });
  34. MockApiClient.addMockResponse({
  35. url: `/organizations/${props.organization.slug}/releases/1.0.0/resolved/`,
  36. });
  37. newIssuesEndpoint = MockApiClient.addMockResponse({
  38. url: `/organizations/${props.organization.slug}/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&limit=10&query=first-release%3A1.0.0%20is%3Aunresolved&sort=freq&start=2020-03-23T01%3A02%3A00Z`,
  39. body: [],
  40. });
  41. MockApiClient.addMockResponse({
  42. url: `/organizations/${props.organization.slug}/issues/?groupStatsPeriod=auto&limit=10&query=first-release%3A1.0.0%20is%3Aunresolved&sort=freq&statsPeriod=24h`,
  43. body: [],
  44. });
  45. resolvedIssuesEndpoint = MockApiClient.addMockResponse({
  46. url: `/organizations/${props.organization.slug}/releases/1.0.0/resolved/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&limit=10&query=&sort=freq&start=2020-03-23T01%3A02%3A00Z`,
  47. body: [],
  48. });
  49. unhandledIssuesEndpoint = MockApiClient.addMockResponse({
  50. url: `/organizations/${props.organization.slug}/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&limit=10&query=release%3A1.0.0%20error.handled%3A0%20is%3Aunresolved&sort=freq&start=2020-03-23T01%3A02%3A00Z`,
  51. body: [],
  52. });
  53. MockApiClient.addMockResponse({
  54. url: `/organizations/${props.organization.slug}/issues/?groupStatsPeriod=auto&limit=10&query=release%3A1.0.0%20error.handled%3A0%20is%3Aunresolved&sort=freq&statsPeriod=24h`,
  55. body: [],
  56. });
  57. allIssuesEndpoint = MockApiClient.addMockResponse({
  58. url: `/organizations/${props.organization.slug}/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&limit=10&query=release%3A1.0.0%20is%3Aunresolved&sort=freq&start=2020-03-23T01%3A02%3A00Z`,
  59. body: [],
  60. });
  61. });
  62. it('shows an empty state', async function () {
  63. const {rerender} = render(<ReleaseIssues {...props} />);
  64. expect(await screen.findByText('No new issues in this release.')).toBeInTheDocument();
  65. await userEvent.click(screen.getByRole('radio', {name: 'Resolved 0'}));
  66. // Simulate query change
  67. rerender(
  68. <ReleaseIssues
  69. {...props}
  70. location={LocationFixture({query: {issuesType: 'resolved'}})}
  71. />
  72. );
  73. expect(
  74. await screen.findByText('No resolved issues in this release.')
  75. ).toBeInTheDocument();
  76. });
  77. it('shows an empty sttate with stats period', async function () {
  78. const query = {pageStatsPeriod: '24h'};
  79. const {rerender} = render(
  80. <ReleaseIssues {...props} location={LocationFixture({query})} />
  81. );
  82. expect(
  83. await screen.findByText(
  84. textWithMarkupMatcher('No new issues for the last 24 hours.')
  85. )
  86. ).toBeInTheDocument();
  87. await userEvent.click(screen.getByRole('radio', {name: 'Unhandled 0'}));
  88. // Simulate query change
  89. rerender(
  90. <ReleaseIssues
  91. {...props}
  92. location={LocationFixture({query: {...query, issuesType: 'unhandled'}})}
  93. />
  94. );
  95. expect(
  96. await screen.findByText(
  97. textWithMarkupMatcher('No unhandled issues for the last 24 hours.')
  98. )
  99. ).toBeInTheDocument();
  100. });
  101. it('can switch issue filters', async function () {
  102. const {router} = initializeOrg();
  103. const {rerender} = render(<ReleaseIssues {...props} />, {router});
  104. // New
  105. expect(await screen.findByRole('radio', {name: 'New Issues 0'})).toBeChecked();
  106. expect(screen.getByRole('button', {name: 'Open in Issues'})).toHaveAttribute(
  107. 'href',
  108. '/organizations/org-slug/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&query=firstRelease%3A1.0.0&sort=freq&start=2020-03-23T01%3A02%3A00Z'
  109. );
  110. expect(newIssuesEndpoint).toHaveBeenCalledTimes(1);
  111. // Resolved
  112. await userEvent.click(screen.getByRole('radio', {name: 'Resolved 0'}));
  113. // Simulate query change
  114. rerender(
  115. <ReleaseIssues
  116. {...props}
  117. location={LocationFixture({query: {issuesType: 'resolved'}})}
  118. />
  119. );
  120. expect(screen.getByRole('button', {name: 'Open in Issues'})).toHaveAttribute(
  121. 'href',
  122. '/organizations/org-slug/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&query=release%3A1.0.0&sort=freq&start=2020-03-23T01%3A02%3A00Z'
  123. );
  124. expect(resolvedIssuesEndpoint).toHaveBeenCalledTimes(1);
  125. // Unhandled
  126. await userEvent.click(screen.getByRole('radio', {name: 'Unhandled 0'}));
  127. rerender(
  128. <ReleaseIssues
  129. {...props}
  130. location={LocationFixture({query: {issuesType: 'unhandled'}})}
  131. />
  132. );
  133. expect(screen.getByRole('button', {name: 'Open in Issues'})).toHaveAttribute(
  134. 'href',
  135. '/organizations/org-slug/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&query=release%3A1.0.0%20error.handled%3A0&sort=freq&start=2020-03-23T01%3A02%3A00Z'
  136. );
  137. expect(unhandledIssuesEndpoint).toHaveBeenCalledTimes(1);
  138. // All
  139. await userEvent.click(screen.getByRole('radio', {name: 'All Issues 0'}));
  140. rerender(
  141. <ReleaseIssues
  142. {...props}
  143. location={LocationFixture({query: {issuesType: 'all'}})}
  144. />
  145. );
  146. expect(await screen.findByRole('button', {name: 'Open in Issues'})).toHaveAttribute(
  147. 'href',
  148. '/organizations/org-slug/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&query=release%3A1.0.0&sort=freq&start=2020-03-23T01%3A02%3A00Z'
  149. );
  150. expect(allIssuesEndpoint).toHaveBeenCalledTimes(1);
  151. });
  152. it('includes release context when linking to issue', async function () {
  153. newIssuesEndpoint = MockApiClient.addMockResponse({
  154. url: `/organizations/${props.organization.slug}/issues/?end=2020-03-24T02%3A04%3A59Z&groupStatsPeriod=auto&limit=10&query=first-release%3A1.0.0%20is%3Aunresolved&sort=freq&start=2020-03-23T01%3A02%3A00Z`,
  155. body: [GroupFixture({id: '123'})],
  156. });
  157. const {router} = initializeOrg();
  158. render(<ReleaseIssues {...props} />, {router});
  159. await userEvent.click(screen.getByRole('radio', {name: /New Issues/}));
  160. const link = await screen.findByRole('link', {name: /RequestError/});
  161. // Should pass the query param `query` with value `release:1.0.0`
  162. expect(link).toHaveAttribute(
  163. 'href',
  164. '/organizations/org-slug/issues/123/?_allp=1&query=release%3A1.0.0&referrer=release-issue-stream'
  165. );
  166. });
  167. });