@@ -10,6 +10,7 @@ var uniqueTempDir = require('unique-temp-dir');
10
10
var findCacheDir = require ( 'find-cache-dir' ) ;
11
11
var debounce = require ( 'lodash.debounce' ) ;
12
12
var ms = require ( 'ms' ) ;
13
+ var getPort = require ( 'get-port' ) ;
13
14
var AvaError = require ( './lib/ava-error' ) ;
14
15
var fork = require ( './lib/fork' ) ;
15
16
var CachingPrecompiler = require ( './lib/caching-precompiler' ) ;
@@ -42,7 +43,7 @@ function Api(options) {
42
43
util . inherits ( Api , EventEmitter ) ;
43
44
module . exports = Api ;
44
45
45
- Api . prototype . _runFile = function ( file , runStatus ) {
46
+ Api . prototype . _runFile = function ( file , runStatus , execArgv ) {
46
47
var hash = this . precompiler . precompileFile ( file ) ;
47
48
var precompiled = { } ;
48
49
precompiled [ file ] = hash ;
@@ -51,7 +52,7 @@ Api.prototype._runFile = function (file, runStatus) {
51
52
precompiled : precompiled
52
53
} ) ;
53
54
54
- var emitter = fork ( file , options ) ;
55
+ var emitter = fork ( file , options , execArgv ) ;
55
56
56
57
runStatus . observeFork ( emitter ) ;
57
58
@@ -127,6 +128,36 @@ Api.prototype._run = function (files, _options) {
127
128
return overwatch ;
128
129
} ;
129
130
131
+ Api . prototype . computeForkExecArgs = function ( files ) {
132
+ var execArgv = this . options . testOnlyExecArgv || process . execArgv ;
133
+ var debugArgIndex = - 1 ;
134
+ execArgv . some ( function ( arg , index ) {
135
+ if ( arg === '--debug' || arg === '--debug-brk' || arg . indexOf ( '--debug-brk=' ) === 0 || arg . indexOf ( '--debug=' ) === 0 ) {
136
+ debugArgIndex = index ;
137
+ return true ;
138
+ }
139
+ return false ;
140
+ } ) ;
141
+
142
+ if ( debugArgIndex === - 1 ) {
143
+ return Promise . resolve ( [ ] ) ;
144
+ }
145
+
146
+ return Promise . map ( files , getPort )
147
+ . then ( function ( ports ) {
148
+ return ports . map ( function ( port ) {
149
+ var forkExecArgv = execArgv . slice ( ) ;
150
+ var flagName = '--debug' ;
151
+ var oldValue = forkExecArgv [ debugArgIndex ] ;
152
+ if ( oldValue . indexOf ( 'brk' ) > 0 ) {
153
+ flagName += '-brk' ;
154
+ }
155
+ forkExecArgv [ debugArgIndex ] = flagName + '=' + port ;
156
+ return forkExecArgv ;
157
+ } ) ;
158
+ } ) ;
159
+ } ;
160
+
130
161
Api . prototype . _runNoPool = function ( files , runStatus ) {
131
162
var self = this ;
132
163
var tests = new Array ( self . fileCount ) ;
@@ -138,94 +169,97 @@ Api.prototype._runNoPool = function (files, runStatus) {
138
169
} ) ;
139
170
} ) ;
140
171
141
- return new Promise ( function ( resolve ) {
142
- function run ( ) {
143
- if ( self . options . match . length > 0 && ! runStatus . hasExclusive ) {
144
- runStatus . handleExceptions ( {
145
- exception : new AvaError ( 'Couldn\'t find any matching tests' ) ,
146
- file : undefined
147
- } ) ;
172
+ return self . computeForkExecArgs ( files )
173
+ . then ( function ( execArgvList ) {
174
+ return new Promise ( function ( resolve ) {
175
+ function run ( ) {
176
+ if ( self . options . match . length > 0 && ! runStatus . hasExclusive ) {
177
+ runStatus . handleExceptions ( {
178
+ exception : new AvaError ( 'Couldn\'t find any matching tests' ) ,
179
+ file : undefined
180
+ } ) ;
181
+
182
+ resolve ( [ ] ) ;
183
+ return ;
184
+ }
148
185
149
- resolve ( [ ] ) ;
150
- return ;
151
- }
152
-
153
- var method = self . options . serial ? 'mapSeries' : 'map' ;
154
- var options = {
155
- runOnlyExclusive : runStatus . hasExclusive
156
- } ;
157
-
158
- resolve ( Promise [ method ] ( files , function ( file , index ) {
159
- return tests [ index ] . run ( options ) . catch ( function ( err ) {
160
- // The test failed catastrophically. Flag it up as an
161
- // exception, then return an empty result. Other tests may
162
- // continue to run.
163
- runStatus . handleExceptions ( {
164
- exception : err ,
165
- file : path . relative ( '.' , file )
166
- } ) ;
186
+ var method = self . options . serial ? 'mapSeries' : 'map' ;
187
+ var options = {
188
+ runOnlyExclusive : runStatus . hasExclusive
189
+ } ;
167
190
168
- return getBlankResults ( ) ;
169
- } ) ;
170
- } ) ) ;
171
- }
191
+ resolve ( Promise [ method ] ( files , function ( file , index ) {
192
+ return tests [ index ] . run ( options ) . catch ( function ( err ) {
193
+ // The test failed catastrophically. Flag it up as an
194
+ // exception, then return an empty result. Other tests may
195
+ // continue to run.
196
+ runStatus . handleExceptions ( {
197
+ exception : err ,
198
+ file : path . relative ( '.' , file )
199
+ } ) ;
200
+
201
+ return getBlankResults ( ) ;
202
+ } ) ;
203
+ } ) ) ;
204
+ }
172
205
173
- // receive test count from all files and then run the tests
174
- var unreportedFiles = self . fileCount ;
175
- var bailed = false ;
206
+ // receive test count from all files and then run the tests
207
+ var unreportedFiles = self . fileCount ;
208
+ var bailed = false ;
176
209
177
- files . every ( function ( file , index ) {
178
- var tried = false ;
210
+ files . every ( function ( file , index ) {
211
+ var tried = false ;
179
212
180
- function tryRun ( ) {
181
- if ( ! tried && ! bailed ) {
182
- tried = true ;
183
- unreportedFiles -- ;
213
+ function tryRun ( ) {
214
+ if ( ! tried && ! bailed ) {
215
+ tried = true ;
216
+ unreportedFiles -- ;
184
217
185
- if ( unreportedFiles === 0 ) {
186
- run ( ) ;
218
+ if ( unreportedFiles === 0 ) {
219
+ run ( ) ;
220
+ }
221
+ }
187
222
}
188
- }
189
- }
190
223
191
- try {
192
- var test = tests [ index ] = self . _runFile ( file , runStatus ) ;
224
+ try {
225
+ var test = tests [ index ] = self . _runFile ( file , runStatus , execArgvList [ index ] ) ;
193
226
194
- test . on ( 'stats' , tryRun ) ;
195
- test . catch ( tryRun ) ;
227
+ test . on ( 'stats' , tryRun ) ;
228
+ test . catch ( tryRun ) ;
196
229
197
- return true ;
198
- } catch ( err ) {
199
- bailed = true ;
230
+ return true ;
231
+ } catch ( err ) {
232
+ bailed = true ;
200
233
201
- runStatus . handleExceptions ( {
202
- exception : err ,
203
- file : path . relative ( '.' , file )
204
- } ) ;
234
+ runStatus . handleExceptions ( {
235
+ exception : err ,
236
+ file : path . relative ( '.' , file )
237
+ } ) ;
205
238
206
- resolve ( [ ] ) ;
239
+ resolve ( [ ] ) ;
207
240
208
- return false ;
209
- }
210
- } ) ;
211
- } ) . then ( function ( results ) {
212
- if ( results . length === 0 ) {
213
- // No tests ran, make sure to tear down the child processes.
214
- tests . forEach ( function ( test ) {
215
- test . send ( 'teardown' ) ;
216
- } ) ;
217
- }
241
+ return false ;
242
+ }
243
+ } ) ;
244
+ } ) . then ( function ( results ) {
245
+ if ( results . length === 0 ) {
246
+ // No tests ran, make sure to tear down the child processes.
247
+ tests . forEach ( function ( test ) {
248
+ test . send ( 'teardown' ) ;
249
+ } ) ;
250
+ }
218
251
219
- return results ;
220
- } ) . then ( function ( results ) {
221
- // cancel debounced _onTimeout() from firing
222
- if ( self . options . timeout ) {
223
- runStatus . _restartTimer . cancel ( ) ;
224
- }
252
+ return results ;
253
+ } ) . then ( function ( results ) {
254
+ // cancel debounced _onTimeout() from firing
255
+ if ( self . options . timeout ) {
256
+ runStatus . _restartTimer . cancel ( ) ;
257
+ }
225
258
226
- runStatus . processResults ( results ) ;
227
- return runStatus ;
228
- } ) ;
259
+ runStatus . processResults ( results ) ;
260
+ return runStatus ;
261
+ } ) ;
262
+ } ) ;
229
263
} ;
230
264
231
265
function getBlankResults ( ) {
@@ -253,57 +287,60 @@ Api.prototype._runLimitedPool = function (files, runStatus, concurrency) {
253
287
} ) ;
254
288
} ) ;
255
289
256
- return Promise . map ( files , function ( file ) {
257
- var handleException = function ( err ) {
258
- runStatus . handleExceptions ( {
259
- exception : err ,
260
- file : path . relative ( '.' , file )
261
- } ) ;
262
- } ;
263
-
264
- try {
265
- var test = tests [ file ] = self . _runFile ( file , runStatus ) ;
266
-
267
- return new Promise ( function ( resolve , reject ) {
268
- var runner = function ( ) {
269
- var options = {
270
- // If we're looking for matches, run every single test process in exclusive-only mode
271
- runOnlyExclusive : self . options . match . length > 0
290
+ return self . computeForkExecArgs ( files )
291
+ . then ( function ( execArgvList ) {
292
+ return Promise . map ( files , function ( file , index ) {
293
+ var handleException = function ( err ) {
294
+ runStatus . handleExceptions ( {
295
+ exception : err ,
296
+ file : path . relative ( '.' , file )
297
+ } ) ;
272
298
} ;
273
- test . run ( options )
274
- . then ( resolve )
275
- . catch ( reject ) ;
276
- } ;
277
-
278
- test . on ( 'stats' , runner ) ;
279
- test . on ( 'exit' , function ( ) {
280
- delete tests [ file ] ;
281
- } ) ;
282
- test . catch ( runner ) ;
283
- } ) . catch ( handleException ) ;
284
- } catch ( err ) {
285
- handleException ( err ) ;
286
- }
287
- } , { concurrency : concurrency } )
288
- . then ( function ( results ) {
289
- // Filter out undefined results (usually result of caught exceptions)
290
- results = results . filter ( Boolean ) ;
291
-
292
- // cancel debounced _onTimeout() from firing
293
- if ( self . options . timeout ) {
294
- runStatus . _restartTimer . cancel ( ) ;
295
- }
296
-
297
- if ( self . options . match . length > 0 && ! runStatus . hasExclusive ) {
298
- // Ensure results are empty
299
- results = [ ] ;
300
- runStatus . handleExceptions ( {
301
- exception : new AvaError ( 'Couldn\'t find any matching tests' ) ,
302
- file : undefined
303
- } ) ;
304
- }
305
299
306
- runStatus . processResults ( results ) ;
307
- return runStatus ;
308
- } ) ;
300
+ try {
301
+ var test = tests [ file ] = self . _runFile ( file , runStatus , execArgvList [ index ] ) ;
302
+
303
+ return new Promise ( function ( resolve , reject ) {
304
+ var runner = function ( ) {
305
+ var options = {
306
+ // If we're looking for matches, run every single test process in exclusive-only mode
307
+ runOnlyExclusive : self . options . match . length > 0
308
+ } ;
309
+ test . run ( options )
310
+ . then ( resolve )
311
+ . catch ( reject ) ;
312
+ } ;
313
+
314
+ test . on ( 'stats' , runner ) ;
315
+ test . on ( 'exit' , function ( ) {
316
+ delete tests [ file ] ;
317
+ } ) ;
318
+ test . catch ( runner ) ;
319
+ } ) . catch ( handleException ) ;
320
+ } catch ( err ) {
321
+ handleException ( err ) ;
322
+ }
323
+ } , { concurrency : concurrency } )
324
+ . then ( function ( results ) {
325
+ // Filter out undefined results (usually result of caught exceptions)
326
+ results = results . filter ( Boolean ) ;
327
+
328
+ // cancel debounced _onTimeout() from firing
329
+ if ( self . options . timeout ) {
330
+ runStatus . _restartTimer . cancel ( ) ;
331
+ }
332
+
333
+ if ( self . options . match . length > 0 && ! runStatus . hasExclusive ) {
334
+ // Ensure results are empty
335
+ results = [ ] ;
336
+ runStatus . handleExceptions ( {
337
+ exception : new AvaError ( 'Couldn\'t find any matching tests' ) ,
338
+ file : undefined
339
+ } ) ;
340
+ }
341
+
342
+ runStatus . processResults ( results ) ;
343
+ return runStatus ;
344
+ } ) ;
345
+ } ) ;
309
346
} ;
0 commit comments