onboarding.spec.tsx 10 KB

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