onboarding.spec.tsx 10 KB

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