onboarding.spec.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {
  3. render,
  4. renderGlobalModal,
  5. screen,
  6. userEvent,
  7. } from 'sentry-test/reactTestingLibrary';
  8. import {OnboardingContextProvider} from 'sentry/components/onboarding/onboardingContext';
  9. import * as useRecentCreatedProjectHook from 'sentry/components/onboarding/useRecentCreatedProject';
  10. import {PlatformKey} from 'sentry/data/platformCategories';
  11. import {OnboardingProjectStatus, Project} from 'sentry/types';
  12. import Onboarding from 'sentry/views/onboarding/onboarding';
  13. describe('Onboarding', function () {
  14. afterEach(function () {
  15. MockApiClient.clearMockResponses();
  16. });
  17. it('renders the welcome page', function () {
  18. const routeParams = {
  19. step: 'welcome',
  20. };
  21. const {router, route, routerContext, organization} = initializeOrg({
  22. router: {
  23. params: routeParams,
  24. },
  25. });
  26. render(
  27. <OnboardingContextProvider>
  28. <Onboarding
  29. router={router}
  30. location={router.location}
  31. params={routeParams}
  32. routes={router.routes}
  33. routeParams={router.params}
  34. route={route}
  35. />
  36. </OnboardingContextProvider>,
  37. {
  38. context: routerContext,
  39. organization,
  40. }
  41. );
  42. expect(screen.getByLabelText('Start')).toBeInTheDocument();
  43. expect(screen.getByLabelText('Invite Team')).toBeInTheDocument();
  44. });
  45. it('renders the select platform step', async function () {
  46. const routeParams = {
  47. step: 'select-platform',
  48. };
  49. const {router, route, routerContext, organization} = initializeOrg({
  50. router: {
  51. params: routeParams,
  52. },
  53. });
  54. render(
  55. <OnboardingContextProvider>
  56. <Onboarding
  57. router={router}
  58. location={router.location}
  59. params={routeParams}
  60. routes={router.routes}
  61. routeParams={router.params}
  62. route={route}
  63. />
  64. </OnboardingContextProvider>,
  65. {
  66. context: routerContext,
  67. organization,
  68. }
  69. );
  70. expect(
  71. await screen.findByText('Select the platform you want to monitor')
  72. ).toBeInTheDocument();
  73. });
  74. it('renders the setup docs step', async function () {
  75. const nextJsProject: Project = TestStubs.Project({
  76. platform: 'javascript-nextjs',
  77. id: '2',
  78. slug: 'javascript-nextjs-slug',
  79. });
  80. const routeParams = {
  81. step: 'setup-docs',
  82. };
  83. const {router, route, routerContext, organization} = initializeOrg({
  84. router: {
  85. params: routeParams,
  86. },
  87. });
  88. MockApiClient.addMockResponse({
  89. url: `/projects/${organization.slug}/${nextJsProject.slug}/docs/javascript-nextjs-with-error-monitoring/`,
  90. body: null,
  91. });
  92. MockApiClient.addMockResponse({
  93. url: `/projects/org-slug/${nextJsProject.slug}/`,
  94. body: [nextJsProject],
  95. });
  96. MockApiClient.addMockResponse({
  97. url: `/projects/${organization.slug}/${nextJsProject.slug}/issues/`,
  98. body: [],
  99. });
  100. jest
  101. .spyOn(useRecentCreatedProjectHook, 'useRecentCreatedProject')
  102. .mockImplementation(() => {
  103. return {
  104. ...nextJsProject,
  105. firstError: false,
  106. firstTransaction: false,
  107. hasReplays: false,
  108. hasSessions: false,
  109. olderThanOneHour: false,
  110. firstIssue: undefined,
  111. };
  112. });
  113. render(
  114. <OnboardingContextProvider
  115. value={{
  116. selectedSDK: {
  117. key: nextJsProject.slug as PlatformKey,
  118. type: 'framework',
  119. language: 'javascript',
  120. category: 'browser',
  121. },
  122. projects: {
  123. [nextJsProject.id]: {
  124. slug: nextJsProject.slug,
  125. status: OnboardingProjectStatus.WAITING,
  126. firstIssueId: undefined,
  127. },
  128. },
  129. }}
  130. >
  131. <Onboarding
  132. router={router}
  133. location={router.location}
  134. params={routeParams}
  135. routes={router.routes}
  136. routeParams={router.params}
  137. route={route}
  138. />
  139. </OnboardingContextProvider>,
  140. {
  141. context: routerContext,
  142. organization,
  143. }
  144. );
  145. expect(await screen.findByText('Configure Next.js SDK')).toBeInTheDocument();
  146. });
  147. it('renders SDK data removal modal when going back', async function () {
  148. const reactProject: Project = TestStubs.Project({
  149. platform: 'javascript-react',
  150. id: '2',
  151. slug: 'javascript-react-slug',
  152. firstTransactionEvent: false,
  153. firstEvent: false,
  154. hasReplays: false,
  155. hasSessions: false,
  156. });
  157. const routeParams = {
  158. step: 'setup-docs',
  159. };
  160. const {router, route, routerContext, organization} = initializeOrg({
  161. organization: {
  162. features: ['onboarding-project-deletion-on-back-click'],
  163. },
  164. router: {
  165. params: routeParams,
  166. },
  167. });
  168. MockApiClient.addMockResponse({
  169. url: `/projects/${organization.slug}/${reactProject.slug}/docs/javascript-react-with-error-monitoring/`,
  170. body: null,
  171. });
  172. MockApiClient.addMockResponse({
  173. url: `/projects/org-slug/${reactProject.slug}/`,
  174. body: [reactProject],
  175. });
  176. MockApiClient.addMockResponse({
  177. url: `/projects/${organization.slug}/${reactProject.slug}/issues/`,
  178. body: [],
  179. });
  180. jest
  181. .spyOn(useRecentCreatedProjectHook, 'useRecentCreatedProject')
  182. .mockImplementation(() => {
  183. return {
  184. ...reactProject,
  185. firstError: false,
  186. firstTransaction: false,
  187. hasReplays: false,
  188. hasSessions: false,
  189. olderThanOneHour: false,
  190. firstIssue: undefined,
  191. };
  192. });
  193. render(
  194. <OnboardingContextProvider
  195. value={{
  196. selectedSDK: {
  197. key: reactProject.slug as PlatformKey,
  198. type: 'framework',
  199. language: 'javascript',
  200. category: 'browser',
  201. },
  202. projects: {
  203. [reactProject.id]: {
  204. slug: reactProject.slug,
  205. status: OnboardingProjectStatus.WAITING,
  206. firstIssueId: undefined,
  207. },
  208. },
  209. }}
  210. >
  211. <Onboarding
  212. router={router}
  213. location={router.location}
  214. params={routeParams}
  215. routes={router.routes}
  216. routeParams={router.params}
  217. route={route}
  218. />
  219. </OnboardingContextProvider>,
  220. {
  221. context: routerContext,
  222. organization,
  223. }
  224. );
  225. // Await for the docs to be loaded
  226. await screen.findByText('Configure React SDK');
  227. renderGlobalModal();
  228. // Click on back button
  229. await userEvent.click(screen.getByRole('button', {name: 'Back'}));
  230. // Await for the modal to be open
  231. expect(
  232. await screen.findByText(/Are you sure you want to head back?/)
  233. ).toBeInTheDocument();
  234. // Close modal
  235. await userEvent.click(screen.getByRole('button', {name: 'Cancel'}));
  236. });
  237. it('does not render SDK data removal modal when going back', async function () {
  238. const reactProject: Project = TestStubs.Project({
  239. platform: 'javascript-react',
  240. id: '2',
  241. slug: 'javascript-react-slug',
  242. });
  243. const routeParams = {
  244. step: 'setup-docs',
  245. };
  246. const {router, route, routerContext, organization} = initializeOrg({
  247. organization: {
  248. features: ['onboarding-project-deletion-on-back-click'],
  249. },
  250. router: {
  251. params: routeParams,
  252. },
  253. });
  254. MockApiClient.addMockResponse({
  255. url: `/projects/${organization.slug}/${reactProject.slug}/docs/javascript-react-with-error-monitoring/`,
  256. body: null,
  257. });
  258. MockApiClient.addMockResponse({
  259. url: `/projects/org-slug/${reactProject.slug}/`,
  260. body: [reactProject],
  261. });
  262. MockApiClient.addMockResponse({
  263. url: `/projects/${organization.slug}/${reactProject.slug}/issues/`,
  264. body: [],
  265. });
  266. jest
  267. .spyOn(useRecentCreatedProjectHook, 'useRecentCreatedProject')
  268. .mockImplementation(() => {
  269. return {
  270. ...reactProject,
  271. firstError: false,
  272. firstTransaction: false,
  273. hasReplays: false,
  274. hasSessions: true,
  275. olderThanOneHour: false,
  276. firstIssue: undefined,
  277. };
  278. });
  279. render(
  280. <OnboardingContextProvider
  281. value={{
  282. selectedSDK: {
  283. key: reactProject.slug as PlatformKey,
  284. type: 'framework',
  285. language: 'javascript',
  286. category: 'browser',
  287. },
  288. projects: {
  289. [reactProject.id]: {
  290. slug: reactProject.slug,
  291. status: OnboardingProjectStatus.WAITING,
  292. firstIssueId: undefined,
  293. },
  294. },
  295. }}
  296. >
  297. <Onboarding
  298. router={router}
  299. location={router.location}
  300. params={routeParams}
  301. routes={router.routes}
  302. routeParams={router.params}
  303. route={route}
  304. />
  305. </OnboardingContextProvider>,
  306. {
  307. context: routerContext,
  308. organization,
  309. }
  310. );
  311. // Await for the docs to be loaded
  312. await screen.findByText('Configure React SDK');
  313. renderGlobalModal();
  314. // Click on back button
  315. await userEvent.click(screen.getByRole('button', {name: 'Back'}));
  316. // Await for the modal to be open
  317. expect(
  318. screen.queryByText(/Are you sure you want to head back?/)
  319. ).not.toBeInTheDocument();
  320. });
  321. it('renders framework selection modal if vanilla js is selected', async function () {
  322. const routeParams = {
  323. step: 'select-platform',
  324. };
  325. const {router, route, routerContext, organization} = initializeOrg({
  326. organization: {
  327. features: ['onboarding-sdk-selection'],
  328. },
  329. router: {
  330. params: routeParams,
  331. },
  332. });
  333. render(
  334. <OnboardingContextProvider>
  335. <Onboarding
  336. router={router}
  337. location={router.location}
  338. params={routeParams}
  339. routes={router.routes}
  340. routeParams={router.params}
  341. route={route}
  342. />
  343. </OnboardingContextProvider>,
  344. {
  345. context: routerContext,
  346. organization,
  347. }
  348. );
  349. renderGlobalModal();
  350. // Select the JavaScript platform
  351. await userEvent.click(screen.getByTestId('platform-javascript'));
  352. // Click on 'configure SDK' button
  353. await userEvent.click(screen.getByRole('button', {name: 'Configure SDK'}));
  354. // Modal is open
  355. await screen.findByText('Do you use a framework?');
  356. // Close modal
  357. await userEvent.click(screen.getByRole('button', {name: 'Skip'}));
  358. });
  359. it('does not render framework selection modal if vanilla js is NOT selected', async function () {
  360. const routeParams = {
  361. step: 'select-platform',
  362. };
  363. const {router, route, routerContext, organization} = initializeOrg({
  364. organization: {
  365. features: ['onboarding-sdk-selection'],
  366. },
  367. router: {
  368. params: routeParams,
  369. },
  370. });
  371. render(
  372. <OnboardingContextProvider>
  373. <Onboarding
  374. router={router}
  375. location={router.location}
  376. params={routeParams}
  377. routes={router.routes}
  378. routeParams={router.params}
  379. route={route}
  380. />
  381. </OnboardingContextProvider>,
  382. {
  383. context: routerContext,
  384. organization,
  385. }
  386. );
  387. // Select the React platform
  388. await userEvent.click(screen.getByTestId('platform-javascript-react'));
  389. // Click on 'configure SDK' button
  390. await userEvent.click(screen.getByRole('button', {name: 'Configure SDK'}));
  391. // Modal shall not be open
  392. expect(screen.queryByText('Do you use a framework?')).not.toBeInTheDocument();
  393. });
  394. });