onboarding.spec.tsx 11 KB

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