Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {textWithMarkupMatcher} from 'sentry-test/utils';

import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types';

import {VueVersion} from './utils';
import {docs} from '.';

describe('javascript-vue onboarding docs', () => {
Expand All @@ -24,6 +25,80 @@ describe('javascript-vue onboarding docs', () => {
).toBeInTheDocument();
});

it('initializes Vue 3 with the root component and existing router', () => {
renderWithOnboardingLayout(docs);

const setup = screen.getByText(textWithMarkupMatcher(/Sentry\.init\(/));
expect(setup).toHaveTextContent('import App from "./App.vue"');
expect(setup).toHaveTextContent('import router from "./router"');
expect(setup).toHaveTextContent('const app = createApp(App)');
expect(setup).toHaveTextContent('app.use(router)');
expect(setup).not.toHaveTextContent('createRouter');
});

it('keeps Vue 2 setup with its constructor and root component', () => {
renderWithOnboardingLayout(docs, {
selectedOptions: {siblingOption: VueVersion.VUE2},
});

const setup = screen.getByText(textWithMarkupMatcher(/Sentry\.init\(/));
expect(setup).toHaveTextContent('import Vue from "vue"');
expect(setup).toHaveTextContent('import App from "./App.vue"');
expect(setup).toHaveTextContent('Vue.use(Router)');
expect(setup).toHaveTextContent(/Sentry\.init\(\{\s*Vue,/);
expect(setup).toHaveTextContent('render: (h) => h(App)');
});

it.each([
{products: [ProductSolution.LOGS]},
{products: [ProductSolution.METRICS]},
{products: [ProductSolution.LOGS, ProductSolution.METRICS]},
])('verifies selected signals: $products', ({products}) => {
renderWithOnboardingLayout(docs, {
selectedProducts: [ProductSolution.ERROR_MONITORING, ...products],
});

const verify = screen.getByText(textWithMarkupMatcher(/throw new Error/));
expect(verify).toHaveTextContent('import * as Sentry from "@sentry/vue"');
expect(verify.textContent?.includes('Sentry.logger.info')).toBe(
products.includes(ProductSolution.LOGS)
);
expect(verify.textContent?.includes('Sentry.metrics.count')).toBe(
products.includes(ProductSolution.METRICS)
);

const setup = screen.getByText(textWithMarkupMatcher(/Sentry\.init\(/));
expect(setup).toHaveTextContent('dataCollection:');
expect(setup).not.toHaveTextContent(/sendDefaultPii|enableLogs|enableMetrics/);
});

it.each([VueVersion.VUE2, VueVersion.VUE3])(
'shows a clickable verification component for %s',
siblingOption => {
renderWithOnboardingLayout(docs, {
selectedOptions: {siblingOption},
selectedProducts: [ProductSolution.ERROR_MONITORING],
});

const verify = screen.getByText(textWithMarkupMatcher(/throw new Error/));
expect(verify).toHaveTextContent('<script>');
expect(verify).toHaveTextContent(/methods:\s*\{\s*triggerError\(\)/);
expect(verify).toHaveTextContent('<template>');
expect(verify).toHaveTextContent(
'<button type="button" @click="triggerError">Break the world</button>'
);
}
);

it('omits signal APIs and imports when only errors are selected', () => {
renderWithOnboardingLayout(docs, {
selectedProducts: [ProductSolution.ERROR_MONITORING],
});

const verify = screen.getByText(textWithMarkupMatcher(/throw new Error/));
expect(verify).not.toHaveTextContent(/import|Sentry\.logger|Sentry\.metrics/);
});

it('displays sample rates by default', () => {
renderWithOnboardingLayout(docs, {
selectedProducts: [
Expand Down
41 changes: 34 additions & 7 deletions static/app/gettingStartedDocs/javascript-vue/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,38 @@ import {
} from './utils';

const getVerifySnippet = (params: Params) => {
const sentryImport =
params.isLogsSelected || params.isMetricsSelected
? `import * as Sentry from "@sentry/vue";

`
: '';
const logsCode = params.isLogsSelected
? ` // Send a log before throwing the error
Sentry.logger.info('User triggered test error', {
action: 'test_error_button_click',
});
`
: '';
const metricsCode = params.isMetricsSelected
? ` // Send a test metric before calling undefined function
Sentry.metrics.count('test_counter', 1);
? ` // Send a test metric before throwing the error
Sentry.metrics.count('test_counter', 1);
`
: '';

return `${metricsCode}myUndefinedFunction();`;
return `<script>
${sentryImport}export default {
methods: {
triggerError() {
${logsCode}${metricsCode} throw new Error('Sentry Test Error');
},
},
};
</script>

<template>
<button type="button" @click="triggerError">Break the world</button>
</template>`;
};

export const onboarding: OnboardingConfig<PlatformOptions> = {
Expand Down Expand Up @@ -68,16 +93,18 @@ export const onboarding: OnboardingConfig<PlatformOptions> = {
content: [
{
type: 'text',
text: t(
"This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
text: tct(
'Add this button to a Vue component, such as [code:App.vue], then click "Break the world" to send a test error to Sentry. If you selected Logs or Metrics, clicking the button sends those too.',
{code: <code />}
),
},
{
type: 'code',
tabs: [
{
label: 'JavaScript',
language: 'javascript',
label: 'Vue',
language: 'html',
filename: 'App.vue',
code: getVerifySnippet(params),
},
],
Expand Down
11 changes: 5 additions & 6 deletions static/app/gettingStartedDocs/javascript-vue/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const getDynamicParts = (params: Params): string[] => {
if (params.isPerformanceSelected) {
dynamicParts.push(`
// Tracing
tracesSampleRate: 1.0, // Capture 100% of the transactions
tracesSampleRate: 1.0, // Capture 100% of the traces
// Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/]`);
}
Expand All @@ -92,13 +92,14 @@ function getSiblingImportsSetupConfiguration(siblingOption: string): string {
switch (siblingOption) {
case VueVersion.VUE3:
return `import {createApp} from "vue";
import {createRouter} from "vue-router";
import App from "./App.vue";
import router from "./router";
`;
case VueVersion.VUE2:
default:
return `import Vue from "vue";
import Router from "vue-router";`;
import Router from "vue-router";
import App from "./App.vue";`;
}
}

Expand All @@ -120,9 +121,7 @@ function getVueConstSetup(siblingOption: string): string {
switch (siblingOption) {
case VueVersion.VUE3:
return `
const app = createApp({
// ...
});
const app = createApp(App);
`;
case VueVersion.VUE2:
return `
Expand Down
Loading