Просмотр исходного кода

ref(onboarding docs): [3/4] convert gatsby, sveltekit, and nextjs (#61311)

Relates to https://github.com/getsentry/sentry/issues/61266
Michelle Zhang 1 год назад
Родитель
Сommit
99c4e2fb89

+ 70 - 38
static/app/gettingStartedDocs/javascript/gatsby.spec.tsx

@@ -1,43 +1,75 @@
-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 {GettingStartedWithGatsby, nextSteps, steps} from './gatsby';
-
-describe('GettingStartedWithGatsby', function () {
-  it('all products are selected', function () {
-    render(
-      <GettingStartedWithGatsby
-        dsn="test-dsn"
-        projectSlug="test-project"
-        activeProductSelection={[
-          ProductSolution.PERFORMANCE_MONITORING,
-          ProductSolution.SESSION_REPLAY,
-        ]}
-      />
-    );
-
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).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();
-    }
+import docs from './gatsby';
+
+describe('javascript-gatsby onboarding docs', function () {
+  it('renders onboarding docs correctly', () => {
+    renderWithOnboardingLayout(docs);
+
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Upload Source Maps'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Verify'})).toBeInTheDocument();
+
+    // Includes import statement
+    expect(
+      screen.getByText(
+        textWithMarkupMatcher(/import \* as Sentry from "@sentry\/gatsby"/)
+      )
+    ).toBeInTheDocument();
+  });
+
+  it('displays sample rates by default', () => {
+    renderWithOnboardingLayout(docs, {
+      selectedProducts: [
+        ProductSolution.ERROR_MONITORING,
+        ProductSolution.PERFORMANCE_MONITORING,
+        ProductSolution.SESSION_REPLAY,
+      ],
+    });
+
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/tracesSampleRate/))
+    ).toBeInTheDocument();
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/replaysSessionSampleRate/))
+    ).toBeInTheDocument();
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/replaysOnErrorSampleRate/))
+    ).toBeInTheDocument();
+  });
+
+  it('enables performance setting the tracesSampleRate to 1', () => {
+    renderWithOnboardingLayout(docs, {
+      selectedProducts: [
+        ProductSolution.ERROR_MONITORING,
+        ProductSolution.PERFORMANCE_MONITORING,
+      ],
+    });
+
+    expect(
+      screen.getByText(textWithMarkupMatcher(/tracesSampleRate: 1\.0/))
+    ).toBeInTheDocument();
+  });
+
+  it('enables replay by setting replay samplerates', () => {
+    renderWithOnboardingLayout(docs, {
+      selectedProducts: [
+        ProductSolution.ERROR_MONITORING,
+        ProductSolution.SESSION_REPLAY,
+      ],
+    });
+
+    expect(
+      screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate: 0\.1/))
+    ).toBeInTheDocument();
+    expect(
+      screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate: 1\.0/))
+    ).toBeInTheDocument();
   });
 });

+ 160 - 203
static/app/gettingStartedDocs/javascript/gatsby.tsx

@@ -1,215 +1,172 @@
-import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
-import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
-import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 import {t, tct} from 'sentry/locale';
-import type {Organization, PlatformKey} from 'sentry/types';
 
