@@ -37,6 +37,33 @@ const mockExistsSync = (path: fs.PathLike) => {
37
37
} ;
38
38
const exitsSync = jest . spyOn ( fs , 'existsSync' ) . mockImplementation ( mockExistsSync ) ;
39
39
40
+ // Make it so that all temporary folders, either created directly by tests or by the code they're testing, will go into
41
+ // one spot that we know about, which we can then clean up when we're done
42
+ const realTmpdir = jest . requireActual ( 'os' ) . tmpdir ;
43
+ const TEMP_DIR_PATH = path . join ( realTmpdir ( ) , 'sentry-nextjs-test' ) ;
44
+ jest . spyOn ( os , 'tmpdir' ) . mockReturnValue ( TEMP_DIR_PATH ) ;
45
+ // In theory, we should always land in the `else` here, but this saves the cases where the prior run got interrupted and
46
+ // the `afterAll` below didn't happen.
47
+ if ( fs . existsSync ( TEMP_DIR_PATH ) ) {
48
+ rimraf . sync ( path . join ( TEMP_DIR_PATH , '*' ) ) ;
49
+ } else {
50
+ fs . mkdirSync ( TEMP_DIR_PATH ) ;
51
+ }
52
+
53
+ afterAll ( ( ) => {
54
+ rimraf . sync ( TEMP_DIR_PATH ) ;
55
+ } ) ;
56
+
57
+ // In order to know what to expect in the webpack config `entry` property, we need to know the path of the temporary
58
+ // directory created when doing the file injection, so wrap the real `mkdtempSync` and store the resulting path where we
59
+ // can access it
60
+ let tempDir : string ;
61
+ const realMkdtempSync = jest . requireActual ( 'fs' ) . mkdtempSync ;
62
+ jest . spyOn ( fs , 'mkdtempSync' ) . mockImplementation ( prefix => {
63
+ tempDir = realMkdtempSync ( prefix ) ;
64
+ return tempDir ;
65
+ } ) ;
66
+
40
67
/** Mocks of the arguments passed to `withSentryConfig` */
41
68
const userNextConfig : Partial < NextConfigObject > = {
42
69
publicRuntimeConfig : { location : 'dogpark' , activities : [ 'fetch' , 'chasing' , 'digging' ] } ,
@@ -103,7 +130,12 @@ function getBuildContext(
103
130
dev : false ,
104
131
buildId : 'sItStAyLiEdOwN' ,
105
132
dir : '/Users/Maisey/projects/squirrelChasingSimulator' ,
106
- config : { target : 'server' , ...userNextConfig } as NextConfigObject ,
133
+ config : {
134
+ // nextjs's default values
135
+ target : 'server' ,
136
+ distDir : '.next' ,
137
+ ...userNextConfig ,
138
+ } as NextConfigObject ,
107
139
webpack : { version : webpackVersion } ,
108
140
isServer : buildTarget === 'server' ,
109
141
} ;
@@ -279,26 +311,34 @@ describe('webpack config', () => {
279
311
incomingWebpackBuildContext : serverBuildContext ,
280
312
} ) ;
281
313
314
+ const rewriteFramesHelper = path . join ( tempDir , 'rewriteFramesHelper.js' ) ;
315
+
282
316
expect ( finalWebpackConfig . entry ) . toEqual (
283
317
expect . objectContaining ( {
284
318
// original entry point value is a string
285
319
// (was 'private-next-pages/api/dogs/[name].js')
286
- 'pages/api/dogs/[name]' : [ serverConfigFilePath , 'private-next-pages/api/dogs/[name].js' ] ,
320
+ 'pages/api/dogs/[name]' : [ rewriteFramesHelper , serverConfigFilePath , 'private-next-pages/api/dogs/[name].js' ] ,
287
321
288
322
// original entry point value is a string array
289
323
// (was ['./node_modules/smellOVision/index.js', 'private-next-pages/_app.js'])
290
- 'pages/_app' : [ serverConfigFilePath , './node_modules/smellOVision/index.js' , 'private-next-pages/_app.js' ] ,
324
+ 'pages/_app' : [
325
+ rewriteFramesHelper ,
326
+ serverConfigFilePath ,
327
+ './node_modules/smellOVision/index.js' ,
328
+ 'private-next-pages/_app.js' ,
329
+ ] ,
291
330
292
331
// original entry point value is an object containing a string `import` value
293
332
// (`import` was 'private-next-pages/api/simulator/dogStats/[name].js')
294
333
'pages/api/simulator/dogStats/[name]' : {
295
- import : [ serverConfigFilePath , 'private-next-pages/api/simulator/dogStats/[name].js' ] ,
334
+ import : [ rewriteFramesHelper , serverConfigFilePath , 'private-next-pages/api/simulator/dogStats/[name].js' ] ,
296
335
} ,
297
336
298
337
// original entry point value is an object containing a string array `import` value
299
338
// (`import` was ['./node_modules/dogPoints/converter.js', 'private-next-pages/api/simulator/leaderboard.js'])
300
339
'pages/api/simulator/leaderboard' : {
301
340
import : [
341
+ rewriteFramesHelper ,
302
342
serverConfigFilePath ,
303
343
'./node_modules/dogPoints/converter.js' ,
304
344
'private-next-pages/api/simulator/leaderboard.js' ,
@@ -308,14 +348,14 @@ describe('webpack config', () => {
308
348
// original entry point value is an object containg properties besides `import`
309
349
// (`dependOn` remains untouched)
310
350
'pages/api/tricks/[trickName]' : {
311
- import : [ serverConfigFilePath , 'private-next-pages/api/tricks/[trickName].js' ] ,
351
+ import : [ rewriteFramesHelper , serverConfigFilePath , 'private-next-pages/api/tricks/[trickName].js' ] ,
312
352
dependOn : 'treats' ,
313
353
} ,
314
354
} ) ,
315
355
) ;
316
356
} ) ;
317
357
318
- it ( 'does not inject into non-_app, non-API routes' , async ( ) => {
358
+ it ( 'does not inject anything into non-_app, non-API routes' , async ( ) => {
319
359
const finalWebpackConfig = await materializeFinalWebpackConfig ( {
320
360
userNextConfig,
321
361
incomingWebpackConfig : clientWebpackConfig ,
@@ -326,12 +366,60 @@ describe('webpack config', () => {
326
366
expect . objectContaining ( {
327
367
// no injected file
328
368
main : './src/index.ts' ,
329
- // was 'next-client-pages-loader?page=%2F_app'
369
+ } ) ,
370
+ ) ;
371
+ } ) ;
372
+
373
+ it ( 'does not inject `RewriteFrames` helper into client routes' , async ( ) => {
374
+ const finalWebpackConfig = await materializeFinalWebpackConfig ( {
375
+ userNextConfig,
376
+ incomingWebpackConfig : clientWebpackConfig ,
377
+ incomingWebpackBuildContext : clientBuildContext ,
378
+ } ) ;
379
+
380
+ expect ( finalWebpackConfig . entry ) . toEqual (
381
+ expect . objectContaining ( {
382
+ // was 'next-client-pages-loader?page=%2F_app', and now has client config but not`RewriteFrames` helper injected
330
383
'pages/_app' : [ clientConfigFilePath , 'next-client-pages-loader?page=%2F_app' ] ,
331
384
} ) ,
332
385
) ;
333
386
} ) ;
334
387
} ) ;
388
+
389
+ describe ( '`distDir` value in default server-side `RewriteFrames` integration' , ( ) => {
390
+ it . each ( [
391
+ [ 'no custom `distDir`' , undefined , '.next' ] ,
392
+ [ 'custom `distDir`' , 'dist' , 'dist' ] ,
393
+ ] ) (
394
+ 'creates file injecting `distDir` value into `global` - %s' ,
395
+ async ( _name , customDistDir , expectedInjectedValue ) => {
396
+ // Note: the fact that the file tested here gets injected correctly is covered in the 'webpack `entry` property
397
+ // config' tests above
398
+
399
+ const userNextConfigDistDir = {
400
+ ...userNextConfig ,
401
+ ...( customDistDir && { distDir : customDistDir } ) ,
402
+ } ;
403
+ await materializeFinalWebpackConfig ( {
404
+ userNextConfig : userNextConfigDistDir ,
405
+ incomingWebpackConfig : serverWebpackConfig ,
406
+ incomingWebpackBuildContext : getBuildContext ( 'server' , userNextConfigDistDir ) ,
407
+ } ) ;
408
+ const rewriteFramesHelper = path . join ( tempDir , 'rewriteFramesHelper.js' ) ;
409
+
410
+ expect ( fs . existsSync ( rewriteFramesHelper ) ) . toBe ( true ) ;
411
+
412
+ const injectedCode = fs . readFileSync ( rewriteFramesHelper ) . toString ( ) ;
413
+ expect ( injectedCode ) . toEqual ( `global.__rewriteFramesDistDir__ = '${ expectedInjectedValue } ';\n` ) ;
414
+ } ,
415
+ ) ;
416
+
417
+ describe ( '`RewriteFrames` ends up with correct `distDir` value' , ( ) => {
418
+ // TODO: this, along with any number of other parts of the build process, should be tested with an integration
419
+ // test which actually runs webpack and inspects the resulting bundles (and that integration test should test
420
+ // custom `distDir` values with and without a `.`, to make sure the regex escaping is working)
421
+ } ) ;
422
+ } ) ;
335
423
} ) ;
336
424
337
425
describe ( 'Sentry webpack plugin config' , ( ) => {
@@ -580,19 +668,15 @@ describe('Sentry webpack plugin config', () => {
580
668
} ) ;
581
669
582
670
describe ( 'getUserConfigFile' , ( ) => {
583
- let tempDir : string ;
584
-
585
671
beforeAll ( ( ) => {
586
672
exitsSync . mockImplementation ( realExistsSync ) ;
587
673
} ) ;
588
674
589
675
beforeEach ( ( ) => {
676
+ // these will get cleaned up by the file's overall `afterAll` function, and the `mkdtempSync` mock above ensures
677
+ // that the location of the created folder is stored in `tempDir`
590
678
const tempDirPathPrefix = path . join ( os . tmpdir ( ) , 'sentry-nextjs-test-' ) ;
591
- tempDir = fs . mkdtempSync ( tempDirPathPrefix ) ;
592
- } ) ;
593
-
594
- afterEach ( ( ) => {
595
- rimraf . sync ( tempDir ) ;
679
+ fs . mkdtempSync ( tempDirPathPrefix ) ;
596
680
} ) ;
597
681
598
682
afterAll ( ( ) => {
0 commit comments