stackTracePreview.spec.tsx 5.4 KB

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