-type StepProps = {
-  newOrg: boolean;
-  organization: Organization;
-  platformKey: PlatformKey;
-  projectId: string;
-  sentryInitContent: string;
-};
-
-// 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.
-`;
+type Params = DocsParams;
+
+const getSdkSetupSnippet = (params: Params) => `
+import * as Sentry from "@sentry/gatsby";
+
+Sentry.init({
+  dsn: "${params.dsn}",
+  integrations: [${
+    params.isPerformanceSelected
+      ? `
+        new Sentry.BrowserTracing({
+          // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
+          tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/],
+        }),`
+      : ''
+  }${
+    params.isReplaySelected
+      ? `
+        new Sentry.Replay(),`
+      : ''
+  }
+],${
+  params.isPerformanceSelected
+    ? `
+      // Performance Monitoring
+      tracesSampleRate: 1.0, //  Capture 100% of the transactions`
+    : ''
+}${
+  params.isReplaySelected
+    ? `
+      // 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/],
-}),
+const container = document.getElementById(“app”);
+const root = createRoot(container);
+root.render(<App />);
 `;
 
-const performanceOtherConfig = `
-// Performance Monitoring
-tracesSampleRate: 1.0, // Capture 100% of the transactions`;
-
-export const steps = ({
-  sentryInitContent,
-  ...props
-}: Partial<StepProps> = {}): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct(
-          'Add the Sentry SDK as a dependency using [codeNpm:npm] or [codeYarn:yarn]:',
-          {
-            codeYarn: <code />,
-            codeNpm: <code />,
-          }
-        )}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: [
-          {
-            label: 'npm',
-            value: 'npm',
-            language: 'bash',
-            code: 'npm install --save @sentry/gatsby',
-          },
-          {
-            label: 'yarn',
-            value: 'yarn',
-            language: 'bash',
-            code: 'yarn add @sentry/gatsby',
-          },
-        ],
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    configurations: [
-      {
-        description: (
-          <p>
-            {tct(
-              'Register the [sentryGatsbyCode:@sentry/gatsby] plugin in your Gatsby configuration file (typically [gatsbyConfigCode:gatsby-config.js]).',
-              {
-                sentryGatsbyCode: <code />,
-                gatsbyConfigCode: <code />,
-              }
-            )}
-          </p>
-        ),
-        language: 'javascript',
-        code: `
-        module.exports = {
-          plugins: [
+const getVerifyGatsbySnippet = () => `
+myUndefinedFunction();`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      configurations: [
+        {
+          description: tct(
+            'Add the Sentry SDK as a dependency using [codeNpm:npm] or [codeYarn:yarn]:',
+            {
+              codeYarn: <code />,
+              codeNpm: <code />,
+            }
+          ),
+          language: 'bash',
+          code: [
             {
-              resolve: "@sentry/gatsby",
+              label: 'npm',
+              value: 'npm',
+              language: 'bash',
+              code: 'npm install --save @sentry/gatsby',
+            },
+            {
+              label: 'yarn',
+              value: 'yarn',
+              language: 'bash',
+              code: 'yarn add @sentry/gatsby',
             },
           ],
-        };
-        `,
-      },
-      {
-        description: (
-          <p>{tct('Then, configure your [code:Sentry.init]:', {code: <code />})}</p>
-        ),
-        language: 'javascript',
-        code: `
-        import * as Sentry from "@sentry/gatsby";
-
-        Sentry.init({
-          ${sentryInitContent}
-        });
-
-        const container = document.getElementById(“app”);
-        const root = createRoot(container);
-        root.render(<App />)
-        `,
-      },
-    ],
-  },
-  getUploadSourceMapsStep({
-    guideLink: 'https://docs.sentry.io/platforms/javascript/guides/gatsby/sourcemaps/',
-    ...props,
-  }),
-  {
-    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: 'javascript',
-        code: 'myUndefinedFunction();',
-      },
-    ],
-  },
-];
-
-export const 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/gatsby/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/gatsby/session-replay/',
-  },
-];
-// Configuration End
-
-export function GettingStartedWithGatsby({
-  dsn,
-  activeProductSelection = [],
-  organization,
-  newOrg,
-  platformKey,
-  projectId,
-  ...props
-}: ModuleProps) {
-  const integrations: string[] = [];
-  const otherConfigs: string[] = [];
-  let nextStepDocs = [...nextSteps];
-
-  if (activeProductSelection.includes(ProductSolution.PERFORMANCE_MONITORING)) {
-    integrations.push(performanceIntegration.trim());
-    otherConfigs.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}",`];
-
-  if (integrations.length > 0) {
-    sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],');
-  }
-
-  if (otherConfigs.length > 0) {
-    sentryInitContent = sentryInitContent.concat(otherConfigs);
-  }
+        },
+      ],
+    },
+  ],
+  configure: (params: Params) => [
+    {
+      type: StepType.CONFIGURE,
+      configurations: [
+        {
+          description: tct(
+            'Register the [codeSentry@sentry/gatsby] plugin in your Gatsby configuration file (typically [codeGatsby:gatsby-config.js]).',
+            {codeSentry: <code />, codeGatsby: <code />}
+          ),
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: `module.exports = {
+                plugins: [{
+                  resolve: "@sentry/gatsby",
+                }],
+              };`,
+            },
+          ],
+        },
+        {
+          description: tct('Then, configure your [codeSentry:Sentry.init:]', {
+            codeSentry: <code />,
+          }),
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: getSdkSetupSnippet(params),
+            },
+          ],
+        },
+      ],
+    },
+    getUploadSourceMapsStep({
+      guideLink: 'https://docs.sentry.io/platforms/javascript/guides/gatsby/sourcemaps//',
+    }),
+  ],
+  verify: () => [
+    {
+      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: [
+        {
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: getVerifyGatsbySnippet(),
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  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/gatsby/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/gatsby/session-replay/',
+    },
+  ],
+};
 
-  return (
-    <Layout
-      steps={steps({
-        sentryInitContent: sentryInitContent.join('\n'),
-        organization,
-        newOrg,
-        platformKey,
-        projectId,
-      })}
-      nextSteps={nextStepDocs}
-      platformKey={platformKey}
-      newOrg={newOrg}
-      {...props}
-    />
-  );
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithGatsby;
+export default docs;

+ 30 - 24
static/app/gettingStartedDocs/javascript/nextjs.spec.tsx

@@ -1,31 +1,37 @@
-import {Organization} from 'sentry-fixture/organization';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
+import {textWithMarkupMatcher} from 'sentry-test/utils';
 
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs from './nextjs';
 
-import {GettingStartedWithNextJs, steps} from './nextjs';
+describe('javascript-nextjs onboarding docs', function () {
+  it('renders onboarding docs correctly', () => {
+    renderWithOnboardingLayout(docs);
 
-describe('GettingStartedWithNextJs', function () {
-  const organization = Organization();
-  it('renders doc correctly', function () {
-    render(
-      <GettingStartedWithNextJs
-        dsn="test-dsn"
-        projectSlug="test-project"
-        organization={organization}
-      />
-    );
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
 
-    // Steps
-    for (const step of steps({
-      dsn: 'test-dsn',
-      projectSlug: 'test-project',
-      organization,
-    })) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Includes configure statement
+    expect(
+      screen.getByText(textWithMarkupMatcher(/npx @sentry\/wizard@latest -i nextjs/))
+    ).toBeInTheDocument();
+  });
+
+  it('displays the configure instructions', () => {
+    renderWithOnboardingLayout(docs, {
+      selectedProducts: [
+        ProductSolution.ERROR_MONITORING,
+        ProductSolution.PERFORMANCE_MONITORING,
+        ProductSolution.SESSION_REPLAY,
+      ],
+    });
+
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/sentry.client.config.js/))
+    ).toBeInTheDocument();
+    expect(screen.queryByText(textWithMarkupMatcher(/Sentry.init/))).toBeInTheDocument();
+    expect(screen.queryByText(textWithMarkupMatcher(/.sentryclirc/))).toBeInTheDocument();
   });
 });

+ 100 - 96
static/app/gettingStartedDocs/javascript/nextjs.tsx

@@ -4,119 +4,123 @@ import styled from '@emotion/styled';
 import ExternalLink from 'sentry/components/links/externalLink';
 import List from 'sentry/components/list/';
 import ListItem from 'sentry/components/list/listItem';
-import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
-import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import TextCopyInput from 'sentry/components/textCopyInput';
 import {t, tct} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
-import {Organization} from 'sentry/types';
 import {trackAnalytics} from 'sentry/utils/analytics';
 
-type Props = {
-  dsn: string;
-  organization: Organization | undefined;
-  projectSlug: string;
-};
+type Params = DocsParams;
 
-export const steps = ({dsn, projectSlug, organization}: Props): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Configure your app automatically with the [wizardLink:Sentry wizard].', {
-          wizardLink: (
-            <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/#install" />
+const onboarding: OnboardingConfig = {
+  install: (params: Params) => [
+    {
+      type: StepType.INSTALL,
+      configurations: [
+        {
+          description: tct(
+            'Configure your app automatically with the [wizardLink:Sentry wizard].',
+            {
+              wizardLink: (
+                <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/#install" />
+              ),
+            }
           ),
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: `npx @sentry/wizard@latest -i nextjs`,
-      },
-    ],
-    additionalInfo: (
-      <Fragment>
-        {t(
-          'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
-        )}
-        <List symbol="bullet">
-          <ListItem>
-            {tct(
-              'Create [clientCode:sentry.client.config.js] and [serverCode:sentry.server.config.js] with the default [sentryInitCode:Sentry.init].',
-              {
-                clientCode: <code />,
-                serverCode: <code />,
-                sentryInitCode: <code />,
-              }
-            )}
-          </ListItem>
-          <ListItem>
-            {tct(
-              'Create or update your Next.js config [nextConfig:next.config.js] with the default Sentry configuration.',
-              {
-                nextConfig: <code />,
-              }
-            )}
-          </ListItem>
-          <ListItem>
-            {tct(
-              'Create [sentryClircCode:.sentryclirc] and [sentryPropertiesCode:sentry.properties] files with configuration for sentry-cli (which is used when automatically uploading source maps).',
-              {
+          language: 'bash',
+          code: `npx @sentry/wizard@latest -i nextjs`,
+        },
+      ],
+      additionalInfo: (
+        <Fragment>
+          {t(
+            'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
+          )}
+          <List symbol="bullet">
+            <ListItem>
+              {tct(
+                'Create [clientCode:sentry.client.config.js] and [serverCode:sentry.server.config.js] with the default [sentryInitCode:Sentry.init].',
+                {
+                  clientCode: <code />,
+                  serverCode: <code />,
+                  sentryInitCode: <code />,
+                }
+              )}
+            </ListItem>
+            <ListItem>
+              {tct(
+                'Create or update your Next.js config [nextConfig:next.config.js] with the default Sentry configuration.',
+                {
+                  nextConfig: <code />,
+                }
+              )}
+            </ListItem>
+            <ListItem>
+              {tct(
+                'Create [sentryClircCode:.sentryclirc] and [sentryPropertiesCode:sentry.properties] files with configuration for sentry-cli (which is used when automatically uploading source maps).',
+                {
+                  sentryClircCode: <code />,
+                  sentryPropertiesCode: <code />,
+                }
+              )}
+            </ListItem>
+            <ListItem>
+              {tct('Add an example page to your app to verify your Sentry setup.', {
                 sentryClircCode: <code />,
-                sentryPropertiesCode: <code />,
-              }
-            )}
-          </ListItem>
-          <ListItem>
-            {tct('Add an example page to your app to verify your Sentry setup.', {
-              sentryClircCode: <code />,
-            })}
-          </ListItem>
-        </List>
-        <br />
-        <ManualSetupTitle>{t('Manual Setup')}</ManualSetupTitle>
-        <p>
-          {tct('Alternatively, you can also [manualSetupLink:set up the SDK manually].', {
-            manualSetupLink: (
-              <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/" />
-            ),
-          })}
-        </p>
-        <br />
-        <DSNText>
+              })}
+            </ListItem>
+          </List>
+          <br />
+          <ManualSetupTitle>{t('Manual Setup')}</ManualSetupTitle>
           <p>
             {tct(
-              "If you already have the configuration for Sentry in your application, and just need this project's ([projectSlug]) DSN, you can find it below:",
+              'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
               {
-                projectSlug: <code>{projectSlug}</code>,
+                manualSetupLink: (
+                  <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/" />
+                ),
               }
             )}
           </p>
-        </DSNText>
-        {organization && (
-          <TextCopyInput
-            onCopy={() => trackAnalytics('onboarding.nextjs-dsn-copied', {organization})}
-          >
-            {dsn}
-          </TextCopyInput>
-        )}
-      </Fragment>
-    ),
-  },
-];
-
-// Configuration End
-
-export function GettingStartedWithNextJs({...props}: ModuleProps) {
-  const {projectSlug, dsn, organization} = props;
+          <br />
+          <DSNText>
+            <p>
+              {tct(
+                "If you already have the configuration for Sentry in your application, and just need this project's ([projectSlug]) DSN, you can find it below:",
+                {
+                  projectSlug: <code>{params.projectSlug}</code>,
+                }
+              )}
+            </p>
+          </DSNText>
+          {params.organization && (
+            <TextCopyInput
+              onCopy={() =>
+                trackAnalytics('onboarding.nextjs-dsn-copied', {
+                  organization: params.organization,
+                })
+              }
+            >
+              {params.dsn}
+            </TextCopyInput>
+          )}
+        </Fragment>
+      ),
+    },
+  ],
+  configure: () => [],
+  verify: () => [],
+};
 
