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

ref(onboarding docs): convert svelte, javascript, ember (#61293)

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

+ 68 - 38
static/app/gettingStartedDocs/javascript/ember.spec.tsx

@@ -1,43 +1,73 @@
-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 {GettingStartedWithEmber, nextSteps, steps} from './ember';
-
-describe('GettingStartedWithEmber', function () {
-  it('all products are selected', function () {
-    render(
-      <GettingStartedWithEmber
-        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 './ember';
+
+describe('javascript-ember 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\/ember"/))
+    ).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();
   });
 });

+ 139 - 169
static/app/gettingStartedDocs/javascript/ember.tsx

@@ -1,181 +1,151 @@
-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(),
-`;
+type Params = DocsParams;
+
+const getSdkSetupSnippet = (params: Params) => `
+import Application from "@ember/application";
+import Resolver from "ember-resolver";
+import loadInitializers from "ember-load-initializers";
+import config from "./config/environment";
+
+import * as Sentry from "@sentry/ember";
+
+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 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.
+export default class App extends Application {
+  modulePrefix = config.modulePrefix;
+  podModulePrefix = config.podModulePrefix;
+  Resolver = Resolver;
+}
 `;
 
-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: t(
-      'Sentry captures data by using an SDK within your application’s runtime.'
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: `
+const getVerifyEmberSnippet = () => `
+myUndefinedFunction();`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      description: t(
+        'Sentry captures data by using an SDK within your application’s runtime.'
+      ),
+      configurations: [
+        {
+          language: 'bash',
+          code: `
 # Using ember-cli
 ember install @sentry/ember
-        `,
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: (
-      <p>
-        {tct(
-          'You should [initCode:init] the Sentry SDK as soon as possible during your application load up in [appCode:app.js], before initializing Ember:',
-          {
-            initCode: <code />,
-            appCode: <code />,
-          }
-        )}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'javascript',
-        code: `
-        import Application from "@ember/application";
-        import Resolver from "ember-resolver";
-        import loadInitializers from "ember-load-initializers";
-        import config from "./config/environment";
-
-        import * as Sentry from "@sentry/ember";
-
-        Sentry.init({
-          ${sentryInitContent}
-        });
-
-        export default class App extends Application {
-          modulePrefix = config.modulePrefix;
-          podModulePrefix = config.podModulePrefix;
-          Resolver = Resolver;
+          `,
+        },
+      ],
+    },
+  ],
+  configure: (params: Params) => [
+    {
+      type: StepType.CONFIGURE,
+      description: tct(
+        'You should [initCode:init] the Sentry SDK as soon as possible during your application load up in [appCode:app.js], before initializing Ember:',
+        {
+          initCode: <code />,
+          appCode: <code />,
         }
-        `,
-      },
-    ],
-  },
-  getUploadSourceMapsStep({
-    guideLink: 'https://docs.sentry.io/platforms/javascript/guides/ember/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/ember/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/ember/session-replay/',
-  },
-];
-// Configuration End
-
-export function GettingStartedWithEmber({
-  dsn,
-  activeProductSelection = [],
-  organization,
-  newOrg,
-  platformKey,
-  projectId,
-  ...props
-}: ModuleProps) {
-  const integrations: string[] = [];
-  const otherConfigs: string[] = [];
-
-  let nextStepDocs = [...nextSteps];
-
-  if (activeProductSelection.includes(ProductSolution.PERFORMANCE_MONITORING)) {
-    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);
-  }
+      ),
+      configurations: [
+        {
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: getSdkSetupSnippet(params),
+            },
+          ],
+        },
+      ],
+    },
+    getUploadSourceMapsStep({
+      guideLink: 'https://docs.sentry.io/platforms/javascript/guides/ember/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: getVerifyEmberSnippet(),
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  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/ember/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/ember/session-replay/',
+    },
+  ],
+};
 
-  return (
-    <Layout
-      steps={steps({
-        sentryInitContent: sentryInitContent.join('\n'),
-        organization,
-        newOrg,
-        platformKey,
-        projectId,
-      })}
-      nextSteps={nextStepDocs}
-      newOrg={newOrg}
-      platformKey={platformKey}
-      {...props}
-    />
-  );
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithEmber;
+export default docs;

+ 70 - 38
static/app/gettingStartedDocs/javascript/javascript.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 GettingStartedWithJavaScript, {nextSteps, steps} from './javascript';
-
-describe('GettingStartedWithJavaScript', function () {
-  it('all products are selected', function () {
-    render(
-      <GettingStartedWithJavaScript
-        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 './javascript';
+
+describe('javascript 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\/browser"/)
+      )
+    ).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();
   });
 });

+ 138 - 172
static/app/gettingStartedDocs/javascript/javascript.tsx

@@ -1,180 +1,146 @@
-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} 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.
-`;
-
-const performanceIntegration = `
-new Sentry.BrowserTracing({
-  // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
-  tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/],
-}),
-`;
-
-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: t(
-      'Sentry captures data by using an SDK within your application’s runtime.'
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: [
-          {
-            label: 'npm',
-            value: 'npm',
-            language: 'bash',
-            code: 'npm install --save @sentry/browser',
-          },
-          {
-            label: 'yarn',
-            value: 'yarn',
-            language: 'bash',
-            code: 'yarn add @sentry/browser',
-          },
-        ],
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: t(
-      "Initialize Sentry as early as possible in your application's lifecycle."
-    ),
-    configurations: [
-      {
-        language: 'javascript',
-        code: `
-        import * as Sentry from "@sentry/browser";
-
-        Sentry.init({
-          ${sentryInitContent}
-        });
-        `,
-      },
-    ],
-  },
-  getUploadSourceMapsStep({
-    guideLink: 'https://docs.sentry.io/platforms/javascript/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/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/session-replay/',
-  },
-];
-// Configuration End
-
-export function GettingStartedWithJavaScript({
-  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, '],');
+type Params = DocsParams;
+
+const getSdkSetupSnippet = (params: Params) => `
+import * as Sentry from "@sentry/browser";
+
+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.`
+    : ''
+}
+});
+`;
 
-  if (otherConfigs.length > 0) {
-    sentryInitContent = sentryInitContent.concat(otherConfigs);
-  }
+const getVerifyJSSnippet = () => `
+myUndefinedFunction();`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      configurations: [
+        {
+          description: t(
+            'Sentry captures data by using an SDK within your application’s runtime.'
+          ),
+          language: 'bash',
+          code: [
+            {
+              label: 'npm',
+              value: 'npm',
+              language: 'bash',
+              code: 'npm install --save @sentry/browser',
+            },
+            {
+              label: 'yarn',
+              value: 'yarn',
+              language: 'bash',
+              code: 'yarn add @sentry/browser',
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  configure: (params: Params) => [
+    {
+      type: StepType.CONFIGURE,
+      description: t(
+        "Initialize Sentry as early as possible in your application's lifecycle."
+      ),
+      configurations: [
+        {
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: getSdkSetupSnippet(params),
+            },
+          ],
+        },
+      ],
+    },
+    getUploadSourceMapsStep({
+      guideLink: 'https://docs.sentry.io/platforms/javascript/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: getVerifyJSSnippet(),
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  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/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/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 GettingStartedWithJavaScript;
+export default docs;

+ 3 - 3
static/app/gettingStartedDocs/javascript/react.spec.tsx

@@ -51,7 +51,7 @@ describe('javascript-react onboarding docs', function () {
     });
 
     expect(
-      screen.getByText(textWithMarkupMatcher(/tracesSampleRate: 1.0/))
+      screen.getByText(textWithMarkupMatcher(/tracesSampleRate: 1\.0/))
     ).toBeInTheDocument();
   });
 
@@ -64,10 +64,10 @@ describe('javascript-react onboarding docs', function () {
     });
 
     expect(
-      screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate: 0.1/))
+      screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate: 0\.1/))
     ).toBeInTheDocument();
     expect(
-      screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate: 1.0/))
+      screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate: 1\.0/))
     ).toBeInTheDocument();
   });
 });

+ 0 - 1
static/app/gettingStartedDocs/javascript/react.tsx

@@ -55,7 +55,6 @@ return <button onClick={() => methodDoesNotExist()}>Break the world</button>;
         `;
 
 const onboarding: OnboardingConfig = {
-  introduction: () => [],
   install: () => [
     {
       type: StepType.INSTALL,

+ 70 - 38
static/app/gettingStartedDocs/javascript/svelte.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 {GettingStartedWithSvelte, nextSteps, steps} from './svelte';
-
-describe('GettingStartedWithSvelte', function () {
-  it('all products are selected', function () {
-    render(
-      <GettingStartedWithSvelte
-        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 './svelte';
+
+describe('javascript-svelte 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\/svelte"/)
+      )
+    ).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();
   });
 });

+ 159 - 201
static/app/gettingStartedDocs/javascript/svelte.tsx

@@ -1,211 +1,169 @@
-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.
-`;
-
-const performanceIntegration = `
-new Sentry.BrowserTracing({
-  // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
-  tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/],
-}),
-`;
-
-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/svelte',
-          },
-          {
-            label: 'yarn',
-            value: 'yarn',
-            language: 'bash',
-            code: 'yarn add @sentry/svelte',
-          },
-        ],
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: (
-      <p>
-        {tct(
-          "Initialize Sentry as early as possible in your application's lifecycle, usually your Svelte app's entry point ([code:main.ts/js]):",
-          {code: <code />}
-        )}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'javascript',
-        code: `
-        import "./app.css";
-        import App from "./App.svelte";
-
-        import * as Sentry from "@sentry/svelte";
-
-        Sentry.init({
-          ${sentryInitContent}
-        });
-
-        const app = new App({
-          target: document.getElementById("app"),
-        });
-
-        export default app;
-        `,
-      },
-    ],
-  },
-  getUploadSourceMapsStep({
-    guideLink: 'https://docs.sentry.io/platforms/javascript/guides/svelte/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: `
-        // SomeComponent.svelte
-        <button type="button" on:click="{unknownFunction}">Break the world</button>
-        `,
-      },
-    ],
-  },
-];
-
-export const nextSteps = [
-  {
-    id: 'svelte-features',
-    name: t('Svelte Features'),
-    description: t('Learn about our first class integration with the Svelte framework.'),
-    link: 'https://docs.sentry.io/platforms/javascript/guides/svelte/features/',
-  },
-  {
-    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/svelte/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/svelte/session-replay/',
-  },
-];
-// Configuration End
-
-export function GettingStartedWithSvelte({
-  dsn,
-  activeProductSelection = [],
-  platformKey,
-  projectId,
-  organization,
-  newOrg,
-  ...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
-    );
+type Params = DocsParams;
+
+const getSdkSetupSnippet = (params: Params) => `
+import "./app.css";
+import App from "./App.svelte";
+
+import * as Sentry from "@sentry/svelte";
+
+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.`
+    : ''
+}
+});
 
-  let sentryInitContent: string[] = [`dsn: "${dsn}",`];
+const app = new App({
+  target: document.getElementById("app"),
+});
 
-  if (integrations.length > 0) {
-    sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],');
-  }
+export default app;
+`;
 
-  if (otherConfigs.length > 0) {
-    sentryInitContent = sentryInitContent.concat(otherConfigs);
-  }
+const getVerifySvelteSnippet = () => `
+// SomeComponent.svelte
+<button type="button" on:click="{unknownFunction}">Break the world</button>`;
+
+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: [
+            {
+              label: 'npm',
+              value: 'npm',
+              language: 'bash',
+              code: 'npm install --save @sentry/svelte',
+            },
+            {
+              label: 'yarn',
+              value: 'yarn',
+              language: 'bash',
+              code: 'yarn add @sentry/svelte',
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  configure: (params: Params) => [
+    {
+      type: StepType.CONFIGURE,
+      description: tct(
+        "Initialize Sentry as early as possible in your application's lifecycle, usually your Svelte app's entry point ([code:main.ts/js]):",
+        {code: <code />}
+      ),
+      configurations: [
+        {
+          code: [
+            {
+              label: 'JavaScript',
+              value: 'javascript',
+              language: 'javascript',
+              code: getSdkSetupSnippet(params),
+            },
+          ],
+        },
+      ],
+    },
+    getUploadSourceMapsStep({
+      guideLink: 'https://docs.sentry.io/platforms/javascript/guides/svelte/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: getVerifySvelteSnippet(),
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  nextSteps: () => [
+    {
+      id: 'svelte-features',
+      name: t('Svelte Features'),
+      description: t(
+        'Learn about our first class integration with the Svelte framework.'
+      ),
+      link: 'https://docs.sentry.io/platforms/javascript/guides/svelte/features/',
+    },
+    {
+      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/svelte/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/svelte/session-replay/',
+    },
+  ],
+};
 
-  return (
-    <Layout
-      steps={steps({
-        sentryInitContent: sentryInitContent.join('\n'),
-        organization,
-        newOrg,
-        platformKey,
-        projectId,
-      })}
-      nextSteps={nextStepDocs}
-      newOrg={newOrg}
-      platformKey={platformKey}
-      {...props}
-    />
-  );
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithSvelte;
+export default docs;