onboarding.spec.tsx 11 KB

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