From 7503b6713eb87d8d3ab5771f1fffddd08c84d16c Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Oct 2023 18:12:37 +0100 Subject: [PATCH 1/2] ref(getting-started): Update remix onboarding with wizard --- .../onboarding/productSelection.tsx | 4 - .../gettingStartedDocs/javascript/remix.tsx | 404 ++++++------------ 2 files changed, 125 insertions(+), 283 deletions(-) diff --git a/static/app/components/onboarding/productSelection.tsx b/static/app/components/onboarding/productSelection.tsx index 5675e963f7ed1d..6ab862d4ad62a8 100644 --- a/static/app/components/onboarding/productSelection.tsx +++ b/static/app/components/onboarding/productSelection.tsx @@ -100,10 +100,6 @@ export const platformProductAvailability = { ProductSolution.PERFORMANCE_MONITORING, ProductSolution.SESSION_REPLAY, ], - 'javascript-remix': [ - ProductSolution.PERFORMANCE_MONITORING, - ProductSolution.SESSION_REPLAY, - ], 'javascript-svelte': [ ProductSolution.PERFORMANCE_MONITORING, ProductSolution.SESSION_REPLAY, diff --git a/static/app/gettingStartedDocs/javascript/remix.tsx b/static/app/gettingStartedDocs/javascript/remix.tsx index f3954b1ff14ff5..dd3fb501b14e63 100644 --- a/static/app/gettingStartedDocs/javascript/remix.tsx +++ b/static/app/gettingStartedDocs/javascript/remix.tsx @@ -1,283 +1,129 @@ import ExternalLink from 'sentry/components/links/externalLink'; -import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout'; -import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation'; +import List from 'sentry/components/list'; +import ListItem from 'sentry/components/list/listItem'; import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step'; -import {ProductSolution} from 'sentry/components/onboarding/productSelection'; -import {t, tct} from 'sentry/locale'; - -// Configuration Start -const replayIntegration = ` -new Sentry.Replay(), -`; - -const replayOtherConfig = ` -// Session Replay -replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. -replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. -`; - -const performanceIntegration = ` -new Sentry.BrowserTracing({ - // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled - tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/], - routingInstrumentation: Sentry.remixRouterInstrumentation( - useEffect, - useLocation, - useMatches - ), -}), -`; - -const performanceOtherConfig = ` -// Performance Monitoring -tracesSampleRate: 1.0, // Capture 100% of the transactions`; - -const prismaIntegration = `new Sentry.Integrations.Prisma({ client: prisma }),`; - -export const steps = ({ - sentryInitContent, - sentryInitContentServer, -}: { - sentryInitContent?: string; - sentryInitContentServer?: string[]; -} = {}): LayoutProps['steps'] => [ - { - type: StepType.INSTALL, - description: ( -

- {tct( - 'Add the Sentry SDK as a dependency using [codeNpm:npm] or [codeYarn:yarn]:', - { - codeYarn: , - codeNpm: , - } - )} -

- ), - configurations: [ - { - language: 'bash', - code: [ - { - label: 'npm', - value: 'npm', - language: 'bash', - code: 'npm install --save @sentry/remix', - }, - { - label: 'yarn', - value: 'yarn', - language: 'bash', - code: 'yarn add @sentry/remix', - }, - ], - }, - ], - }, - { - type: StepType.CONFIGURE, - description: ( -

- {tct( - 'Import and initialize Sentry in your Remix entry points for the client ([clientFile:entry.client.tsx]):', - { - clientFile: , - } - )} -

- ), - configurations: [ - { - language: 'javascript', - code: ` - import { useLocation, useMatches } from "@remix-run/react"; - import * as Sentry from "@sentry/remix"; - import { useEffect } from "react"; - - Sentry.init({ - ${sentryInitContent} - }); - `, - }, - { - language: 'javascript', - description: ( -

- {tct( - `Initialize Sentry in your entry point for the server ([serverFile:entry.server.tsx]) to capture exceptions and get performance metrics for your [action] and [loader] functions. You can also initialize Sentry's database integrations, such as Prisma, to get spans for your database calls:`, - { - action: ( - - ), - loader: ( - - ), - serverFile: , - } - )} -

- ), - code: ` - ${ - (sentryInitContentServer ?? []).length > 1 - ? `import { prisma } from "~/db.server";` - : '' - } - - import * as Sentry from "@sentry/remix"; - - Sentry.init({ - ${sentryInitContentServer?.join('\n')} - }); - `, - }, - { - description: t( - 'Lastly, wrap your Remix root with "withSentry" to catch React component errors and to get parameterized router transactions:' - ), - language: 'javascript', - code: ` import { - Links, - LiveReload, - Meta, - Outlet, - Scripts, - ScrollRestoration, -} from "@remix-run/react"; - -import { withSentry } from "@sentry/remix"; - -function App() { - return ( - - - - - - - - - - - - - ); -} - -export default withSentry(App); - `, - }, - ], - }, - { - type: StepType.VERIFY, - description: t( - "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected." - ), - configurations: [ - { - language: 'jsx', - code: ` - - `, - }, - ], - }, -]; - -export const nextSteps = [ - { - id: 'source-maps', - name: t('Source Maps'), - description: t('Learn how to enable readable stack traces in your Sentry errors.'), - link: 'https://docs.sentry.io/platforms/javascript/guides/remix/sourcemaps/', - }, - { - id: 'performance-monitoring', - name: t('Performance Monitoring'), - description: t( - 'Track down transactions to connect the dots between 10-second page loads and poor-performing API calls or slow database queries.' - ), - link: 'https://docs.sentry.io/platforms/javascript/guides/remix/performance/', - }, - { - id: 'session-replay', - name: t('Session Replay'), - description: t( - 'Get to the root cause of an error or latency issue faster by seeing all the technical details related to that issue in one visual replay on your web application.' - ), - link: 'https://docs.sentry.io/platforms/javascript/guides/remix/session-replay/', - }, -]; -// Configuration End - -export function GettingStartedWithRemix({ - dsn, - activeProductSelection = [], - ...props -}: ModuleProps) { - const integrations: string[] = []; - const otherConfigs: string[] = []; - - const serverIntegrations: string[] = []; - const otherConfigsServer: string[] = []; - - let nextStepDocs = [...nextSteps]; - - if (activeProductSelection.includes(ProductSolution.PERFORMANCE_MONITORING)) { - integrations.push(performanceIntegration.trim()); - otherConfigs.push(performanceOtherConfig.trim()); - serverIntegrations.push(prismaIntegration.trim()); - otherConfigsServer.push(performanceOtherConfig.trim()); - nextStepDocs = nextStepDocs.filter( - step => step.id !== ProductSolution.PERFORMANCE_MONITORING - ); - } - - if (activeProductSelection.includes(ProductSolution.SESSION_REPLAY)) { - integrations.push(replayIntegration.trim()); - otherConfigs.push(replayOtherConfig.trim()); - nextStepDocs = nextStepDocs.filter( - step => step.id !== ProductSolution.SESSION_REPLAY - ); - } - - let sentryInitContent: string[] = [`dsn: "${dsn}",`]; - let sentryInitContentServer: string[] = [`dsn: "${dsn}",`]; - - if (integrations.length > 0) { - sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],'); - } - - if (serverIntegrations.length) { - sentryInitContentServer = sentryInitContentServer.concat( - 'integrations: [', - serverIntegrations, - '],' - ); - } - - if (otherConfigs.length > 0) { - sentryInitContent = sentryInitContent.concat(otherConfigs); - } - - if (otherConfigsServer.length) { - sentryInitContentServer = sentryInitContentServer.concat(otherConfigsServer); - } - - return ( - - ); -} + Docs, + DocsParams, + OnboardingConfig, +} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; -export default GettingStartedWithRemix; +type Params = DocsParams; + +const onboarding: OnboardingConfig = { + introduction: () => + tct("Sentry's integration with [remixLink:Remix] supports Remix 1.0.0 and above.", { + remixLink: , + }), + install: (_params: Params) => [ + { + type: StepType.INSTALL, + configurations: [ + { + description: t( + 'Install and configure the Sentry Remix SDK automatically with our wizard:' + ), + language: 'bash', + code: [ + { + label: 'bash', + value: 'bash', + language: 'bash', + code: `npx @sentry/wizard@latest -i remix`, + }, + ], + }, + ], + }, + ], + configure: () => [ + { + type: StepType.CONFIGURE, + description: t( + 'The Sentry wizard will automatically add code to your project to inialize and configure the Sentry SDK:' + ), + configurations: [ + { + description: ( + + + {tct( + "Create two files in the root directory of your project, [clientEntry:entry.client.tsx] and [serverEntry:entry.server.tsx] (if they don't already exist).", + { + clientEntry: , + serverEntry: , + } + )} + + + {tct( + 'Add the default [sentryInitCode:Sentry.init] call to both, client and server entry files.', + { + sentryInitCode: , + } + )} + + + {tct( + 'Create a [cliRc:.sentryclirc] with an auth token to upload source maps (this file is automatically added to your [gitignore:.gitignore]).', + { + cliRc: , + gitignore: , + } + )} + + + {tct( + 'Adjust your [buildscript:build] script in your [pkgJson:package.json] to automatically upload source maps to Sentry when you build your application.', + { + buildscript: , + pkgJson: , + } + )} + + + ), + }, + { + description: tct( + 'You can also further [manualConfigure:configure your SDK] or [manualSetupLink:set it up manually], without the wizard.', + { + manualConfigure: ( + + ), + manualSetupLink: ( + + ), + } + ), + }, + ], + }, + ], + verify: () => [], + nextSteps: () => [ + { + id: 'performance-monitoring', + name: t('Performance Monitoring'), + description: t( + 'Track down transactions to connect the dots between 10-second page loads and poor-performing API calls or slow database queries.' + ), + link: 'https://docs.sentry.io/platforms/javascript/guides/remix/performance/', + }, + { + id: 'session-replay', + name: t('Session Replay'), + description: t( + 'Get to the root cause of an error or latency issue faster by seeing all the technical details related to that issue in one visual replay on your web application.' + ), + link: 'https://docs.sentry.io/platforms/javascript/guides/remix/session-replay/', + }, + ], +}; + +const docs: Docs = { + onboarding, +}; + +export default docs; From 9ac087af0e331e39ba0219d8b4bfa18447f9f369 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Oct 2023 18:20:34 +0100 Subject: [PATCH 2/2] adjust tests --- .../javascript/remix.spec.tsx | 53 ++++++------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/static/app/gettingStartedDocs/javascript/remix.spec.tsx b/static/app/gettingStartedDocs/javascript/remix.spec.tsx index 5ccf7b83f447a9..ff2b9e4135c838 100644 --- a/static/app/gettingStartedDocs/javascript/remix.spec.tsx +++ b/static/app/gettingStartedDocs/javascript/remix.spec.tsx @@ -1,43 +1,24 @@ -import {render, screen} from 'sentry-test/reactTestingLibrary'; +import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout'; +import {screen} from 'sentry-test/reactTestingLibrary'; +import {textWithMarkupMatcher} from 'sentry-test/utils'; -import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step'; -import {ProductSolution} from 'sentry/components/onboarding/productSelection'; +import docs from './remix'; -import {GettingStartedWithRemix, nextSteps, steps} from './remix'; +describe('javascript-remix onboarding docs', function () { + it('renders onboarding docs correctly', () => { + renderWithOnboardingLayout(docs); -describe('GettingStartedWithRemix', function () { - it('all products are selected', function () { - render( - - ); + // Renders main headings + expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument(); + expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument(); + expect(screen.getByRole('heading', {name: 'Next Steps'})).toBeInTheDocument(); - // Steps - for (const step of steps()) { - expect( - screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]}) - ).toBeInTheDocument(); - } + // Includes minimum required Astro version + expect(screen.getByText(textWithMarkupMatcher(/Remix 1.0.0/))).toBeInTheDocument(); - // Next Steps - const filteredNextStepsLinks = nextSteps.filter( - nextStep => - ![ - ProductSolution.PERFORMANCE_MONITORING, - ProductSolution.SESSION_REPLAY, - ].includes(nextStep.id as ProductSolution) - ); - - for (const filteredNextStepsLink of filteredNextStepsLinks) { - expect( - screen.getByRole('link', {name: filteredNextStepsLink.name}) - ).toBeInTheDocument(); - } + // Includes wizard command statement + expect( + screen.getByText(textWithMarkupMatcher(/npx @sentry\/wizard@latest -i remix/)) + ).toBeInTheDocument(); }); });