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