sidebar.spec.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import {Broadcast} from 'sentry-fixture/broadcast';
  2. import {Project} from 'sentry-fixture/project';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  5. import {textWithMarkupMatcher} from 'sentry-test/utils';
  6. import {OnboardingContextProvider} from 'sentry/components/onboarding/onboardingContext';
  7. import SidebarContainer from 'sentry/components/sidebar';
  8. import {SidebarPanelKey} from 'sentry/components/sidebar/types';
  9. import PageFiltersStore from 'sentry/stores/pageFiltersStore';
  10. import ProjectsStore from 'sentry/stores/projectsStore';
  11. import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
  12. import {generateDocKeys} from './utils';
  13. jest.mock('sentry/actionCreators/serviceIncidents');
  14. describe('Sidebar > Performance Onboarding Checklist', function () {
  15. const {organization, routerContext, router} = initializeOrg({
  16. router: {
  17. location: {query: {}, search: '', pathname: '/test/'},
  18. },
  19. });
  20. const broadcast = Broadcast();
  21. const apiMocks: any = {};
  22. const getElement = (props: React.ComponentProps<typeof SidebarContainer>) => {
  23. return (
  24. <OnboardingContextProvider>
  25. <SidebarContainer organization={props.organization} {...props} />
  26. </OnboardingContextProvider>
  27. );
  28. };
  29. const renderSidebar = props =>
  30. render(getElement(props), {organization: props.organization, context: routerContext});
  31. beforeEach(function () {
  32. jest.resetAllMocks();
  33. PageFiltersStore.init();
  34. PageFiltersStore.onInitializeUrlState(
  35. {
  36. projects: [],
  37. environments: [],
  38. datetime: {start: null, end: null, period: '24h', utc: null},
  39. },
  40. new Set()
  41. );
  42. apiMocks.broadcasts = MockApiClient.addMockResponse({
  43. url: `/organizations/${organization.slug}/broadcasts/`,
  44. body: [broadcast],
  45. });
  46. });
  47. afterEach(() => {
  48. MockApiClient.clearMockResponses();
  49. });
  50. it('displays boost performance card', async function () {
  51. renderSidebar({
  52. organization: {
  53. ...organization,
  54. features: ['onboarding'],
  55. },
  56. });
  57. const quickStart = await screen.findByText('Quick Start');
  58. expect(quickStart).toBeInTheDocument();
  59. await userEvent.click(quickStart);
  60. const sidebar = await screen.findByRole('dialog');
  61. expect(sidebar).toBeInTheDocument();
  62. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  63. expect(screen.getByText('Level Up')).toBeInTheDocument();
  64. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  65. await userEvent.click(quickStart);
  66. expect(screen.queryByText('Boost performance')).not.toBeInTheDocument();
  67. });
  68. it('checklist feature disabled', async function () {
  69. renderSidebar({
  70. organization: {
  71. ...organization,
  72. features: ['onboarding'],
  73. },
  74. });
  75. window.open = jest.fn().mockImplementation(() => true);
  76. const quickStart = await screen.findByText('Quick Start');
  77. expect(quickStart).toBeInTheDocument();
  78. await userEvent.click(quickStart);
  79. const sidebar = await screen.findByRole('dialog');
  80. expect(sidebar).toBeInTheDocument();
  81. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  82. expect(screen.getByText('Level Up')).toBeInTheDocument();
  83. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  84. const performanceCard = screen.getByTestId('setup_transactions');
  85. await userEvent.click(performanceCard);
  86. expect(window.open).toHaveBeenCalledWith(
  87. 'https://docs.sentry.io/product/performance/getting-started/',
  88. '_blank'
  89. );
  90. });
  91. it('checklist feature enabled > navigate to performance page > project with onboarding support', async function () {
  92. ProjectsStore.loadInitialData([
  93. Project({platform: 'javascript-react', firstTransactionEvent: false}),
  94. ]);
  95. renderSidebar({
  96. organization: {
  97. ...organization,
  98. features: ['onboarding', 'performance-onboarding-checklist'],
  99. },
  100. });
  101. window.open = jest.fn().mockImplementation(() => true);
  102. const quickStart = await screen.findByText('Quick Start');
  103. expect(quickStart).toBeInTheDocument();
  104. await userEvent.click(quickStart);
  105. const sidebar = await screen.findByRole('dialog');
  106. expect(sidebar).toBeInTheDocument();
  107. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  108. expect(screen.getByText('Level Up')).toBeInTheDocument();
  109. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  110. const performanceCard = screen.getByTestId('setup_transactions');
  111. await userEvent.click(performanceCard);
  112. expect(window.open).not.toHaveBeenCalled();
  113. expect(router.push).toHaveBeenCalledWith(
  114. '/organizations/org-slug/performance/?project=2#performance-sidequest'
  115. );
  116. });
  117. it('checklist feature enabled > navigate to performance page > project without onboarding support', async function () {
  118. ProjectsStore.loadInitialData([
  119. Project({platform: 'javascript-angular', firstTransactionEvent: false}),
  120. ]);
  121. renderSidebar({
  122. organization: {
  123. ...organization,
  124. features: ['onboarding', 'performance-onboarding-checklist'],
  125. },
  126. });
  127. window.open = jest.fn().mockImplementation(() => true);
  128. const quickStart = await screen.findByText('Quick Start');
  129. expect(quickStart).toBeInTheDocument();
  130. await userEvent.click(quickStart);
  131. const sidebar = await screen.findByRole('dialog');
  132. expect(sidebar).toBeInTheDocument();
  133. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  134. expect(screen.getByText('Level Up')).toBeInTheDocument();
  135. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  136. const performanceCard = screen.getByTestId('setup_transactions');
  137. await userEvent.click(performanceCard);
  138. expect(window.open).not.toHaveBeenCalled();
  139. expect(router.push).toHaveBeenCalledWith(
  140. '/organizations/org-slug/performance/?project=2#performance-sidequest'
  141. );
  142. });
  143. it('checklist feature enabled > navigate to performance page > project without performance support', async function () {
  144. ProjectsStore.loadInitialData([
  145. Project({platform: 'elixir', firstTransactionEvent: false}),
  146. ]);
  147. renderSidebar({
  148. organization: {
  149. ...organization,
  150. features: ['onboarding', 'performance-onboarding-checklist'],
  151. },
  152. });
  153. window.open = jest.fn().mockImplementation(() => true);
  154. const quickStart = await screen.findByText('Quick Start');
  155. expect(quickStart).toBeInTheDocument();
  156. await userEvent.click(quickStart);
  157. const sidebar = await screen.findByRole('dialog');
  158. expect(sidebar).toBeInTheDocument();
  159. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  160. expect(screen.getByText('Level Up')).toBeInTheDocument();
  161. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  162. const performanceCard = screen.getByTestId('setup_transactions');
  163. await userEvent.click(performanceCard);
  164. expect(window.open).not.toHaveBeenCalled();
  165. expect(router.push).toHaveBeenCalledWith('/organizations/org-slug/performance/');
  166. });
  167. it('displays checklist', async function () {
  168. const project = Project({
  169. platform: 'javascript-react',
  170. firstTransactionEvent: false,
  171. });
  172. ProjectsStore.loadInitialData([project]);
  173. const docApiMocks: any = {};
  174. const docKeys = generateDocKeys(project.platform!);
  175. docKeys.forEach(docKey => {
  176. docApiMocks[docKey] = MockApiClient.addMockResponse({
  177. url: `/projects/${organization.slug}/${project.slug}/docs/${docKey}/`,
  178. method: 'GET',
  179. body: {html: `<h1>${docKey}</h1> content`},
  180. });
  181. });
  182. MockApiClient.addMockResponse({
  183. url: `/projects/${organization.slug}/${project.slug}/`,
  184. method: 'GET',
  185. body: {},
  186. });
  187. renderSidebar({
  188. organization: {
  189. ...organization,
  190. features: ['onboarding', 'performance-onboarding-checklist'],
  191. },
  192. });
  193. act(() => {
  194. SidebarPanelStore.activatePanel(SidebarPanelKey.PERFORMANCE_ONBOARDING);
  195. });
  196. expect(
  197. await screen.findByText(
  198. textWithMarkupMatcher('Adding Performance to your React project is simple.')
  199. )
  200. ).toBeInTheDocument();
  201. for (const docKey of docKeys) {
  202. expect(
  203. await screen.findByText(textWithMarkupMatcher(`${docKey} content`))
  204. ).toBeInTheDocument();
  205. }
  206. });
  207. });