@@ -30,6 +30,66 @@ function createTmpFile(content = 'console.log("running");', ext = '.js', basenam
30
30
return file ;
31
31
}
32
32
33
+ function runInBackground ( { args = [ ] , options = { } , completed = 'Completed running' , shouldFail = false } ) {
34
+ let future = Promise . withResolvers ( ) ;
35
+ let child ;
36
+ let stderr = '' ;
37
+ let stdout = [ ] ;
38
+
39
+ const run = ( ) => {
40
+ args . unshift ( '--no-warnings' ) ;
41
+ child = spawn ( execPath , args , { encoding : 'utf8' , stdio : 'pipe' , ...options } ) ;
42
+
43
+ child . stderr . on ( 'data' , ( data ) => {
44
+ stderr += data ;
45
+ } ) ;
46
+
47
+ const rl = createInterface ( { input : child . stdout } ) ;
48
+ rl . on ( 'line' , ( data ) => {
49
+ if ( ! data . startsWith ( 'Waiting for graceful termination' ) && ! data . startsWith ( 'Gracefully restarted' ) ) {
50
+ stdout . push ( data ) ;
51
+ if ( data . startsWith ( completed ) ) {
52
+ future . resolve ( { stderr, stdout } ) ;
53
+ future = Promise . withResolvers ( ) ;
54
+ stdout = [ ] ;
55
+ stderr = '' ;
56
+ } else if ( data . startsWith ( 'Failed running' ) ) {
57
+ if ( shouldFail ) {
58
+ future . resolve ( { stderr, stdout } ) ;
59
+ } else {
60
+ future . reject ( { stderr, stdout } ) ;
61
+ }
62
+ future = Promise . withResolvers ( ) ;
63
+ stdout = [ ] ;
64
+ stderr = '' ;
65
+ }
66
+ }
67
+ } ) ;
68
+ } ;
69
+
70
+ return {
71
+ async done ( ) {
72
+ child ?. kill ( ) ;
73
+ future . resolve ( ) ;
74
+ return { stdout, stderr } ;
75
+ } ,
76
+ restart ( timeout = 1000 ) {
77
+ if ( ! child ) {
78
+ run ( ) ;
79
+ }
80
+ const timer = setTimeout ( ( ) => {
81
+ if ( ! future . resolved ) {
82
+ child . kill ( ) ;
83
+ future . reject ( new Error ( 'Timed out waiting for restart' ) ) ;
84
+ }
85
+ } , timeout ) ;
86
+ return future . promise . finally ( ( ) => {
87
+ clearTimeout ( timer ) ;
88
+ } ) ;
89
+ }
90
+ } ;
91
+ }
92
+
33
93
async function runWriteSucceed ( {
34
94
file,
35
95
watchedFile,
@@ -132,6 +192,56 @@ describe('watch mode', { concurrency: !process.env.TEST_PARALLEL, timeout: 60_00
132
192
] ) ;
133
193
} ) ;
134
194
195
+ it ( 'should reload env variables when --env-file changes' , async ( ) => {
196
+ const envKey = `TEST_ENV_${ Date . now ( ) } ` ;
197
+ const jsFile = createTmpFile ( `console.log('ENV: ' + process.env.${ envKey } );` ) ;
198
+ const envFile = createTmpFile ( `${ envKey } =value1` , '.env' ) ;
199
+ const { done, restart } = runInBackground ( { args : [ '--watch' , `--env-file=${ envFile } ` , jsFile ] } ) ;
200
+
201
+ try {
202
+ await restart ( ) ;
203
+ writeFileSync ( envFile , `${ envKey } =value2` ) ;
204
+
205
+ // Second restart, after env change
206
+ const { stdout, stderr } = await restart ( ) ;
207
+
208
+ assert . strictEqual ( stderr , '' ) ;
209
+ assert . deepStrictEqual ( stdout , [
210
+ `Restarting ${ inspect ( jsFile ) } ` ,
211
+ 'ENV: value2' ,
212
+ `Completed running ${ inspect ( jsFile ) } ` ,
213
+ ] ) ;
214
+ } finally {
215
+ await done ( ) ;
216
+ }
217
+ } ) ;
218
+
219
+ it ( 'should load new env variables when --env-file changes' , async ( ) => {
220
+ const envKey = `TEST_ENV_${ Date . now ( ) } ` ;
221
+ const envKey2 = `TEST_ENV_2_${ Date . now ( ) } ` ;
222
+ const jsFile = createTmpFile ( `console.log('ENV: ' + process.env.${ envKey } + '\\n' + 'ENV2: ' + process.env.${ envKey2 } );` ) ;
223
+ const envFile = createTmpFile ( `${ envKey } =value1` , '.env' ) ;
224
+ const { done, restart } = runInBackground ( { args : [ '--watch' , `--env-file=${ envFile } ` , jsFile ] } ) ;
225
+
226
+ try {
227
+ await restart ( ) ;
228
+ await writeFileSync ( envFile , `${ envKey } =value1\n${ envKey2 } =newValue` ) ;
229
+
230
+ // Second restart, after env change
231
+ const { stderr, stdout } = await restart ( ) ;
232
+
233
+ assert . strictEqual ( stderr , '' ) ;
234
+ assert . deepStrictEqual ( stdout , [
235
+ `Restarting ${ inspect ( jsFile ) } ` ,
236
+ 'ENV: value1' ,
237
+ 'ENV2: newValue' ,
238
+ `Completed running ${ inspect ( jsFile ) } ` ,
239
+ ] ) ;
240
+ } finally {
241
+ await done ( ) ;
242
+ }
243
+ } ) ;
244
+
135
245
it ( 'should watch changes to a failing file' , async ( ) => {
136
246
const file = createTmpFile ( 'throw new Error("fails");' ) ;
137
247
const { stderr, stdout } = await runWriteSucceed ( {
0 commit comments