setupDocs.spec.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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. if (project.slug !== 'javascript-react') {
  29. MockApiClient.addMockResponse({
  30. url: `/projects/${orgSlug}/${project.slug}/docs/${project.platform}/`,
  31. body: {html: ''},
  32. });
  33. }
  34. }
  35. describe('Onboarding Setup Docs', function () {
  36. it('does not render Product Selection', async function () {
  37. const {router, route, routerContext, organization, project} = initializeOrg({
  38. projects: [
  39. {
  40. ...initializeOrg().project,
  41. slug: 'python',
  42. platform: 'python',
  43. },
  44. ],
  45. });
  46. ProjectsStore.init();
  47. ProjectsStore.loadInitialData([project]);
  48. renderMockRequests({project, orgSlug: organization.slug});
  49. render(
  50. <OnboardingContextProvider>
  51. <SetupDocs
  52. active
  53. onComplete={() => {}}
  54. stepIndex={2}
  55. router={router}
  56. route={route}
  57. location={router.location}
  58. genSkipOnboardingLink={() => ''}
  59. orgId={organization.slug}
  60. search=""
  61. recentCreatedProject={project}
  62. />
  63. </OnboardingContextProvider>,
  64. {
  65. context: routerContext,
  66. organization,
  67. }
  68. );
  69. expect(
  70. await screen.findByRole('heading', {name: 'Configure Python SDK'})
  71. ).toBeInTheDocument();
  72. expect(
  73. screen.queryByTestId(
  74. `product-${ProductSolution.ERROR_MONITORING}-${ProductSolution.PERFORMANCE_MONITORING}-${ProductSolution.SESSION_REPLAY}`
  75. )
  76. ).not.toBeInTheDocument();
  77. });
  78. describe('renders Product Selection', function () {
  79. it('all products checked', async function () {
  80. const {router, route, routerContext, organization, project} = initializeOrg({
  81. router: {
  82. location: {
  83. query: {
  84. product: [
  85. ProductSolution.PERFORMANCE_MONITORING,
  86. ProductSolution.SESSION_REPLAY,
  87. ],
  88. },
  89. },
  90. },
  91. projects: [
  92. {
  93. ...initializeOrg().project,
  94. slug: 'javascript-react',
  95. platform: 'javascript-react',
  96. },
  97. ],
  98. });
  99. ProjectsStore.init();
  100. ProjectsStore.loadInitialData([project]);
  101. renderMockRequests({
  102. project,
  103. orgSlug: organization.slug,
  104. });
  105. render(
  106. <OnboardingContextProvider>
  107. <SetupDocs
  108. active
  109. onComplete={() => {}}
  110. stepIndex={2}
  111. router={router}
  112. route={route}
  113. location={router.location}
  114. genSkipOnboardingLink={() => ''}
  115. orgId={organization.slug}
  116. search=""
  117. recentCreatedProject={project}
  118. />
  119. </OnboardingContextProvider>,
  120. {
  121. context: routerContext,
  122. organization,
  123. }
  124. );
  125. expect(
  126. await screen.findByRole('heading', {name: 'Configure React SDK'})
  127. ).toBeInTheDocument();
  128. expect(await screen.findByText('// Performance Monitoring')).toBeInTheDocument();
  129. expect(screen.getByText('// Session Replay')).toBeInTheDocument();
  130. });
  131. it('only performance checked', async function () {
  132. const {router, route, routerContext, organization, project} = initializeOrg({
  133. router: {
  134. location: {
  135. query: {product: [ProductSolution.PERFORMANCE_MONITORING]},
  136. },
  137. },
  138. projects: [
  139. {
  140. ...initializeOrg().project,
  141. slug: 'javascript-react',
  142. platform: 'javascript-react',
  143. },
  144. ],
  145. });
  146. ProjectsStore.init();
  147. ProjectsStore.loadInitialData([project]);
  148. renderMockRequests({
  149. project,
  150. orgSlug: organization.slug,
  151. });
  152. render(
  153. <OnboardingContextProvider>
  154. <SetupDocs
  155. active
  156. onComplete={() => {}}
  157. stepIndex={2}
  158. router={router}
  159. route={route}
  160. location={router.location}
  161. genSkipOnboardingLink={() => ''}
  162. orgId={organization.slug}
  163. search=""
  164. recentCreatedProject={project}
  165. />
  166. </OnboardingContextProvider>,
  167. {
  168. context: routerContext,
  169. organization,
  170. }
  171. );
  172. expect(await screen.findByText('// Performance Monitoring')).toBeInTheDocument();
  173. expect(screen.queryByText('// Session Replay')).not.toBeInTheDocument();
  174. });
  175. it('only session replay checked', async function () {
  176. const {router, route, routerContext, organization, project} = initializeOrg({
  177. router: {
  178. location: {
  179. query: {product: [ProductSolution.SESSION_REPLAY]},
  180. },
  181. },
  182. projects: [
  183. {
  184. ...initializeOrg().project,
  185. slug: 'javascript-react',
  186. platform: 'javascript-react',
  187. },
  188. ],
  189. });
  190. ProjectsStore.init();
  191. ProjectsStore.loadInitialData([project]);
  192. renderMockRequests({
  193. project,
  194. orgSlug: organization.slug,
  195. });
  196. render(
  197. <OnboardingContextProvider>
  198. <SetupDocs
  199. active
  200. onComplete={() => {}}
  201. stepIndex={2}
  202. router={router}
  203. route={route}
  204. location={router.location}
  205. genSkipOnboardingLink={() => ''}
  206. orgId={organization.slug}
  207. search=""
  208. recentCreatedProject={project}
  209. />
  210. </OnboardingContextProvider>,
  211. {
  212. context: routerContext,
  213. organization,
  214. }
  215. );
  216. expect(await screen.findByText('// Session Replay')).toBeInTheDocument();
  217. expect(screen.queryByText('// Performance Monitoring')).not.toBeInTheDocument();
  218. });
  219. it('only error monitoring checked', async function () {
  220. const {router, route, routerContext, organization, project} = initializeOrg({
  221. router: {
  222. location: {
  223. query: {product: []},
  224. },
  225. },
  226. projects: [
  227. {
  228. ...initializeOrg().project,
  229. slug: 'javascript-react',
  230. platform: 'javascript-react',
  231. },
  232. ],
  233. });
  234. ProjectsStore.init();
  235. ProjectsStore.loadInitialData([project]);
  236. renderMockRequests({
  237. project,
  238. orgSlug: organization.slug,
  239. });
  240. render(
  241. <OnboardingContextProvider>
  242. <SetupDocs
  243. active
  244. onComplete={() => {}}
  245. stepIndex={2}
  246. router={router}
  247. route={route}
  248. location={router.location}
  249. genSkipOnboardingLink={() => ''}
  250. orgId={organization.slug}
  251. search=""
  252. recentCreatedProject={project}
  253. />
  254. </OnboardingContextProvider>,
  255. {
  256. context: routerContext,
  257. organization,
  258. }
  259. );
  260. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  261. expect(screen.queryByText('// Session Replay')).not.toBeInTheDocument();
  262. expect(screen.queryByText('// Performance Monitoring')).not.toBeInTheDocument();
  263. });
  264. });
  265. describe('JS Loader Script', function () {
  266. it('renders Loader Script setup', async function () {
  267. const {router, route, routerContext, organization, project} = initializeOrg({
  268. router: {
  269. location: {
  270. query: {
  271. product: [
  272. ProductSolution.PERFORMANCE_MONITORING,
  273. ProductSolution.SESSION_REPLAY,
  274. ],
  275. },
  276. },
  277. },
  278. projects: [
  279. {
  280. ...initializeOrg().project,
  281. slug: 'javascript',
  282. platform: 'javascript',
  283. },
  284. ],
  285. });
  286. const updateLoaderMock = MockApiClient.addMockResponse({
  287. url: `/projects/${organization.slug}/${project.slug}/keys/${PROJECT_KEY.id}/`,
  288. method: 'PUT',
  289. body: PROJECT_KEY,
  290. });
  291. ProjectsStore.init();
  292. ProjectsStore.loadInitialData([project]);
  293. renderMockRequests({
  294. project,
  295. orgSlug: organization.slug,
  296. });
  297. const {rerender} = render(
  298. <OnboardingContextProvider>
  299. <SetupDocs
  300. active
  301. onComplete={() => {}}
  302. stepIndex={2}
  303. router={router}
  304. route={route}
  305. location={router.location}
  306. genSkipOnboardingLink={() => ''}
  307. orgId={organization.slug}
  308. search=""
  309. recentCreatedProject={project}
  310. />
  311. </OnboardingContextProvider>,
  312. {
  313. context: routerContext,
  314. organization,
  315. }
  316. );
  317. expect(
  318. await screen.findByRole('heading', {name: 'Configure JavaScript SDK'})
  319. ).toBeInTheDocument();
  320. expect(updateLoaderMock).toHaveBeenCalledTimes(1);
  321. expect(updateLoaderMock).toHaveBeenCalledWith(
  322. expect.any(String), // The URL
  323. {
  324. data: {
  325. dynamicSdkLoaderOptions: {
  326. hasDebug: false,
  327. hasPerformance: true,
  328. hasReplay: true,
  329. },
  330. },
  331. error: expect.any(Function),
  332. method: 'PUT',
  333. success: expect.any(Function),
  334. }
  335. );
  336. // update query in URL
  337. router.location.query = {
  338. product: [ProductSolution.SESSION_REPLAY],
  339. };
  340. rerender(
  341. <OnboardingContextProvider>
  342. <SetupDocs
  343. active
  344. onComplete={() => {}}
  345. stepIndex={2}
  346. router={router}
  347. route={route}
  348. location={router.location}
  349. genSkipOnboardingLink={() => ''}
  350. orgId={organization.slug}
  351. search=""
  352. recentCreatedProject={project}
  353. />
  354. </OnboardingContextProvider>
  355. );
  356. expect(updateLoaderMock).toHaveBeenCalledTimes(2);
  357. expect(updateLoaderMock).toHaveBeenLastCalledWith(
  358. expect.any(String), // The URL
  359. {
  360. data: {
  361. dynamicSdkLoaderOptions: {
  362. hasDebug: false,
  363. hasPerformance: false,
  364. hasReplay: true,
  365. },
  366. },
  367. error: expect.any(Function),
  368. method: 'PUT',
  369. success: expect.any(Function),
  370. }
  371. );
  372. });
  373. });
  374. });