Skip to content

Commit 5d045eb

Browse files
authored
fix(nextjs|sveltekit/v7): Ensure we can pass browserTracingIntegration (#11765)
Turns out the logic to get the options was not correct, because we used the `options` that the integration exposes, but this has `instrumentPageload: false` & `instrumentNavigation: false` because we did not "fix" the `options` we expose on the integration. This was not caught by the tests, because it only happens if passing the `browserTracingIntegration` from `@sentry/nextjs` or `@sentry/sveltekit`, not when passing the "original" one (which we had tests for). Really fixes #11627
1 parent cfaa9be commit 5d045eb

File tree

5 files changed

+156
-22
lines changed

5 files changed

+156
-22
lines changed

dev-packages/e2e-tests/test-applications/nextjs-14/sentry.client.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ Sentry.init({
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
88
sendDefaultPii: true,
9+
10+
// Ensure it also works with passing the integration
11+
integrations: [Sentry.browserTracingIntegration()],
912
});

packages/nextjs/src/client/browserTracingIntegration.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
startBrowserTracingNavigationSpan,
66
startBrowserTracingPageLoadSpan,
77
} from '@sentry/react';
8-
import type { Integration, StartSpanOptions } from '@sentry/types';
8+
import type { StartSpanOptions } from '@sentry/types';
99
import { nextRouterInstrumentation } from '../index.client';
1010

