Skip to content
Merged
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 @@ -3,7 +3,6 @@ import * as Sentry from '@sentry/sveltekit';
import * as Spotlight from '@spotlightjs/spotlight';

Sentry.init({
traceLifecycle: 'static',
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: env.PUBLIC_E2E_TEST_DSN,
debug: !!env.PUBLIC_DEBUG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/sveltekit';
import { E2E_TEST_DSN } from '$env/static/private';

Sentry.init({
traceLifecycle: 'static',
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: E2E_TEST_DSN,
debug: !!process.env.DEBUG,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,129 +1,81 @@
import { expect, test } from '@playwright/test';
import { waitForTransaction } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import { waitForInitialPageload } from './utils';

test.describe('client-specific performance events', () => {
test('multiple navigations have distinct traces', async ({ page }) => {
const navigationTxn1EventPromise = waitForTransaction('sveltekit-2-kit-tracing', txnEvent => {
return txnEvent?.transaction === '/nav1' && txnEvent.contexts?.trace?.op === 'navigation';
const navigationSpan1Promise = waitForStreamedSpan('sveltekit-2-kit-tracing', span => {
return span.name === '/nav1' && getSpanOp(span) === 'navigation' && span.is_segment;
});

const navigationTxn2EventPromise = waitForTransaction('sveltekit-2-kit-tracing', txnEvent => {
return txnEvent?.transaction === '/' && txnEvent.contexts?.trace?.op === 'navigation';
const navigationSpan2Promise = waitForStreamedSpan('sveltekit-2-kit-tracing', span => {
return span.name === '/' && getSpanOp(span) === 'navigation' && span.is_segment;
});

const navigationTxn3EventPromise = waitForTransaction('sveltekit-2-kit-tracing', txnEvent => {
return txnEvent?.transaction === '/nav2' && txnEvent.contexts?.trace?.op === 'navigation';
const navigationSpan3Promise = waitForStreamedSpan('sveltekit-2-kit-tracing', span => {
return span.name === '/nav2' && getSpanOp(span) === 'navigation' && span.is_segment;
});

await waitForInitialPageload(page);

await page.getByText('Nav 1').click();
const navigationTxn1Event = await navigationTxn1EventPromise;
const navigationSpan1 = await navigationSpan1Promise;

await page.goBack();
const navigationTxn2Event = await navigationTxn2EventPromise;
const navigationSpan2 = await navigationSpan2Promise;

await page.getByText('Nav 2').click();
const navigationTxn3Event = await navigationTxn3EventPromise;

expect(navigationTxn1Event).toMatchObject({
transaction: '/nav1',
transaction_info: { source: 'route' },
type: 'transaction',
contexts: {
trace: {
op: 'navigation',
origin: 'auto.navigation.sveltekit',
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
data: {
'url.path': '/nav1',
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/nav1$/),
'url.template': '/nav1',
},
const navigationSpan3 = await navigationSpan3Promise;

const expectNavigationSpan = (span: typeof navigationSpan1, route: string) => {
expect(span.trace_id).toMatch(/[a-f0-9]{32}/);
expect(span.attributes).toMatchObject({
'sentry.op': { value: 'navigation', type: 'string' },
'sentry.origin': { value: 'auto.navigation.sveltekit', type: 'string' },
'sentry.segment.name.source': { value: 'route', type: 'string' },
'url.path': { value: route, type: 'string' },
'url.full': {
value: expect.stringMatching(new RegExp(`^https?:\\/\\/localhost:\\d+${route}$`)),
type: 'string',
},
},
});
'url.template': { value: route, type: 'string' },
});
};

expect(navigationTxn2Event).toMatchObject({
transaction: '/',
transaction_info: { source: 'route' },
type: 'transaction',
contexts: {
trace: {
op: 'navigation',
origin: 'auto.navigation.sveltekit',
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
data: {
'url.path': '/',
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
'url.template': '/',
},
},
},
});

expect(navigationTxn3Event).toMatchObject({
transaction: '/nav2',
transaction_info: { source: 'route' },
type: 'transaction',
contexts: {
trace: {
op: 'navigation',
origin: 'auto.navigation.sveltekit',
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
data: {
'url.path': '/nav2',
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/nav2$/),
'url.template': '/nav2',
},
},
},
});
expectNavigationSpan(navigationSpan1, '/nav1');
expectNavigationSpan(navigationSpan2, '/');
expectNavigationSpan(navigationSpan3, '/nav2');

// traces should NOT be connected
expect(navigationTxn1Event.contexts?.trace?.trace_id).not.toBe(navigationTxn2Event.contexts?.trace?.trace_id);
expect(navigationTxn2Event.contexts?.trace?.trace_id).not.toBe(navigationTxn3Event.contexts?.trace?.trace_id);
expect(navigationTxn1Event.contexts?.trace?.trace_id).not.toBe(navigationTxn3Event.contexts?.trace?.trace_id);
expect(navigationSpan1.trace_id).not.toBe(navigationSpan2.trace_id);
expect(navigationSpan2.trace_id).not.toBe(navigationSpan3.trace_id);
expect(navigationSpan1.trace_id).not.toBe(navigationSpan3.trace_id);
});

test('records manually added component tracking spans', async ({ page }) => {
const componentTxnEventPromise = waitForTransaction('sveltekit-2-kit-tracing', txnEvent => {
return txnEvent?.transaction === '/components';
});
const componentTraceSpansPromise = collectStreamedSpansUntilSegment('sveltekit-2-kit-tracing', '/components');

await waitForInitialPageload(page);

await page.getByText('Component Tracking').click();

const componentTxnEvent = await componentTxnEventPromise;
const componentTraceSpans = await componentTraceSpansPromise;

expect(componentTxnEvent.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({
data: { 'sentry.op': 'ui.mount', 'sentry.origin': 'auto.ui.svelte' },
description: '<components/+page>',
op: 'ui.mount',
origin: 'auto.ui.svelte',
}),
expect.objectContaining({
data: { 'sentry.op': 'ui.mount', 'sentry.origin': 'auto.ui.svelte' },
description: '<Component1>',
op: 'ui.mount',
origin: 'auto.ui.svelte',
}),
expect.objectContaining({
data: { 'sentry.op': 'ui.mount', 'sentry.origin': 'auto.ui.svelte' },
description: '<Component2>',
op: 'ui.mount',
origin: 'auto.ui.svelte',
}),
expect.objectContaining({
data: { 'sentry.op': 'ui.mount', 'sentry.origin': 'auto.ui.svelte' },
description: '<Component3>',
op: 'ui.mount',
origin: 'auto.ui.svelte',
const componentSpan = (name: string) =>
expect.objectContaining({
name,
attributes: expect.objectContaining({
'sentry.op': { value: 'ui.mount', type: 'string' },
'sentry.origin': { value: 'auto.ui.svelte', type: 'string' },
}),
});

expect(componentTraceSpans).toEqual(
expect.arrayContaining([
componentSpan('<components/+page>'),
componentSpan('<Component1>'),
componentSpan('<Component2>'),
componentSpan('<Component3>'),
]),
);
});
Expand Down
Loading
Loading