onboarding.spec.tsx 11 KB

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