performanceOnboarding.spec.tsx 9.0 KB

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