performanceOnboarding.spec.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. });
  66. it('displays boost performance card', async function () {
  67. const {container} = renderSidebar({
  68. organization: {
  69. ...organization,
  70. features: ['onboarding'],
  71. },
  72. });
  73. await waitFor(() => container);
  74. const quickStart = screen.getByText('Quick Start');
  75. expect(quickStart).toBeInTheDocument();
  76. userEvent.click(quickStart);
  77. const sidebar = await screen.findByRole('dialog');
  78. expect(sidebar).toBeInTheDocument();
  79. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  80. expect(screen.getByText('Level Up')).toBeInTheDocument();
  81. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  82. userEvent.click(quickStart);
  83. expect(screen.queryByText('Boost performance')).not.toBeInTheDocument();
  84. });
  85. it('checklist feature disabled', async function () {
  86. const {container} = renderSidebar({
  87. organization: {
  88. ...organization,
  89. features: ['onboarding'],
  90. },
  91. });
  92. await waitFor(() => container);
  93. window.open = jest.fn().mockImplementation(() => true);
  94. const quickStart = screen.getByText('Quick Start');
  95. expect(quickStart).toBeInTheDocument();
  96. userEvent.click(quickStart);
  97. const sidebar = await screen.findByRole('dialog');
  98. expect(sidebar).toBeInTheDocument();
  99. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  100. expect(screen.getByText('Level Up')).toBeInTheDocument();
  101. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  102. const performanceCard = screen.getByTestId('setup_transactions');
  103. userEvent.click(performanceCard);
  104. expect(window.open).toHaveBeenCalledWith(
  105. 'https://docs.sentry.io/product/performance/getting-started/',
  106. '_blank'
  107. );
  108. });
  109. it('checklist feature enabled > navigate to performance page > project with onboarding support', async function () {
  110. ProjectsStore.loadInitialData([
  111. TestStubs.Project({platform: 'javascript-react', firstTransactionEvent: false}),
  112. ]);
  113. const {container} = renderSidebar({
  114. organization: {
  115. ...organization,
  116. features: ['onboarding', 'performance-onboarding-checklist'],
  117. },
  118. });
  119. await waitFor(() => container);
  120. window.open = jest.fn().mockImplementation(() => true);
  121. const quickStart = screen.getByText('Quick Start');
  122. expect(quickStart).toBeInTheDocument();
  123. userEvent.click(quickStart);
  124. const sidebar = await screen.findByRole('dialog');
  125. expect(sidebar).toBeInTheDocument();
  126. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  127. expect(screen.getByText('Level Up')).toBeInTheDocument();
  128. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  129. const performanceCard = screen.getByTestId('setup_transactions');
  130. userEvent.click(performanceCard);
  131. expect(window.open).not.toHaveBeenCalled();
  132. expect(router.push).toHaveBeenCalledWith(
  133. '/organizations/org-slug/performance/?project=2#performance-sidequest'
  134. );
  135. });
  136. it('checklist feature enabled > navigate to performance page > project without onboarding support', async function () {
  137. ProjectsStore.loadInitialData([
  138. TestStubs.Project({platform: 'javascript-angular', firstTransactionEvent: false}),
  139. ]);
  140. const {container} = renderSidebar({
  141. organization: {
  142. ...organization,
  143. features: ['onboarding', 'performance-onboarding-checklist'],
  144. },
  145. });
  146. await waitFor(() => container);
  147. window.open = jest.fn().mockImplementation(() => true);
  148. const quickStart = screen.getByText('Quick Start');
  149. expect(quickStart).toBeInTheDocument();
  150. userEvent.click(quickStart);
  151. const sidebar = await screen.findByRole('dialog');
  152. expect(sidebar).toBeInTheDocument();
  153. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  154. expect(screen.getByText('Level Up')).toBeInTheDocument();
  155. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  156. const performanceCard = screen.getByTestId('setup_transactions');
  157. userEvent.click(performanceCard);
  158. expect(window.open).not.toHaveBeenCalled();
  159. expect(router.push).toHaveBeenCalledWith(
  160. '/organizations/org-slug/performance/?project=2#performance-sidequest'
  161. );
  162. });
  163. it('checklist feature enabled > navigate to performance page > project without performance support', async function () {
  164. ProjectsStore.loadInitialData([
  165. TestStubs.Project({platform: 'elixir', firstTransactionEvent: false}),
  166. ]);
  167. const {container} = renderSidebar({
  168. organization: {
  169. ...organization,
  170. features: ['onboarding', 'performance-onboarding-checklist'],
  171. },
  172. });
  173. await waitFor(() => container);
  174. window.open = jest.fn().mockImplementation(() => true);
  175. const quickStart = screen.getByText('Quick Start');
  176. expect(quickStart).toBeInTheDocument();
  177. userEvent.click(quickStart);
  178. const sidebar = await screen.findByRole('dialog');
  179. expect(sidebar).toBeInTheDocument();
  180. expect(screen.getByText('Capture your first error')).toBeInTheDocument();
  181. expect(screen.getByText('Level Up')).toBeInTheDocument();
  182. expect(screen.getByText('Boost performance')).toBeInTheDocument();
  183. const performanceCard = screen.getByTestId('setup_transactions');
  184. userEvent.click(performanceCard);
  185. expect(window.open).not.toHaveBeenCalled();
  186. expect(router.push).toHaveBeenCalledWith('/organizations/org-slug/performance/');
  187. });
  188. it('displays checklist', async function () {
  189. const project = TestStubs.Project({
  190. platform: 'javascript-react',
  191. firstTransactionEvent: false,
  192. });
  193. ProjectsStore.loadInitialData([project]);
  194. const docApiMocks: any = {};
  195. const docKeys = generateOnboardingDocKeys(project.platform);
  196. docKeys.forEach(docKey => {
  197. docApiMocks[docKey] = MockApiClient.addMockResponse({
  198. url: `/projects/${organization.slug}/${project.slug}/docs/${docKey}/`,
  199. method: 'GET',
  200. body: {html: `<h1>${docKey}</h1> content`},
  201. });
  202. });
  203. MockApiClient.addMockResponse({
  204. url: `/projects/${organization.slug}/${project.slug}/`,
  205. method: 'GET',
  206. body: {},
  207. });
  208. renderSidebar({
  209. organization: {
  210. ...organization,
  211. features: ['onboarding', 'performance-onboarding-checklist'],
  212. },
  213. });
  214. act(() => {
  215. SidebarPanelStore.activatePanel(SidebarPanelKey.PerformanceOnboarding);
  216. });
  217. expect(
  218. await screen.findByText(
  219. textWithMarkupMatcher('Adding Performance to your React project is simple.')
  220. )
  221. ).toBeInTheDocument();
  222. for (const docKey of docKeys) {
  223. expect(
  224. await screen.findByText(textWithMarkupMatcher(`${docKey} content`))
  225. ).toBeInTheDocument();
  226. }
  227. });
  228. });