setupDocs.spec.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, waitForElementToBeRemoved} from 'sentry-test/reactTestingLibrary';
  3. import {OnboardingContextProvider} from 'sentry/components/onboarding/onboardingContext';
  4. import {ProductSolution} from 'sentry/components/onboarding/productSelection';
  5. import ProjectsStore from 'sentry/stores/projectsStore';
  6. import {Organization, Project} from 'sentry/types';
  7. import SetupDocs from 'sentry/views/onboarding/setupDocs';
  8. const PROJECT_KEY = TestStubs.ProjectKeys()[0];
  9. function renderMockRequests({
  10. project,
  11. orgSlug,
  12. }: {
  13. orgSlug: Organization['slug'];
  14. project: Project;
  15. }) {
  16. MockApiClient.addMockResponse({
  17. url: `/projects/${orgSlug}/${project.slug}/`,
  18. body: project,
  19. });
  20. MockApiClient.addMockResponse({
  21. url: `/projects/${orgSlug}/${project.slug}/keys/`,
  22. body: [PROJECT_KEY],
  23. });
  24. MockApiClient.addMockResponse({
  25. url: `/projects/${orgSlug}/${project.slug}/issues/`,
  26. body: [],
  27. });
  28. MockApiClient.addMockResponse({
  29. url: `/organizations/${orgSlug}/sdks/`,
  30. body: {
  31. 'sentry.java': {
  32. canonical: 'maven:io.sentry:sentry',
  33. main_docs_url: 'https://docs.sentry.io/platforms/java',
  34. name: 'io.sentry:sentry',
  35. package_url: 'https://search.maven.org/artifact/io.sentry/sentry',
  36. repo_url: 'https://github.com/getsentry/sentry-java',
  37. version: '6.28.0',
  38. },
  39. },
  40. });
  41. if (project.slug !== 'javascript-react') {
  42. MockApiClient.addMockResponse({
  43. url: `/projects/${orgSlug}/${project.slug}/docs/${project.platform}/`,
  44. body: {html: ''},
  45. });
  46. }
  47. }
  48. describe('Onboarding Setup Docs', function () {
  49. it('does not render Product Selection', async function () {
  50. const {router, route, routerContext, organization, project} = initializeOrg({
  51. projects: [
  52. {
  53. ...initializeOrg().project,
  54. slug: 'python',
  55. platform: 'python',
  56. },
  57. ],
  58. });
  59. ProjectsStore.init();
  60. ProjectsStore.loadInitialData([project]);
  61. renderMockRequests({project, orgSlug: organization.slug});
  62. render(
  63. <OnboardingContextProvider>
  64. <SetupDocs
  65. active
  66. onComplete={() => {}}
  67. stepIndex={2}
  68. router={router}
  69. route={route}
  70. location={router.location}
  71. genSkipOnboardingLink={() => ''}
  72. orgId={organization.slug}
  73. search=""
  74. recentCreatedProject={project}
  75. />
  76. </OnboardingContextProvider>,
  77. {
  78. context: routerContext,
  79. organization,
  80. }
  81. );
  82. expect(
  83. await screen.findByRole('heading', {name: 'Configure Python SDK'})
  84. ).toBeInTheDocument();
  85. expect(
  86. screen.queryByTestId(
  87. `product-${ProductSolution.ERROR_MONITORING}-${ProductSolution.PERFORMANCE_MONITORING}-${ProductSolution.SESSION_REPLAY}`
  88. )
  89. ).not.toBeInTheDocument();
  90. });
  91. it('renders SDK version from the sentry release registry', async function () {
  92. const {router, route, routerContext, organization, project} = initializeOrg({
  93. projects: [
  94. {
  95. ...initializeOrg().project,
  96. slug: 'java',
  97. platform: 'java',
  98. },
  99. ],
  100. });
  101. ProjectsStore.init();
  102. ProjectsStore.loadInitialData([project]);
  103. renderMockRequests({project, orgSlug: organization.slug});
  104. render(
  105. <OnboardingContextProvider>
  106. <SetupDocs
  107. active
  108. onComplete={() => {}}
  109. stepIndex={2}
  110. router={router}
  111. route={route}
  112. location={router.location}
  113. genSkipOnboardingLink={() => ''}
  114. orgId={organization.slug}
  115. search=""
  116. recentCreatedProject={project}
  117. />
  118. </OnboardingContextProvider>,
  119. {
  120. context: routerContext,
  121. organization,
  122. }
  123. );
  124. expect(
  125. await screen.findByText(/implementation 'io.sentry:sentry:6.28.0'/)
  126. ).toBeInTheDocument();
  127. });
  128. describe('renders Product Selection', function () {
  129. it('all products checked', async function () {
  130. const {router, route, routerContext, organization, project} = initializeOrg({
  131. router: {
  132. location: {
  133. query: {
  134. product: [
  135. ProductSolution.PERFORMANCE_MONITORING,
  136. ProductSolution.SESSION_REPLAY,
  137. ],
  138. },
  139. },
  140. },
  141. projects: [
  142. {
  143. ...initializeOrg().project,
  144. slug: 'javascript-react',
  145. platform: 'javascript-react',
  146. },
  147. ],
  148. });
  149. ProjectsStore.init();
  150. ProjectsStore.loadInitialData([project]);
  151. renderMockRequests({
  152. project,
  153. orgSlug: organization.slug,
  154. });
  155. render(
  156. <OnboardingContextProvider>
  157. <SetupDocs
  158. active
  159. onComplete={() => {}}
  160. stepIndex={2}
  161. router={router}
  162. route={route}
  163. location={router.location}
  164. genSkipOnboardingLink={() => ''}
  165. orgId={organization.slug}
  166. search=""
  167. recentCreatedProject={project}
  168. />
  169. </OnboardingContextProvider>,
  170. {
  171. context: routerContext,
  172. organization,
  173. }
  174. );
  175. expect(
  176. await screen.findByRole('heading', {name: 'Configure React SDK'})
  177. ).toBeInTheDocument();
  178. expect(await screen.findByText('// Performance Monitoring')).toBeInTheDocument();
  179. expect(screen.getByText('// Session Replay')).toBeInTheDocument();
  180. });
  181. it('only performance checked', async function () {
  182. const {router, route, routerContext, organization, project} = initializeOrg({
  183. router: {
  184. location: {
  185. query: {product: [ProductSolution.PERFORMANCE_MONITORING]},
  186. },
  187. },
  188. projects: [
  189. {
  190. ...initializeOrg().project,
  191. slug: 'javascript-react',
  192. platform: 'javascript-react',
  193. },
  194. ],
  195. });
  196. ProjectsStore.init();
  197. ProjectsStore.loadInitialData([project]);
  198. renderMockRequests({
  199. project,
  200. orgSlug: organization.slug,
  201. });
  202. render(
  203. <OnboardingContextProvider>
  204. <SetupDocs
  205. active
  206. onComplete={() => {}}
  207. stepIndex={2}
  208. router={router}
  209. route={route}
  210. location={router.location}
  211. genSkipOnboardingLink={() => ''}
  212. orgId={organization.slug}
  213. search=""
  214. recentCreatedProject={project}
  215. />
  216. </OnboardingContextProvider>,
  217. {
  218. context: routerContext,
  219. organization,
  220. }
  221. );
  222. expect(await screen.findByText('// Performance Monitoring')).toBeInTheDocument();
  223. expect(screen.queryByText('// Session Replay')).not.toBeInTheDocument();
  224. });
  225. it('only session replay checked', async function () {
  226. const {router, route, routerContext, organization, project} = initializeOrg({
  227. router: {
  228. location: {
  229. query: {product: [ProductSolution.SESSION_REPLAY]},
  230. },
  231. },
  232. projects: [
  233. {
  234. ...initializeOrg().project,
  235. slug: 'javascript-react',
  236. platform: 'javascript-react',
  237. },
  238. ],
  239. });
  240. ProjectsStore.init();
  241. ProjectsStore.loadInitialData([project]);
  242. renderMockRequests({
  243. project,
  244. orgSlug: organization.slug,
  245. });
  246. render(
  247. <OnboardingContextProvider>
  248. <SetupDocs
  249. active
  250. onComplete={() => {}}
  251. stepIndex={2}
  252. router={router}
  253. route={route}
  254. location={router.location}
  255. genSkipOnboardingLink={() => ''}
  256. orgId={organization.slug}
  257. search=""
  258. recentCreatedProject={project}
  259. />
  260. </OnboardingContextProvider>,
  261. {
  262. context: routerContext,
  263. organization,
  264. }
  265. );
  266. expect(await screen.findByText('// Session Replay')).toBeInTheDocument();
  267. expect(screen.queryByText('// Performance Monitoring')).not.toBeInTheDocument();
  268. });
  269. it('only error monitoring checked', async function () {
  270. const {router, route, routerContext, organization, project} = initializeOrg({
  271. router: {
  272. location: {
  273. query: {product: []},
  274. },
  275. },
  276. projects: [
  277. {
  278. ...initializeOrg().project,
  279. slug: 'javascript-react',
  280. platform: 'javascript-react',
  281. },
  282. ],
  283. });
  284. ProjectsStore.init();
  285. ProjectsStore.loadInitialData([project]);
  286. renderMockRequests({
  287. project,
  288. orgSlug: organization.slug,
  289. });
  290. render(
  291. <OnboardingContextProvider>
  292. <SetupDocs
  293. active
  294. onComplete={() => {}}
  295. stepIndex={2}
  296. router={router}
  297. route={route}
  298. location={router.location}
  299. genSkipOnboardingLink={() => ''}
  300. orgId={organization.slug}
  301. search=""
  302. recentCreatedProject={project}
  303. />
  304. </OnboardingContextProvider>,
  305. {
  306. context: routerContext,
  307. organization,
  308. }
  309. );
  310. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  311. expect(screen.queryByText('// Session Replay')).not.toBeInTheDocument();
  312. expect(screen.queryByText('// Performance Monitoring')).not.toBeInTheDocument();
  313. });
  314. });
  315. describe('JS Loader Script', function () {
  316. it('renders Loader Script setup', async function () {
  317. const {router, route, routerContext, organization, project} = initializeOrg({
  318. router: {
  319. location: {
  320. query: {
  321. product: [
  322. ProductSolution.PERFORMANCE_MONITORING,
  323. ProductSolution.SESSION_REPLAY,
  324. ],
  325. },
  326. },
  327. },
  328. projects: [
  329. {
  330. ...initializeOrg().project,
  331. slug: 'javascript',
  332. platform: 'javascript',
  333. },
  334. ],
  335. });
  336. const updateLoaderMock = MockApiClient.addMockResponse({
  337. url: `/projects/${organization.slug}/${project.slug}/keys/${PROJECT_KEY.id}/`,
  338. method: 'PUT',
  339. body: PROJECT_KEY,
  340. });
  341. ProjectsStore.init();
  342. ProjectsStore.loadInitialData([project]);
  343. renderMockRequests({
  344. project,
  345. orgSlug: organization.slug,
  346. });
  347. const {rerender} = render(
  348. <OnboardingContextProvider>
  349. <SetupDocs
  350. active
  351. onComplete={() => {}}
  352. stepIndex={2}
  353. router={router}
  354. route={route}
  355. location={router.location}
  356. genSkipOnboardingLink={() => ''}
  357. orgId={organization.slug}
  358. search=""
  359. recentCreatedProject={project}
  360. />
  361. </OnboardingContextProvider>,
  362. {
  363. context: routerContext,
  364. organization,
  365. }
  366. );
  367. expect(
  368. await screen.findByRole('heading', {name: 'Configure JavaScript SDK'})
  369. ).toBeInTheDocument();
  370. expect(updateLoaderMock).toHaveBeenCalledTimes(1);
  371. expect(updateLoaderMock).toHaveBeenCalledWith(
  372. expect.any(String), // The URL
  373. {
  374. data: {
  375. dynamicSdkLoaderOptions: {
  376. hasDebug: false,
  377. hasPerformance: true,
  378. hasReplay: true,
  379. },
  380. },
  381. error: expect.any(Function),
  382. method: 'PUT',
  383. success: expect.any(Function),
  384. }
  385. );
  386. // update query in URL
  387. router.location.query = {
  388. product: [ProductSolution.SESSION_REPLAY],
  389. };
  390. rerender(
  391. <OnboardingContextProvider>
  392. <SetupDocs
  393. active
  394. onComplete={() => {}}
  395. stepIndex={2}
  396. router={router}
  397. route={route}
  398. location={router.location}
  399. genSkipOnboardingLink={() => ''}
  400. orgId={organization.slug}
  401. search=""
  402. recentCreatedProject={project}
  403. />
  404. </OnboardingContextProvider>
  405. );
  406. expect(updateLoaderMock).toHaveBeenCalledTimes(2);
  407. expect(updateLoaderMock).toHaveBeenLastCalledWith(
  408. expect.any(String), // The URL
  409. {
  410. data: {
  411. dynamicSdkLoaderOptions: {
  412. hasDebug: false,
  413. hasPerformance: false,
  414. hasReplay: true,
  415. },
  416. },
  417. error: expect.any(Function),
  418. method: 'PUT',
  419. success: expect.any(Function),
  420. }
  421. );
  422. });
  423. });
  424. });