eventNavigation.spec.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import {EventFixture} from 'sentry-fixture/event';
  2. import {EventAttachmentFixture} from 'sentry-fixture/eventAttachment';
  3. import {GroupFixture} from 'sentry-fixture/group';
  4. import {LocationFixture} from 'sentry-fixture/locationFixture';
  5. import {RouterFixture} from 'sentry-fixture/routerFixture';
  6. import {initializeOrg} from 'sentry-test/initializeOrg';
  7. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  8. import * as useMedia from 'sentry/utils/useMedia';
  9. import {SectionKey, useEventDetails} from 'sentry/views/issueDetails/streamline/context';
  10. import {IssueEventNavigation} from './eventNavigation';
  11. jest.mock('sentry/views/issueDetails/streamline/context');
  12. describe('EventNavigation', () => {
  13. const {organization, router} = initializeOrg();
  14. const group = GroupFixture({id: 'group-id'});
  15. const testEvent = EventFixture({
  16. id: 'event-id',
  17. size: 7,
  18. dateCreated: '2019-03-20T00:00:00.000Z',
  19. errors: [],
  20. entries: [],
  21. tags: [
  22. {key: 'environment', value: 'dev'},
  23. {key: 'replayId', value: 'replay-id'},
  24. ],
  25. previousEventID: 'prev-event-id',
  26. nextEventID: 'next-event-id',
  27. });
  28. const defaultProps: React.ComponentProps<typeof IssueEventNavigation> = {
  29. event: testEvent,
  30. group,
  31. query: undefined,
  32. };
  33. beforeEach(() => {
  34. jest.resetAllMocks();
  35. jest.mocked(useEventDetails).mockReturnValue({
  36. sectionData: {
  37. highlights: {key: SectionKey.HIGHLIGHTS},
  38. tags: {key: SectionKey.TAGS},
  39. replay: {key: SectionKey.REPLAY},
  40. },
  41. dispatch: jest.fn(),
  42. });
  43. MockApiClient.addMockResponse({
  44. url: `/organizations/${organization.slug}/issues/${group.id}/attachments/`,
  45. body: [],
  46. });
  47. MockApiClient.addMockResponse({
  48. url: '/organizations/org-slug/replay-count/',
  49. body: {},
  50. });
  51. });
  52. describe('recommended event tabs', () => {
  53. it('can navigate to the oldest event', async () => {
  54. jest.spyOn(useMedia, 'default').mockReturnValue(true);
  55. render(<IssueEventNavigation {...defaultProps} />, {router});
  56. await userEvent.click(await screen.findByRole('tab', {name: 'First'}));
  57. expect(router.push).toHaveBeenCalledWith({
  58. pathname: '/organizations/org-slug/issues/group-id/events/oldest/',
  59. query: {referrer: 'oldest-event'},
  60. });
  61. });
  62. it('can navigate to the latest event', async () => {
  63. jest.spyOn(useMedia, 'default').mockReturnValue(true);
  64. render(<IssueEventNavigation {...defaultProps} />, {router});
  65. await userEvent.click(await screen.findByRole('tab', {name: 'Last'}));
  66. expect(router.push).toHaveBeenCalledWith({
  67. pathname: '/organizations/org-slug/issues/group-id/events/latest/',
  68. query: {referrer: 'latest-event'},
  69. });
  70. });
  71. it('can navigate to the recommended event', async () => {
  72. jest.spyOn(useMedia, 'default').mockReturnValue(true);
  73. const recommendedEventRouter = RouterFixture({
  74. params: {eventId: 'latest'},
  75. location: LocationFixture({
  76. pathname: `/organizations/org-slug/issues/group-id/events/latest/`,
  77. }),
  78. });
  79. render(<IssueEventNavigation {...defaultProps} />, {
  80. router: recommendedEventRouter,
  81. });
  82. await userEvent.click(await screen.findByRole('tab', {name: 'Rec.'}));
  83. expect(recommendedEventRouter.push).toHaveBeenCalledWith({
  84. pathname: '/organizations/org-slug/issues/group-id/events/recommended/',
  85. query: {referrer: 'recommended-event'},
  86. });
  87. });
  88. });
  89. it('can navigate next/previous events', async () => {
  90. render(<IssueEventNavigation {...defaultProps} />);
  91. expect(await screen.findByRole('button', {name: 'Previous Event'})).toHaveAttribute(
  92. 'href',
  93. `/organizations/org-slug/issues/group-id/events/prev-event-id/?referrer=previous-event`
  94. );
  95. expect(screen.getByRole('button', {name: 'Next Event'})).toHaveAttribute(
  96. 'href',
  97. `/organizations/org-slug/issues/group-id/events/next-event-id/?referrer=next-event`
  98. );
  99. });
  100. it('can preload next/previous events', async () => {
  101. const event = EventFixture({
  102. nextEventID: 'next-event-id',
  103. previousEventID: 'prev-event-id',
  104. });
  105. const mockNextEvent = MockApiClient.addMockResponse({
  106. url: `/organizations/org-slug/issues/group-id/events/next-event-id/`,
  107. body: EventFixture(),
  108. });
  109. const mockPreviousEvent = MockApiClient.addMockResponse({
  110. url: `/organizations/org-slug/issues/group-id/events/prev-event-id/`,
  111. body: EventFixture(),
  112. });
  113. render(<IssueEventNavigation {...defaultProps} event={event} />);
  114. expect(mockNextEvent).not.toHaveBeenCalled();
  115. expect(mockPreviousEvent).not.toHaveBeenCalled();
  116. await userEvent.hover(await screen.findByRole('button', {name: 'Next Event'}));
  117. await waitFor(() => expect(mockNextEvent).toHaveBeenCalled());
  118. expect(mockPreviousEvent).not.toHaveBeenCalled();
  119. await userEvent.hover(screen.getByRole('button', {name: 'Previous Event'}));
  120. await waitFor(() => expect(mockPreviousEvent).toHaveBeenCalled());
  121. });
  122. describe('counts', () => {
  123. it('renders default counts', async () => {
  124. render(<IssueEventNavigation {...defaultProps} />);
  125. await userEvent.click(screen.getByRole('button', {name: 'Events'}));
  126. expect(
  127. await screen.findByRole('menuitemradio', {name: 'Attachments 0'})
  128. ).toBeInTheDocument();
  129. expect(
  130. screen.getByRole('menuitemradio', {name: 'Events 327k'})
  131. ).toBeInTheDocument();
  132. expect(screen.getByRole('menuitemradio', {name: 'Replays 0'})).toBeInTheDocument();
  133. expect(screen.getByRole('menuitemradio', {name: 'Feedback 0'})).toBeInTheDocument();
  134. });
  135. it('renders 1 attachment', async () => {
  136. MockApiClient.addMockResponse({
  137. url: `/organizations/${organization.slug}/issues/${group.id}/attachments/`,
  138. body: [EventAttachmentFixture()],
  139. });
  140. render(<IssueEventNavigation {...defaultProps} />);
  141. await userEvent.click(screen.getByRole('button', {name: 'Events'}));
  142. expect(
  143. await screen.findByRole('menuitemradio', {name: 'Attachments 1'})
  144. ).toBeInTheDocument();
  145. });
  146. it('renders 50+ attachments', async () => {
  147. MockApiClient.addMockResponse({
  148. url: `/organizations/${organization.slug}/issues/${group.id}/attachments/`,
  149. body: [EventAttachmentFixture()],
  150. headers: {
  151. // Assumes there is more than 50 attachments if there is a next page
  152. Link: '<https://sentry.io>; rel="previous"; results="false"; cursor="0:0:1", <https://sentry.io>; rel="next"; results="true"; cursor="0:20:0"',
  153. },
  154. });
  155. render(<IssueEventNavigation {...defaultProps} />);
  156. await userEvent.click(screen.getByRole('button', {name: 'Events'}));
  157. expect(
  158. await screen.findByRole('menuitemradio', {name: 'Attachments 50+'})
  159. ).toBeInTheDocument();
  160. });
  161. });
  162. });