releaseIssues.spec.tsx 7.8 KB

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