stackTracePreview.spec.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import React from 'react';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import {StackTracePreview} from 'sentry/components/stacktracePreview';
  5. import {EventError} from 'sentry/types';
  6. import {EntryType, Event, ExceptionType, ExceptionValue, Frame} from 'sentry/types/event';
  7. import useApi from 'sentry/utils/useApi';
  8. import {OrganizationContext} from 'sentry/views/organizationContext';
  9. import {RouteContext} from 'sentry/views/routeContext';
  10. const makeEvent = (event: Partial<Event> = {}): Event => {
  11. const evt: Event = {
  12. ...TestStubs.Event(),
  13. ...event,
  14. };
  15. return evt;
  16. };
  17. function TestComponent({children}: {children: React.ReactNode}) {
  18. const {organization, router} = initializeOrg();
  19. return (
  20. <OrganizationContext.Provider value={organization}>
  21. <RouteContext.Provider
  22. value={{
  23. router,
  24. location: router.location,
  25. params: {},
  26. routes: [],
  27. }}
  28. >
  29. {children}
  30. </RouteContext.Provider>
  31. </OrganizationContext.Provider>
  32. );
  33. }
  34. jest.mock('sentry/utils/useApi');
  35. describe('StackTracePreview', () => {
  36. it('fetches from projects when eventId and projectSlug are provided', async () => {
  37. const api = new MockApiClient();
  38. const spy = jest
  39. .spyOn(api, 'requestPromise')
  40. .mockResolvedValue(makeEvent({id: 'event_id', entries: []}));
  41. // @ts-ignore useApi is mocked
  42. useApi.mockReturnValue(api);
  43. render(
  44. <TestComponent>
  45. <StackTracePreview
  46. issueId="issue"
  47. eventId="event_id"
  48. projectSlug="project_slug"
  49. organization={TestStubs.Organization({slug: 'org_slug'})}
  50. >
  51. Preview Trigger
  52. </StackTracePreview>
  53. </TestComponent>
  54. );
  55. userEvent.hover(screen.getByText(/Preview Trigger/));
  56. await waitFor(() => {
  57. expect(spy.mock.calls[0][0]).toBe(
  58. `/projects/org_slug/project_slug/events/event_id/`
  59. );
  60. });
  61. });
  62. it('fetches from issues when issueId when eventId and projectSlug are not provided', async () => {
  63. const api = new MockApiClient();
  64. const spy = jest
  65. .spyOn(api, 'requestPromise')
  66. .mockResolvedValue(makeEvent({id: 'event_id', entries: []}));
  67. // @ts-ignore useApi is mocked
  68. useApi.mockReturnValue(api);
  69. render(
  70. <TestComponent>
  71. <StackTracePreview
  72. issueId="issue"
  73. organization={TestStubs.Organization({slug: 'org_slug'})}
  74. >
  75. Preview Trigger
  76. </StackTracePreview>
  77. </TestComponent>
  78. );
  79. userEvent.hover(screen.getByText(/Preview Trigger/));
  80. await waitFor(() => {
  81. expect(spy.mock.calls[0][0]).toBe(
  82. `/issues/issue/events/latest/?collapse=stacktraceOnly`
  83. );
  84. });
  85. });
  86. it('renders error message', async () => {
  87. const api = new MockApiClient();
  88. jest
  89. .spyOn(api, 'requestPromise')
  90. .mockRejectedValue(makeEvent({id: 'event_id', entries: []}));
  91. // @ts-ignore useApi is mocked
  92. useApi.mockReturnValue(api);
  93. render(
  94. <TestComponent>
  95. <StackTracePreview
  96. issueId="issue"
  97. organization={TestStubs.Organization({slug: 'org_slug'})}
  98. >
  99. Preview Trigger
  100. </StackTracePreview>
  101. </TestComponent>
  102. );
  103. userEvent.hover(screen.getByText(/Preview Trigger/));
  104. expect(await screen.findByText(/Failed to load stack trace/)).toBeInTheDocument();
  105. });
  106. it('warns about no stacktrace', async () => {
  107. const api = new MockApiClient();
  108. jest
  109. .spyOn(api, 'requestPromise')
  110. .mockResolvedValue(makeEvent({id: 'event_id', entries: []}));
  111. // @ts-ignore useApi is mocked
  112. useApi.mockReturnValue(api);
  113. render(
  114. <TestComponent>
  115. <StackTracePreview
  116. issueId="issue"
  117. organization={TestStubs.Organization({slug: 'org_slug'})}
  118. >
  119. Preview Trigger
  120. </StackTracePreview>
  121. </TestComponent>
  122. );
  123. userEvent.hover(screen.getByText(/Preview Trigger/));
  124. expect(
  125. await screen.findByText(/There is no stack trace available for this issue./)
  126. ).toBeInTheDocument();
  127. });
  128. it.each([
  129. ['stack-trace-content', []],
  130. ['stack-trace-content-v2', ['grouping-stacktrace-ui']],
  131. ])('renders %s', async (component, features) => {
  132. const api = new MockApiClient();
  133. const frame: Frame = {
  134. colNo: 0,
  135. filename: 'file.js',
  136. function: 'throwError',
  137. lineNo: 0,
  138. absPath: null,
  139. context: [],
  140. errors: null,
  141. inApp: false,
  142. instructionAddr: null,
  143. module: null,
  144. package: null,
  145. platform: null,
  146. rawFunction: null,
  147. symbol: null,
  148. symbolAddr: null,
  149. trust: undefined,
  150. vars: null,
  151. };
  152. const thread: ExceptionValue = {
  153. stacktrace: {
  154. hasSystemFrames: false,
  155. registers: {},
  156. framesOmitted: 0,
  157. frames: [frame],
  158. },
  159. mechanism: null,
  160. module: null,
  161. rawStacktrace: null,
  162. threadId: null,
  163. type: '',
  164. value: '',
  165. };
  166. const exceptionValue: ExceptionType = {
  167. values: [thread],
  168. excOmitted: undefined,
  169. hasSystemFrames: false,
  170. };
  171. const errorEvent: EventError = {
  172. id: 'event_id',
  173. entries: [
  174. {
  175. type: EntryType.EXCEPTION,
  176. data: exceptionValue,
  177. },
  178. ],
  179. } as EventError;
  180. jest.spyOn(api, 'requestPromise').mockResolvedValue(makeEvent(errorEvent));
  181. // @ts-ignore useApi is mocked
  182. useApi.mockReturnValue(api);
  183. render(
  184. <TestComponent>
  185. <StackTracePreview
  186. issueId="issue"
  187. organization={TestStubs.Organization({
  188. slug: 'org_slug',
  189. features,
  190. })}
  191. >
  192. Preview Trigger
  193. </StackTracePreview>
  194. </TestComponent>
  195. );
  196. userEvent.hover(screen.getByText(/Preview Trigger/));
  197. expect(await screen.findByTestId(component)).toBeInTheDocument();
  198. });
  199. });