onboarding.spec.tsx 10 KB

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