index.spec.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {RouterFixture} from 'sentry-fixture/routerFixture';
  3. import {render, screen} from 'sentry-test/reactTestingLibrary';
  4. import {GroupRelatedIssues} from 'sentry/views/issueDetails/groupRelatedIssues';
  5. describe('Related Issues View', function () {
  6. let relatedIssuesMock: jest.Mock;
  7. let issuesMock: jest.Mock;
  8. const router = RouterFixture();
  9. const organization = OrganizationFixture();
  10. const orgSlug = organization.slug;
  11. const groupId = '12345678';
  12. const group1 = '15';
  13. const group2 = '20';
  14. // query=issue.id:[15,20] -> query=issue.id%3A%5B15%2C20%5D
  15. const orgIssuesEndpoint = `/organizations/${orgSlug}/issues/?query=issue.id%3A%5B${group1}%2C${group2}%5D`;
  16. const params = {groupId: groupId};
  17. const errorType = 'RuntimeError';
  18. const noData = {
  19. data: [
  20. {
  21. type: 'same_root_cause',
  22. data: [],
  23. },
  24. {
  25. type: 'trace_connected',
  26. data: [],
  27. },
  28. ],
  29. };
  30. const onlySameRootData = {
  31. data: [
  32. {
  33. type: 'same_root_cause',
  34. data: [group1, group2],
  35. },
  36. {
  37. type: 'trace_connected',
  38. data: [],
  39. },
  40. ],
  41. };
  42. const onlyTraceConnectedData = {
  43. data: [
  44. {
  45. type: 'same_root_cause',
  46. data: [],
  47. },
  48. {
  49. type: 'trace_connected',
  50. data: [group1, group2],
  51. meta: {
  52. event_id: 'abcd',
  53. trace_id: '1234',
  54. },
  55. },
  56. ],
  57. };
  58. const issuesData = [
  59. {
  60. id: group1,
  61. shortId: `EARTH-${group1}`,
  62. project: {id: '3', name: 'Earth', slug: 'earth', platform: null},
  63. type: 'error',
  64. metadata: {
  65. type: errorType,
  66. },
  67. issueCategory: 'error',
  68. lastSeen: '2024-03-15T20:15:30Z',
  69. },
  70. {
  71. id: group2,
  72. shortId: `EARTH-${group2}`,
  73. project: {id: '3', name: 'Earth', slug: 'earth', platform: null},
  74. type: 'error',
  75. metadata: {
  76. type: errorType,
  77. },
  78. issueCategory: 'error',
  79. lastSeen: '2024-03-16T20:15:30Z',
  80. },
  81. ];
  82. beforeEach(function () {
  83. // GroupList calls this but we don't need it for this test
  84. MockApiClient.addMockResponse({
  85. url: `/organizations/${orgSlug}/users/`,
  86. body: {},
  87. });
  88. });
  89. afterEach(() => {
  90. MockApiClient.clearMockResponses();
  91. jest.clearAllMocks();
  92. });
  93. it('renders with no data', async function () {
  94. relatedIssuesMock = MockApiClient.addMockResponse({
  95. url: `/issues/${groupId}/related-issues/`,
  96. body: noData,
  97. });
  98. render(
  99. <GroupRelatedIssues
  100. params={params}
  101. location={router.location}
  102. router={router}
  103. routeParams={router.params}
  104. routes={router.routes}
  105. route={{}}
  106. />
  107. );
  108. expect(
  109. await screen.findByText('No same-root-cause related issues were found.')
  110. ).toBeInTheDocument();
  111. expect(
  112. await screen.findByText('No trace-connected related issues were found.')
  113. ).toBeInTheDocument();
  114. expect(relatedIssuesMock).toHaveBeenCalled();
  115. });
  116. it('renders with same root issues', async function () {
  117. relatedIssuesMock = MockApiClient.addMockResponse({
  118. url: `/issues/${groupId}/related-issues/`,
  119. body: onlySameRootData,
  120. });
  121. issuesMock = MockApiClient.addMockResponse({
  122. url: orgIssuesEndpoint,
  123. body: issuesData,
  124. });
  125. render(
  126. <GroupRelatedIssues
  127. params={params}
  128. location={router.location}
  129. router={router}
  130. routeParams={router.params}
  131. routes={router.routes}
  132. route={{}}
  133. />
  134. );
  135. // Wait for the issues showing up on the table
  136. expect(await screen.findByText(`EARTH-${group1}`)).toBeInTheDocument();
  137. expect(await screen.findByText(`EARTH-${group2}`)).toBeInTheDocument();
  138. expect(relatedIssuesMock).toHaveBeenCalled();
  139. expect(issuesMock).toHaveBeenCalled();
  140. expect(
  141. await screen.findByText('No trace-connected related issues were found.')
  142. ).toBeInTheDocument();
  143. const linkButton = screen.getByRole('button', {name: /open in issues/i});
  144. expect(linkButton).toHaveAttribute(
  145. 'href',
  146. // Opening in Issues needs to include the group we are currently viewing
  147. `/organizations/org-slug/issues/?query=issue.id:[${groupId},${group1},${group2}]`
  148. );
  149. });
  150. it('renders with trace connected issues', async function () {
  151. relatedIssuesMock = MockApiClient.addMockResponse({
  152. url: `/issues/${groupId}/related-issues/`,
  153. body: onlyTraceConnectedData,
  154. });
  155. issuesMock = MockApiClient.addMockResponse({
  156. url: orgIssuesEndpoint,
  157. body: issuesData,
  158. });
  159. render(
  160. <GroupRelatedIssues
  161. params={params}
  162. location={router.location}
  163. router={router}
  164. routeParams={router.params}
  165. routes={router.routes}
  166. route={{}}
  167. />
  168. );
  169. // Wait for the issues showing up on the table
  170. expect(await screen.findByText(`EARTH-${group1}`)).toBeInTheDocument();
  171. expect(await screen.findByText(`EARTH-${group2}`)).toBeInTheDocument();
  172. expect(relatedIssuesMock).toHaveBeenCalled();
  173. expect(issuesMock).toHaveBeenCalled();
  174. expect(
  175. await screen.findByText('No same-root-cause related issues were found.')
  176. ).toBeInTheDocument();
  177. const linkElement = screen.getByRole('link', {name: /this trace/i});
  178. expect(linkElement).toHaveAttribute(
  179. 'href',
  180. '/organizations/org-slug/performance/trace/1234/?node=error-abcd'
  181. );
  182. const linkButton = screen.getByRole('button', {name: /open in issues/i});
  183. // The Issue search supports using `trace` as a parameter
  184. expect(linkButton).toHaveAttribute(
  185. 'href',
  186. `/organizations/org-slug/issues/?query=trace:1234`
  187. );
  188. });
  189. });