Skip to content

Commit 84d05f4

Browse files
committed
test: Write tests for auto client perf
1 parent 15a2aa2 commit 84d05f4

File tree

4 files changed

+119
-10
lines changed

4 files changed

+119
-10
lines changed

packages/nextjs/src/index.client.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,43 @@ import { Integrations } from '@sentry/tracing';
44
import { nextRouterInstrumentation } from './performance/client';
55
import { MetadataBuilder } from './utils/metadataBuilder';
66
import { NextjsOptions } from './utils/nextjsOptions';
7-
import { addIntegration } from './utils/userIntegrations';
7+
import { addIntegration, UserIntegrations } from './utils/userIntegrations';
88

99
export * from '@sentry/react';
1010
export { nextRouterInstrumentation } from './performance/client';
1111

12+
const { BrowserTracing } = Integrations;
13+
1214
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
1315
export function init(options: NextjsOptions): void {
1416
const metadataBuilder = new MetadataBuilder(options, ['nextjs', 'react']);
1517
metadataBuilder.addSdkMetadata();
1618
options.environment = options.environment || process.env.NODE_ENV;
17-
addClientIntegrations(options);
18-
reactInit(options);
19+
reactInit({
20+
...options,
21+
integrations: createClientIntegrations(options.integrations),
22+
});
1923
configureScope(scope => {
2024
scope.setTag('runtime', 'browser');
2125
});
2226
}
2327

24-
const defaultBrowserTracingIntegration = new Integrations.BrowserTracing({
28+
const defaultBrowserTracingIntegration = new BrowserTracing({
2529
routingInstrumentation: nextRouterInstrumentation,
2630
});
2731

28-
function addClientIntegrations(options: NextjsOptions): void {
29-
if (options.integrations) {
30-
addIntegration(defaultBrowserTracingIntegration, options.integrations);
32+
function createClientIntegrations(integrations?: UserIntegrations): UserIntegrations {
33+
if (integrations) {
34+
const newIntegrations = addIntegration(defaultBrowserTracingIntegration, integrations);
35+
if (Array.isArray(newIntegrations)) {
36+
newIntegrations.forEach(i => {
37+
if (i.name === 'BrowserTracing') {
38+
(i as InstanceType<typeof BrowserTracing>).options.routingInstrumentation = nextRouterInstrumentation;
39+
}
40+
});
41+
}
42+
return newIntegrations;
3143
} else {
32-
options.integrations = [defaultBrowserTracingIntegration];
44+
return [defaultBrowserTracingIntegration];
3345
}
3446
}

packages/nextjs/src/utils/userIntegrations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Integration } from '@sentry/types';
22

33
export type UserFunctionIntegrations = (integrations: Integration[]) => Integration[];
4-
type UserIntegrations = Integration[] | UserFunctionIntegrations;
4+
export type UserIntegrations = Integration[] | UserFunctionIntegrations;
55

66
/**
77
* Retrieves the patched integrations with the provided integration.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { Integrations as TracingIntegrations } from '@sentry/tracing';
2+
import { Integration } from '@sentry/types';
3+
4+
import { init, Integrations, nextRouterInstrumentation, Scope } from '../src/index.client';
5+
import { NextjsOptions } from '../src/utils/nextjsOptions';
6+
7+
const { BrowserTracing } = TracingIntegrations;
8+
9+
const mockInit = jest.fn();
10+
let configureScopeCallback: (scope: Scope) => void = () => undefined;
11+
12+
jest.mock('@sentry/react', () => {
13+
const actual = jest.requireActual('@sentry/react');
14+
return {
15+
...actual,
16+
init: (options: NextjsOptions) => {
17+
mockInit(options);
18+
},
19+
configureScope: (callback: (scope: Scope) => void) => {
20+
configureScopeCallback = callback;
21+
},
22+
};
23+
});
24+
25+
describe('Client init()', () => {
26+
afterEach(() => {
27+
mockInit.mockClear();
28+
configureScopeCallback = () => undefined;
29+
});
30+
31+
it('inits the React SDK', () => {
32+
expect(mockInit).toHaveBeenCalledTimes(0);
33+
init({});
34+
expect(mockInit).toHaveBeenCalledTimes(1);
35+
expect(mockInit).toHaveBeenLastCalledWith({
36+
_metadata: {
37+
sdk: {
38+
name: 'sentry.javascript.nextjs',
39+
version: expect.any(String),
40+
packages: expect.any(Array),
41+
},
42+
},
43+
environment: 'test',
44+
integrations: expect.any(Array),
45+
});
46+
});
47+
48+
it('sets runtime on scope', () => {
49+
const mockScope = new Scope();
50+
init({});
51+
configureScopeCallback(mockScope);
52+
// @ts-ignore need access to protected _tags attribute
53+
expect(mockScope._tags).toEqual({ runtime: 'browser' });
54+
});
55+
56+
describe('integrations', () => {
57+
it('adds BrowserTracing integration by default', () => {
58+
init({});
59+
60+
const reactInitOptions: NextjsOptions = mockInit.mock.calls[0][0];
61+
expect(reactInitOptions.integrations).toHaveLength(1);
62+
63+
const integrations = reactInitOptions.integrations as Integration[];
64+
expect(integrations[0]).toEqual(expect.any(BrowserTracing));
65+
// eslint-disable-next-line @typescript-eslint/unbound-method
66+
expect((integrations[0] as InstanceType<typeof BrowserTracing>).options.routingInstrumentation).toEqual(
67+
nextRouterInstrumentation,
68+
);
69+
});
70+
71+
it('supports passing integration through options', () => {
72+
init({ integrations: [new Integrations.Breadcrumbs({ console: false })] });
73+
const reactInitOptions: NextjsOptions = mockInit.mock.calls[0][0];
74+
expect(reactInitOptions.integrations).toHaveLength(2);
75+
76+
const integrations = reactInitOptions.integrations as Integration[];
77+
expect(integrations).toEqual([expect.any(Integrations.Breadcrumbs), expect.any(BrowserTracing)]);
78+
});
79+
80+
it('uses custom BrowserTracing but uses nextRouterInstrumentation', () => {
81+
init({
82+
integrations: [new BrowserTracing({ idleTimeout: 5000, startTransactionOnLocationChange: false })],
83+
});
84+
85+
const reactInitOptions: NextjsOptions = mockInit.mock.calls[0][0];
86+
expect(reactInitOptions.integrations).toHaveLength(1);
87+
const integrations = reactInitOptions.integrations as Integration[];
88+
expect((integrations[0] as InstanceType<typeof BrowserTracing>).options).toEqual(
89+
expect.objectContaining({
90+
idleTimeout: 5000,
91+
startTransactionOnLocationChange: false,
92+
routingInstrumentation: nextRouterInstrumentation,
93+
}),
94+
);
95+
});
96+
});
97+
});

packages/nextjs/test/userIntegrations.test.ts renamed to packages/nextjs/test/utils/userIntegrations.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { RewriteFrames } from '@sentry/integrations';
22
import { Integration } from '@sentry/types';
33

4-
import { addIntegration, UserFunctionIntegrations } from '../src/utils/userIntegrations';
4+
import { addIntegration, UserFunctionIntegrations } from '../../src/utils/userIntegrations';
55

66
const testIntegration = new RewriteFrames();
77

0 commit comments

Comments
 (0)