setupDocs.spec.tsx 13 KB

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