1111
/**
@@ -42,7 +42,7 @@ export class BrowserTracing extends OriginalBrowserTracing {
4242
*/
4343
export function browserTracingIntegration(
4444
options?: Parameters<typeof originalBrowserTracingIntegration>[0],
45-
): Integration {
45+
): ReturnType<typeof originalBrowserTracingIntegration> {
4646
const browserTracingIntegrationInstance = originalBrowserTracingIntegration({
4747
// eslint-disable-next-line deprecation/deprecation
4848
tracingOrigins:
@@ -61,8 +61,16 @@ export function browserTracingIntegration(
6161
instrumentPageLoad: false,
6262
});
6363

64+
const fullOptions = {
65+
...browserTracingIntegrationInstance.options,
66+
instrumentPageLoad: true,
67+
instrumentNavigation: true,
68+
...options,
69+
};
70+
6471
return {
6572
...browserTracingIntegrationInstance,
73+
options: fullOptions,
6674
afterAllSetup(client) {
6775
const startPageloadCallback = (startSpanOptions: StartSpanOptions): void => {
6876
startBrowserTracingPageLoadSpan(client, startSpanOptions);
@@ -80,7 +88,7 @@ export function browserTracingIntegration(
8088
nextRouterInstrumentation(
8189
() => undefined,
8290
false,
83-
options?.instrumentNavigation,
91+
fullOptions.instrumentNavigation,
8492
startPageloadCallback,
8593
startNavigationCallback,
8694
);
@@ -90,7 +98,7 @@ export function browserTracingIntegration(
9098
// eslint-disable-next-line deprecation/deprecation
9199
nextRouterInstrumentation(
92100
() => undefined,
93-
options?.instrumentPageLoad,
101+
fullOptions.instrumentPageLoad,
94102
false,
95103
startPageloadCallback,
96104
startNavigationCallback,

packages/nextjs/test/clientSdk.test.ts

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { BaseClient, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getActiveSpan, spanToJSON } from '@sentry/core';
1+
import {
2+
BaseClient,
3+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
4+
getActiveSpan,
5+
getIsolationScope,
6+
spanToJSON,
7+
} from '@sentry/core';
28
import * as SentryReact from '@sentry/react';
39
import type { BrowserClient } from '@sentry/react';
410
import { browserTracingIntegration } from '@sentry/react';
@@ -7,7 +13,13 @@ import type { Integration } from '@sentry/types';
713
import { logger } from '@sentry/utils';
814
import { JSDOM } from 'jsdom';
915

10-
import { BrowserTracing, breadcrumbsIntegration, init, nextRouterInstrumentation } from '../src/client';
16+
import {
17+
BrowserTracing,
18+
breadcrumbsIntegration,
19+
browserTracingIntegration as nextjsBrowserTracingIntegration,
20+
init,
21+
nextRouterInstrumentation,
22+
} from '../src/client';
1123

1224
const reactInit = jest.spyOn(SentryReact, 'init');
1325
const captureEvent = jest.spyOn(BaseClient.prototype, 'captureEvent');
@@ -35,6 +47,11 @@ function findIntegrationByName(integrations: Integration[] = [], name: string):
3547
const TEST_DSN = 'https://[email protected]/1337';
3648

3749
describe('Client init()', () => {
50+
beforeEach(() => {
51+
getCurrentScope().clear();
52+
getIsolationScope().clear();
53+
});
54+
3855
afterEach(() => {
3956
jest.clearAllMocks();
4057
WINDOW.__SENTRY__.hub = undefined;
@@ -141,9 +158,16 @@ describe('Client init()', () => {
141158
});
142159

143160
it('forces correct router instrumentation if user provides `browserTracingIntegration`', () => {
161+
const beforeStartSpan = jest.fn(options => options);
144162
init({
145163
dsn: TEST_DSN,
146-
integrations: [browserTracingIntegration({ finalTimeout: 10 })],
164+
integrations: [
165+
browserTracingIntegration({
166+
finalTimeout: 10,
167+
instrumentNavigation: false,
168+
beforeStartSpan,
169+
}),
170+
],
147171
enableTracing: true,
148172
});
149173

@@ -156,14 +180,58 @@ describe('Client init()', () => {
156180
// It is a "new" browser tracing integration
157181
expect(typeof integration?.afterAllSetup).toBe('function');
158182

183+
// the hooks is correctly invoked
184+
expect(beforeStartSpan).toHaveBeenCalledTimes(1);
185+
expect(beforeStartSpan).toHaveBeenCalledWith(
186+
expect.objectContaining({
187+
name: '/',
188+
op: 'pageload',
189+
}),
190+
);
191+
192+
// it correctly starts the page load span
193+
expect(getActiveSpan()).toBeDefined();
194+
expect(spanToJSON(getActiveSpan()!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toEqual(
195+
'auto.pageload.nextjs.app_router_instrumentation',
196+
);
197+
159198
// This shows that the user-configured options are still here
160-
expect(integration?.options?.finalTimeout).toEqual(10);
199+
expect(integration?.options.finalTimeout).toEqual(10);
200+
expect(integration?.options.instrumentNavigation).toBe(false);
201+
expect(integration?.options.instrumentPageLoad).toBe(true);
202+
});
161203

162-
// it is the svelte kit variety
204+
it('forces correct router instrumentation if user provides Next.js `browserTracingIntegration` ', () => {
205+
init({
206+
dsn: TEST_DSN,
207+
integrations: [
208+
nextjsBrowserTracingIntegration({
209+
finalTimeout: 10,
210+
instrumentNavigation: false,
211+
}),
212+
],
213+
enableTracing: true,
214+
});
215+
216+
const client = getClient<BrowserClient>()!;
217+
// eslint-disable-next-line deprecation/deprecation
218+
const integration = client.getIntegrationByName<ReturnType<typeof browserTracingIntegration>>('BrowserTracing');
219+
220+
expect(integration).toBeDefined();
221+
222+
// It is a "new" browser tracing integration
223+
expect(typeof integration?.afterAllSetup).toBe('function');
224+
225+
// it correctly starts the pageload span
163226
expect(getActiveSpan()).toBeDefined();
164227
expect(spanToJSON(getActiveSpan()!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toEqual(
165228
'auto.pageload.nextjs.app_router_instrumentation',
166229
);
230+
231+
// This shows that the user-configured options are still here
232+
expect(integration?.options.finalTimeout).toEqual(10);
233+
expect(integration?.options.instrumentNavigation).toBe(false);
234+
expect(integration?.options.instrumentPageLoad).toBe(true);
167235
});
168236

169237
it('forces correct router instrumentation if user provides `BrowserTracing` in a function', () => {
@@ -187,10 +255,10 @@ describe('Client init()', () => {
187255

188256
expect(browserTracingIntegration?.options).toEqual(
189257
expect.objectContaining({
258+
startTransactionOnPageLoad: true,
259+
startTransactionOnLocationChange: false,
190260
// eslint-disable-next-line deprecation/deprecation
191261
routingInstrumentation: nextRouterInstrumentation,
192-
// This proves it's still the user's copy
193-
startTransactionOnLocationChange: false,
194262
}),
195263
);
196264
});

packages/sveltekit/src/client/browserTracingIntegration.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
startBrowserTracingPageLoadSpan,
1010
startInactiveSpan,
1111
} from '@sentry/svelte';
12-
import type { Client, Integration, Span } from '@sentry/types';
12+
import type { Client, Span } from '@sentry/types';
1313
import { svelteKitRoutingInstrumentation } from './router';
1414

1515
/**
@@ -36,7 +36,7 @@ export class BrowserTracing extends OriginalBrowserTracing {
3636
*/
3737
export function browserTracingIntegration(
3838
options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},
39-
): Integration {
39+
): ReturnType<typeof originalBrowserTracingIntegration> {
4040
const integration = {
4141
...originalBrowserTracingIntegration({
4242
...options,
@@ -45,16 +45,24 @@ export function browserTracingIntegration(
4545
}),
4646
};
4747

48+
const fullOptions = {
49+
...integration.options,
50+
instrumentPageLoad: true,
51+
instrumentNavigation: true,
52+
...options,
53+
};
54+
4855
return {
4956
...integration,
57+
options: fullOptions,
5058
afterAllSetup: client => {
5159
integration.afterAllSetup(client);
5260

53-
if (options.instrumentPageLoad !== false) {
61+
if (fullOptions.instrumentPageLoad) {
5462
_instrumentPageload(client);
5563
}
5664

57-
if (options.instrumentNavigation !== false) {
65+
if (fullOptions.instrumentNavigation) {
5866
_instrumentNavigations(client);
5967
}
6068
},

packages/sveltekit/test/client/sdk.test.ts

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getActiveSpan, getClient, getCurrentScope, spanToJSON } from '@sentry/core';
1+
import {
2+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
3+
getActiveSpan,
4+
getClient,
5+
getCurrentScope,
6+
getIsolationScope,
7+
spanToJSON,
8+
} from '@sentry/core';
29
import type { BrowserClient } from '@sentry/svelte';
310
import * as SentrySvelte from '@sentry/svelte';
411
import { SDK_VERSION, WINDOW, browserTracingIntegration } from '@sentry/svelte';
512
import { vi } from 'vitest';
613

7-
import { BrowserTracing, init } from '../../src/client';
14+
import {
15+
BrowserTracing,
16+
browserTracingIntegration as sveltekitBrowserTracingIntegration,
17+
init,
18+
} from '../../src/client';
819
import { svelteKitRoutingInstrumentation } from '../../src/client/router';
920

1021
const svelteInit = vi.spyOn(SentrySvelte, 'init');
@@ -16,6 +27,11 @@ describe('Sentry client SDK', () => {
1627
WINDOW.__SENTRY__.hub = undefined;
1728
});
1829

30+
beforeEach(() => {
31+
getCurrentScope().clear();
32+
getIsolationScope().clear();
33+
});
34+
1935
it('adds SvelteKit metadata to the SDK options', () => {
2036
expect(svelteInit).not.toHaveBeenCalled();
2137

@@ -99,7 +115,7 @@ describe('Sentry client SDK', () => {
99115
init({
100116
dsn: 'https://[email protected]/1337',
101117
// eslint-disable-next-line deprecation/deprecation
102-
integrations: [new BrowserTracing({ finalTimeout: 10 })],
118+
integrations: [new BrowserTracing({ finalTimeout: 10, startTransactionOnLocationChange: false })],
103119
enableTracing: true,
104120
});
105121

@@ -118,34 +134,65 @@ describe('Sentry client SDK', () => {
118134
// But we force the routing instrumentation to be ours
119135
// eslint-disable-next-line deprecation/deprecation
120136
expect(options.routingInstrumentation).toEqual(svelteKitRoutingInstrumentation);
137+
expect(options.startTransactionOnPageLoad).toEqual(true);
138+
expect(options.startTransactionOnLocationChange).toEqual(false);
121139
});
122140

123141
it('Merges a user-provided browserTracingIntegration with the automatically added one', () => {
124142
init({
125143
dsn: 'https://[email protected]/1337',
126-
integrations: [browserTracingIntegration({ finalTimeout: 10 })],
144+
integrations: [browserTracingIntegration({ finalTimeout: 10, instrumentNavigation: false })],
127145
enableTracing: true,
128146
});
129147

130148
const browserTracing =
131149
getClient<BrowserClient>()?.getIntegrationByName<ReturnType<typeof browserTracingIntegration>>(
132150
'BrowserTracing',
133151
);
134-
const options = browserTracing?.options;
135152

136153
expect(browserTracing).toBeDefined();
137154

138155
// It is a "new" browser tracing integration
139156
expect(typeof browserTracing?.afterAllSetup).toBe('function');
140157

158+
// it is the svelte kit variety
159+
expect(getActiveSpan()).toBeDefined();
160+
expect(spanToJSON(getActiveSpan()!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toEqual(
161+
'auto.pageload.sveltekit',
162+
);
163+
141164
// This shows that the user-configured options are still here
142-
expect(options?.finalTimeout).toEqual(10);
165+
expect(browserTracing?.options.finalTimeout).toEqual(10);
166+
expect(browserTracing?.options.instrumentPageLoad).toEqual(true);
167+
expect(browserTracing?.options.instrumentNavigation).toEqual(false);
168+
});
143169

144-
// it is the svelte kit variety
170+
it('forces correct router instrumentation if user provides Sveltekit `browserTracingIntegration` ', () => {
171+
init({
172+
dsn: 'https://[email protected]/1337',
173+
integrations: [sveltekitBrowserTracingIntegration({ finalTimeout: 10, instrumentNavigation: false })],
174+
enableTracing: true,
175+
});
176+
177+
const client = getClient<BrowserClient>()!;
178+
// eslint-disable-next-line deprecation/deprecation
179+
const integration = client.getIntegrationByName<ReturnType<typeof browserTracingIntegration>>('BrowserTracing');
180+
181+
expect(integration).toBeDefined();
182+
183+
// It is a "new" browser tracing integration
184+
expect(typeof integration?.afterAllSetup).toBe('function');
185+
186+
// it correctly starts the pageload span
145187
expect(getActiveSpan()).toBeDefined();
146188
expect(spanToJSON(getActiveSpan()!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toEqual(
147189
'auto.pageload.sveltekit',
148190
);
191+
192+
// This shows that the user-configured options are still here
193+
expect(integration?.options.finalTimeout).toEqual(10);
194+
expect(integration?.options.instrumentNavigation).toBe(false);
195+
expect(integration?.options.instrumentPageLoad).toBe(true);
149196
});
150197
});
151198
});

0 commit comments

Comments
 (0)