onboarding.spec.tsx 11 KB

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