@@ -7,7 +7,7 @@ import { getGlobalObject, logger } from '@sentry/utils';
7
7
import { JSDOM } from 'jsdom' ;
8
8
9
9
import { init , Integrations , nextRouterInstrumentation } from '../src/index.client' ;
10
- import { NextjsOptions } from '../src/utils/nextjsOptions ' ;
10
+ import { UserIntegrationsFunction } from '../src/utils/userIntegrations ' ;
11
11
12
12
const { BrowserTracing } = TracingIntegrations ;
13
13
@@ -32,6 +32,10 @@ afterAll(() => {
32
32
Object . defineProperty ( global , 'location' , { value : originalGlobalLocation } ) ;
33
33
} ) ;
34
34
35
+ function findIntegrationByName ( integrations : Integration [ ] = [ ] , name : string ) : Integration | undefined {
36
+ return integrations . find ( integration => integration . name === name ) ;
37
+ }
38
+
35
39
describe ( 'Client init()' , ( ) => {
36
40
afterEach ( ( ) => {
37
41
jest . clearAllMocks ( ) ;
@@ -95,84 +99,101 @@ describe('Client init()', () => {
95
99
} ) ;
96
100
97
101
describe ( 'integrations' , ( ) => {
98
- it ( 'does not add BrowserTracing integration by default if tracesSampleRate is not set' , ( ) => {
99
- init ( { } ) ;
100
-
101
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
102
- expect ( reactInitOptions . integrations ) . toBeUndefined ( ) ;
103
- } ) ;
102
+ // Options passed by `@sentry/nextjs`'s `init` to `@sentry/react`'s `init` after modifying them
103
+ type ModifiedInitOptionsIntegrationArray = { integrations : Integration [ ] } ;
104
+ type ModifiedInitOptionsIntegrationFunction = { integrations : UserIntegrationsFunction } ;
104
105
105
- it ( 'adds BrowserTracing integration by default if tracesSampleRate is set ' , ( ) => {
106
- init ( { tracesSampleRate : 1.0 } ) ;
106
+ it ( 'supports passing unrelated integrations through options ' , ( ) => {
107
+ init ( { integrations : [ new Integrations . Breadcrumbs ( { console : false } ) ] } ) ;
107
108
108
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
109
- expect ( reactInitOptions . integrations ) . toHaveLength ( 1 ) ;
109
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationArray ;
110
+ const breadcrumbsIntegration = findIntegrationByName ( reactInitOptions . integrations , 'Breadcrumbs' ) ;
110
111
111
- const integrations = reactInitOptions . integrations as Integration [ ] ;
112
- expect ( integrations [ 0 ] ) . toEqual ( expect . any ( BrowserTracing ) ) ;
113
- // eslint-disable-next-line @typescript-eslint/unbound-method
114
- expect ( ( integrations [ 0 ] as InstanceType < typeof BrowserTracing > ) . options . routingInstrumentation ) . toEqual (
115
- nextRouterInstrumentation ,
116
- ) ;
112
+ expect ( breadcrumbsIntegration ) . toBeDefined ( ) ;
117
113
} ) ;
118
114
119
- it ( 'adds BrowserTracing integration by default if tracesSampler is set' , ( ) => {
120
- init ( { tracesSampler : ( ) => true } ) ;
115
+ describe ( '`BrowserTracing` integration' , ( ) => {
116
+ it ( 'adds `BrowserTracing` integration if `tracesSampleRate` is set' , ( ) => {
117
+ init ( { tracesSampleRate : 1.0 } ) ;
118
+
119
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationArray ;
120
+ const browserTracingIntegration = findIntegrationByName ( reactInitOptions . integrations , 'BrowserTracing' ) ;
121
+
122
+ expect ( browserTracingIntegration ) . toBeDefined ( ) ;
123
+ expect ( browserTracingIntegration ) . toEqual (
124
+ expect . objectContaining ( {
125
+ options : expect . objectContaining ( {
126
+ routingInstrumentation : nextRouterInstrumentation ,
127
+ } ) ,
128
+ } ) ,
129
+ ) ;
130
+ } ) ;
121
131
122
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
123
- expect ( reactInitOptions . integrations ) . toHaveLength ( 1 ) ;
132
+ it ( 'adds `BrowserTracing` integration if `tracesSampler` is set' , ( ) => {
133
+ init ( { tracesSampler : ( ) => true } ) ;
124
134
125
- const integrations = reactInitOptions . integrations as Integration [ ] ;
126
- expect ( integrations [ 0 ] ) . toEqual ( expect . any ( BrowserTracing ) ) ;
127
- // eslint-disable-next-line @typescript-eslint/unbound-method
128
- expect ( ( integrations [ 0 ] as InstanceType < typeof BrowserTracing > ) . options . routingInstrumentation ) . toEqual (
129
- nextRouterInstrumentation ,
130
- ) ;
131
- } ) ;
135
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationArray ;
136
+ const browserTracingIntegration = findIntegrationByName ( reactInitOptions . integrations , 'BrowserTracing' ) ;
132
137
133
- it ( 'supports passing integration through options' , ( ) => {
134
- init ( { tracesSampleRate : 1.0 , integrations : [ new Integrations . Breadcrumbs ( { console : false } ) ] } ) ;
135
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
136
- expect ( reactInitOptions . integrations ) . toHaveLength ( 2 ) ;
138
+ expect ( browserTracingIntegration ) . toBeDefined ( ) ;
139
+ expect ( browserTracingIntegration ) . toEqual (
140
+ expect . objectContaining ( {
141
+ options : expect . objectContaining ( {
142
+ routingInstrumentation : nextRouterInstrumentation ,
143
+ } ) ,
144
+ } ) ,
145
+ ) ;
146
+ } ) ;
137
147
138
- const integrations = reactInitOptions . integrations as Integration [ ] ;
139
- expect ( integrations ) . toEqual ( [ expect . any ( Integrations . Breadcrumbs ) , expect . any ( BrowserTracing ) ] ) ;
140
- } ) ;
148
+ it ( 'does not add `BrowserTracing` integration if tracing not enabled in SDK' , ( ) => {
149
+ init ( { } ) ;
141
150
142
- it ( 'uses custom BrowserTracing with array option with nextRouterInstrumentation' , ( ) => {
143
- init ( {
144
- tracesSampleRate : 1.0 ,
145
- integrations : [ new BrowserTracing ( { idleTimeout : 5000 , startTransactionOnLocationChange : false } ) ] ,
146
- } ) ;
151
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationArray ;
152
+ const browserTracingIntegration = findIntegrationByName ( reactInitOptions . integrations , 'BrowserTracing' ) ;
147
153
148
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
149
- expect ( reactInitOptions . integrations ) . toHaveLength ( 1 ) ;
150
- const integrations = reactInitOptions . integrations as Integration [ ] ;
151
- expect ( ( integrations [ 0 ] as InstanceType < typeof BrowserTracing > ) . options ) . toEqual (
152
- expect . objectContaining ( {
153
- idleTimeout : 5000 ,
154
- startTransactionOnLocationChange : false ,
155
- routingInstrumentation : nextRouterInstrumentation ,
156
- } ) ,
157
- ) ;
158
- } ) ;
154
+ expect ( browserTracingIntegration ) . toBeUndefined ( ) ;
155
+ } ) ;
159
156
160
- it ( 'uses custom BrowserTracing with function option with nextRouterInstrumentation' , ( ) => {
161
- init ( {
162
- tracesSampleRate : 1.0 ,
163
- integrations : ( ) => [ new BrowserTracing ( { idleTimeout : 5000 , startTransactionOnLocationChange : false } ) ] ,
157
+ it ( 'forces correct router instrumentation if user provides `BrowserTracing` in an array' , ( ) => {
158
+ init ( {
159
+ tracesSampleRate : 1.0 ,
160
+ integrations : [ new BrowserTracing ( { startTransactionOnLocationChange : false } ) ] ,
161
+ } ) ;
162
+
163
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationArray ;
164
+ const browserTracingIntegration = findIntegrationByName ( reactInitOptions . integrations , 'BrowserTracing' ) ;
165
+
166
+ expect ( browserTracingIntegration ) . toEqual (
167
+ expect . objectContaining ( {
168
+ options : expect . objectContaining ( {
169
+ routingInstrumentation : nextRouterInstrumentation ,
170
+ // This proves it's still the user's copy
171
+ startTransactionOnLocationChange : false ,
172
+ } ) ,
173
+ } ) ,
174
+ ) ;
164
175
} ) ;
165
176
166
- const reactInitOptions : NextjsOptions = reactInit . mock . calls [ 0 ] [ 0 ] ;
167
- const integrationFunc = reactInitOptions . integrations as ( ) => Integration [ ] ;
168
- const integrations = integrationFunc ( ) ;
169
- expect ( ( integrations [ 0 ] as InstanceType < typeof BrowserTracing > ) . options ) . toEqual (
170
- expect . objectContaining ( {
171
- idleTimeout : 5000 ,
172
- startTransactionOnLocationChange : false ,
173
- routingInstrumentation : nextRouterInstrumentation ,
174
- } ) ,
175
- ) ;
177
+ it ( 'forces correct router instrumentation if user provides `BrowserTracing` in a function' , ( ) => {
178
+ init ( {
179
+ tracesSampleRate : 1.0 ,
180
+ integrations : defaults => [ ...defaults , new BrowserTracing ( { startTransactionOnLocationChange : false } ) ] ,
181
+ } ) ;
182
+
183
+ const reactInitOptions = reactInit . mock . calls [ 0 ] [ 0 ] as ModifiedInitOptionsIntegrationFunction ;
184
+ const materializedIntegrations = reactInitOptions . integrations ( SentryReact . defaultIntegrations ) ;
185
+ const browserTracingIntegration = findIntegrationByName ( materializedIntegrations , 'BrowserTracing' ) ;
186
+
187
+ expect ( browserTracingIntegration ) . toEqual (
188
+ expect . objectContaining ( {
189
+ options : expect . objectContaining ( {
190
+ routingInstrumentation : nextRouterInstrumentation ,
191
+ // This proves it's still the user's copy
192
+ startTransactionOnLocationChange : false ,
193
+ } ) ,
194
+ } ) ,
195
+ ) ;
196
+ } ) ;
176
197
} ) ;
177
198
} ) ;
178
199
} ) ;
0 commit comments