listContent.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import {Organization} from 'sentry-fixture/organization';
  2. import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
  3. import {Organization as TOrganization} from 'sentry/types';
  4. import useDeadRageSelectors from 'sentry/utils/replays/hooks/useDeadRageSelectors';
  5. import useReplayList from 'sentry/utils/replays/hooks/useReplayList';
  6. import {
  7. useHaveSelectedProjectsSentAnyReplayEvents,
  8. useReplayOnboardingSidebarPanel,
  9. } from 'sentry/utils/replays/hooks/useReplayOnboarding';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import useProjectSdkNeedsUpdate from 'sentry/utils/useProjectSdkNeedsUpdate';
  12. import ListPage from 'sentry/views/replays/list/listContent';
  13. jest.mock('sentry/utils/replays/hooks/useReplayOnboarding');
  14. jest.mock('sentry/utils/replays/hooks/useDeadRageSelectors');
  15. jest.mock('sentry/utils/replays/hooks/useReplayPageview');
  16. jest.mock('sentry/utils/useOrganization');
  17. jest.mock('sentry/utils/useProjectSdkNeedsUpdate');
  18. jest.mock('sentry/utils/replays/hooks/useReplayList', () => {
  19. return {
  20. __esModule: true,
  21. default: jest.fn(() => {
  22. return {
  23. fetchError: undefined,
  24. isFetching: false,
  25. pageLinks: null,
  26. replays: [],
  27. };
  28. }),
  29. };
  30. });
  31. const mockUseReplayList = jest.mocked(useReplayList);
  32. const mockUseDeadRageSelectors = jest.mocked(useDeadRageSelectors);
  33. const mockUseHaveSelectedProjectsSentAnyReplayEvents = jest.mocked(
  34. useHaveSelectedProjectsSentAnyReplayEvents
  35. );
  36. const mockUseProjectSdkNeedsUpdate = jest.mocked(useProjectSdkNeedsUpdate);
  37. const mockUseReplayOnboardingSidebarPanel = jest.mocked(useReplayOnboardingSidebarPanel);
  38. mockUseReplayOnboardingSidebarPanel.mockReturnValue({activateSidebar: jest.fn()});
  39. const AM1_FEATURES = [];
  40. const AM2_FEATURES = ['session-replay'];
  41. function getMockOrganization({features}: {features: string[]}) {
  42. const mockOrg = Organization({
  43. features,
  44. access: [],
  45. });
  46. jest.mocked(useOrganization).mockReturnValue(mockOrg);
  47. return mockOrg;
  48. }
  49. function getMockContext(mockOrg: TOrganization) {
  50. return TestStubs.routerContext([{organization: mockOrg}]);
  51. }
  52. describe('ReplayList', () => {
  53. beforeEach(() => {
  54. mockUseReplayList.mockClear();
  55. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockClear();
  56. mockUseProjectSdkNeedsUpdate.mockClear();
  57. mockUseDeadRageSelectors.mockClear();
  58. MockApiClient.clearMockResponses();
  59. MockApiClient.addMockResponse({
  60. url: '/organizations/org-slug/tags/',
  61. body: [],
  62. });
  63. });
  64. it('should render the onboarding panel when the org is on AM1', async () => {
  65. const mockOrg = getMockOrganization({features: AM1_FEATURES});
  66. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockReturnValue({
  67. fetching: false,
  68. hasSentOneReplay: false,
  69. });
  70. mockUseProjectSdkNeedsUpdate.mockReturnValue({
  71. isError: false,
  72. isFetching: false,
  73. needsUpdate: false,
  74. });
  75. render(<ListPage />, {
  76. context: getMockContext(mockOrg),
  77. });
  78. await waitFor(() =>
  79. expect(screen.getByText('Get to the root cause faster')).toBeInTheDocument()
  80. );
  81. expect(mockUseReplayList).not.toHaveBeenCalled();
  82. });
  83. it('should render the onboarding panel when the org is on AM1 and has sent some replays', async () => {
  84. const mockOrg = getMockOrganization({features: AM1_FEATURES});
  85. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockReturnValue({
  86. fetching: false,
  87. hasSentOneReplay: true,
  88. });
  89. mockUseProjectSdkNeedsUpdate.mockReturnValue({
  90. isError: false,
  91. isFetching: false,
  92. needsUpdate: false,
  93. });
  94. render(<ListPage />, {
  95. context: getMockContext(mockOrg),
  96. });
  97. await waitFor(() =>
  98. expect(screen.getByText('Get to the root cause faster')).toBeInTheDocument()
  99. );
  100. expect(mockUseReplayList).not.toHaveBeenCalled();
  101. });
  102. it('should render the onboarding panel when the org is on AM2 and has never sent a replay', async () => {
  103. const mockOrg = getMockOrganization({features: AM2_FEATURES});
  104. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockReturnValue({
  105. fetching: false,
  106. hasSentOneReplay: false,
  107. });
  108. mockUseProjectSdkNeedsUpdate.mockReturnValue({
  109. isError: false,
  110. isFetching: false,
  111. needsUpdate: false,
  112. });
  113. render(<ListPage />, {
  114. context: getMockContext(mockOrg),
  115. });
  116. await waitFor(() =>
  117. expect(screen.getByText('Get to the root cause faster')).toBeInTheDocument()
  118. );
  119. expect(mockUseReplayList).not.toHaveBeenCalled();
  120. });
  121. it('should render the rage-click sdk update banner when the org is AM2, has sent replays, but the sdk version is low', async () => {
  122. const mockOrg = getMockOrganization({features: AM2_FEATURES});
  123. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockReturnValue({
  124. fetching: false,
  125. hasSentOneReplay: true,
  126. });
  127. mockUseProjectSdkNeedsUpdate.mockReturnValue({
  128. isError: false,
  129. isFetching: false,
  130. needsUpdate: true,
  131. });
  132. mockUseReplayList.mockReturnValue({
  133. replays: [],
  134. isFetching: false,
  135. fetchError: undefined,
  136. pageLinks: null,
  137. });
  138. render(<ListPage />, {
  139. context: getMockContext(mockOrg),
  140. });
  141. await waitFor(() => {
  142. expect(screen.queryByText('Introducing Rage and Dead Clicks')).toBeInTheDocument();
  143. expect(screen.queryByTestId('replay-table')).toBeInTheDocument();
  144. });
  145. expect(mockUseReplayList).toHaveBeenCalled();
  146. });
  147. it('should fetch the replay table and show selector tables when the org is on AM2, has sent some replays, and has a newer SDK version', async () => {
  148. const mockOrg = getMockOrganization({features: AM2_FEATURES});
  149. mockUseHaveSelectedProjectsSentAnyReplayEvents.mockReturnValue({
  150. fetching: false,
  151. hasSentOneReplay: true,
  152. });
  153. mockUseProjectSdkNeedsUpdate.mockReturnValue({
  154. isError: false,
  155. isFetching: false,
  156. needsUpdate: false,
  157. });
  158. mockUseReplayList.mockReturnValue({
  159. replays: [],
  160. isFetching: false,
  161. fetchError: undefined,
  162. pageLinks: null,
  163. });
  164. mockUseDeadRageSelectors.mockReturnValue({
  165. isLoading: false,
  166. isError: false,
  167. data: [],
  168. pageLinks: undefined,
  169. });
  170. render(<ListPage />, {
  171. context: getMockContext(mockOrg),
  172. });
  173. await waitFor(() => expect(screen.queryAllByTestId('replay-table')).toHaveLength(1));
  174. await waitFor(() =>
  175. expect(screen.queryAllByTestId('selector-widget')).toHaveLength(2)
  176. );
  177. expect(mockUseReplayList).toHaveBeenCalled();
  178. });
  179. });