-  return <Layout steps={steps({dsn, projectSlug, organization})} {...props} />;
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithNextJs;
+export default docs;
 
 const DSNText = styled('div')`
   margin-bottom: ${space(0.5)};

+ 1 - 4
static/app/gettingStartedDocs/javascript/remix.tsx

@@ -4,19 +4,16 @@ import ListItem from 'sentry/components/list/listItem';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
 import {
   Docs,
-  DocsParams,
   OnboardingConfig,
 } from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-type Params = DocsParams;
-
 const onboarding: OnboardingConfig = {
   introduction: () =>
     tct("Sentry's integration with [remixLink:Remix] supports Remix 1.0.0 and above.", {
       remixLink: <ExternalLink href="https://remix.run/" />,
     }),
-  install: (_params: Params) => [
+  install: () => [
     {
       type: StepType.INSTALL,
       configurations: [

+ 34 - 12
static/app/gettingStartedDocs/javascript/sveltekit.spec.tsx

@@ -1,18 +1,40 @@
-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 {GettingStartedWithSvelteKit, steps} from './sveltekit';
+import docs from './sveltekit';
 
-describe('GettingStartedWithSvelteKit', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithSvelteKit dsn="test-dsn" projectSlug="test-project" />);
+describe('javascript-sveltekit onboarding docs', function () {
+  it('renders onboarding docs correctly', () => {
+    renderWithOnboardingLayout(docs);
 
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+
+    // Includes configure statement
+    expect(
+      screen.getByText(textWithMarkupMatcher(/npx @sentry\/wizard@latest -i sveltekit/))
+    ).toBeInTheDocument();
+  });
+
+  it('displays the configure instructions', () => {
+    renderWithOnboardingLayout(docs, {
+      selectedProducts: [
+        ProductSolution.ERROR_MONITORING,
+        ProductSolution.PERFORMANCE_MONITORING,
+        ProductSolution.SESSION_REPLAY,
+      ],
+    });
+
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/vite.config.js/))
+    ).toBeInTheDocument();
+    expect(
+      screen.queryByText(textWithMarkupMatcher(/src\/hooks.server.js/))
+    ).toBeInTheDocument();
+    expect(screen.queryByText(textWithMarkupMatcher(/.sentryclirc/))).toBeInTheDocument();
   });
 });

+ 84 - 73
static/app/gettingStartedDocs/javascript/sveltekit.tsx

@@ -3,82 +3,93 @@ import {Fragment} from 'react';
 import ExternalLink from 'sentry/components/links/externalLink';
 import List from 'sentry/components/list/';
 import ListItem from 'sentry/components/list/listItem';
-import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
-import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  Docs,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-export const steps = (): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Configure your app automatically with the [wizardLink:Sentry wizard].', {
-          wizardLink: (
-            <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/#install" />
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      configurations: [
+        {
+          description: tct(
+            'Configure your app automatically with the [wizardLink:Sentry wizard].',
+            {
+              wizardLink: (
+                <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/#install" />
+              ),
+            }
           ),
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: `npx @sentry/wizard@latest -i sveltekit`,
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: (
-      <Fragment>
-        {t(
-          'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
-        )}
-        <List symbol="bullet">
-          <ListItem>
-            {tct(
-              'Create or update [hookClientCode:src/hooks.client.js] and [hookServerCode:src/hooks.server.js] with the default [sentryInitCode:Sentry.init] call and SvelteKit hooks handlers.',
-              {
-                hookClientCode: <code />,
-                hookServerCode: <code />,
-                sentryInitCode: <code />,
-              }
-            )}
-          </ListItem>
-          <ListItem>
-            {tct(
-              'Update [code:vite.config.js] to add source maps upload and auto-instrumentation via Vite plugins.',
-              {
-                code: <code />,
-              }
-            )}
-          </ListItem>
-          <ListItem>
-            {tct(
-              'Create [sentryClircCode:.sentryclirc] and [sentryPropertiesCode:sentry.properties] files with configuration for sentry-cli (which is used when automatically uploading source maps).',
-              {
-                sentryClircCode: <code />,
-                sentryPropertiesCode: <code />,
-              }
-            )}
-          </ListItem>
-        </List>
-        <p>
-          {tct('Alternatively, you can also [manualSetupLink:set up the SDK manually].', {
-            manualSetupLink: (
-              <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/" />
-            ),
-          })}
-        </p>
-      </Fragment>
-    ),
-  },
-];
-
-// Configuration End
+          language: 'bash',
+          code: `npx @sentry/wizard@latest -i sveltekit`,
+        },
+      ],
+    },
+  ],
+  configure: () => [
+    {
+      type: StepType.CONFIGURE,
+      configurations: [
+        {
+          description: (
+            <Fragment>
+              {t(
+                'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
+              )}
+              <List symbol="bullet">
+                <ListItem>
+                  {tct(
+                    'Create or update [hookClientCode:src/hooks.client.js] and [hookServerCode:src/hooks.server.js] with the default [sentryInitCode:Sentry.init] call and SvelteKit hooks handlers.',
+                    {
+                      hookClientCode: <code />,
+                      hookServerCode: <code />,
+                      sentryInitCode: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {tct(
+                    'Update [code:vite.config.js] to add source maps upload and auto-instrumentation via Vite plugins.',
+                    {
+                      code: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {tct(
+                    'Create [sentryClircCode:.sentryclirc] and [sentryPropertiesCode:sentry.properties] files with configuration for sentry-cli (which is used when automatically uploading source maps).',
+                    {
+                      sentryClircCode: <code />,
+                      sentryPropertiesCode: <code />,
+                    }
+                  )}
+                </ListItem>
+              </List>
+              <p>
+                {tct(
+                  'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
+                  {
+                    manualSetupLink: (
+                      <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/" />
+                    ),
+                  }
+                )}
+              </p>
+            </Fragment>
+          ),
+        },
+      ],
+    },
+  ],
+  verify: () => [],
+};
 
-export function GettingStartedWithSvelteKit({...props}: ModuleProps) {
-  return <Layout steps={steps()} {...props} />;
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithSvelteKit;
+export default docs;