ava 0.16.0 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api.js +297 -265
- package/cli.js +15 -179
- package/index.js +5 -98
- package/index.js.flow +201 -0
- package/lib/assert.js +87 -53
- package/lib/ava-error.js +4 -8
- package/lib/ava-files.js +282 -0
- package/lib/babel-config.js +35 -73
- package/lib/beautify-stack.js +17 -16
- package/lib/caching-precompiler.js +72 -87
- package/lib/cli.js +181 -0
- package/lib/code-excerpt.js +57 -0
- package/lib/colors.js +6 -2
- package/lib/concurrent.js +62 -75
- package/lib/enhance-assert.js +57 -49
- package/lib/extract-stack.js +10 -0
- package/lib/fork.js +67 -68
- package/lib/format-assert-error.js +72 -0
- package/lib/globals.js +3 -8
- package/lib/hook.js +15 -20
- package/lib/logger.js +59 -82
- package/lib/main.js +90 -0
- package/lib/prefix-title.js +21 -0
- package/lib/process-adapter.js +108 -0
- package/lib/reporters/mini.js +260 -257
- package/lib/reporters/tap.js +80 -85
- package/lib/reporters/verbose.js +142 -115
- package/lib/run-status.js +110 -152
- package/lib/runner.js +125 -137
- package/lib/sequence.js +68 -84
- package/lib/serialize-error.js +68 -4
- package/lib/snapshot-state.js +30 -0
- package/lib/test-collection.js +144 -156
- package/lib/test-worker.js +45 -95
- package/lib/test.js +289 -318
- package/lib/throws-helper.js +9 -9
- package/lib/validate-test.js +48 -0
- package/lib/watcher.js +258 -297
- package/package.json +63 -53
- package/profile.js +68 -55
- package/readme.md +215 -101
- package/types/generated.d.ts +848 -228
- package/types/make.js +54 -23
- package/lib/send.js +0 -16
package/api.js
CHANGED
|
@@ -1,315 +1,347 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cwd: process.cwd(),
|
|
28
|
-
resolveTestsFrom: process.cwd(),
|
|
29
|
-
match: []
|
|
30
|
-
}, options);
|
|
31
|
-
|
|
32
|
-
this.options.require = (this.options.require || []).map(function (moduleId) {
|
|
33
|
-
var ret = resolveCwd(moduleId);
|
|
34
|
-
if (ret === null) {
|
|
35
|
-
throw new Error('Could not resolve required module \'' + moduleId + '\'');
|
|
2
|
+
const EventEmitter = require('events');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const commonPathPrefix = require('common-path-prefix');
|
|
6
|
+
const uniqueTempDir = require('unique-temp-dir');
|
|
7
|
+
const findCacheDir = require('find-cache-dir');
|
|
8
|
+
const resolveCwd = require('resolve-cwd');
|
|
9
|
+
const debounce = require('lodash.debounce');
|
|
10
|
+
const autoBind = require('auto-bind');
|
|
11
|
+
const Promise = require('bluebird');
|
|
12
|
+
const getPort = require('get-port');
|
|
13
|
+
const arrify = require('arrify');
|
|
14
|
+
const ms = require('ms');
|
|
15
|
+
const CachingPrecompiler = require('./lib/caching-precompiler');
|
|
16
|
+
const RunStatus = require('./lib/run-status');
|
|
17
|
+
const AvaError = require('./lib/ava-error');
|
|
18
|
+
const AvaFiles = require('./lib/ava-files');
|
|
19
|
+
const fork = require('./lib/fork');
|
|
20
|
+
|
|
21
|
+
function resolveModules(modules) {
|
|
22
|
+
return arrify(modules).map(name => {
|
|
23
|
+
const modulePath = resolveCwd(name);
|
|
24
|
+
|
|
25
|
+
if (modulePath === null) {
|
|
26
|
+
throw new Error(`Could not resolve required module '${name}'`);
|
|
36
27
|
}
|
|
37
28
|
|
|
38
|
-
return
|
|
29
|
+
return modulePath;
|
|
39
30
|
});
|
|
40
|
-
|
|
41
|
-
Object.keys(Api.prototype).forEach(function (key) {
|
|
42
|
-
this[key] = this[key].bind(this);
|
|
43
|
-
}, this);
|
|
44
31
|
}
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
runStatus.observeFork(emitter);
|
|
61
|
-
|
|
62
|
-
return emitter;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
Api.prototype._onTimeout = function (runStatus) {
|
|
66
|
-
var timeout = ms(this.options.timeout);
|
|
67
|
-
var message = 'Exited because no new tests completed within the last ' + timeout + 'ms of inactivity';
|
|
33
|
+
function getBlankResults() {
|
|
34
|
+
return {
|
|
35
|
+
stats: {
|
|
36
|
+
knownFailureCount: 0,
|
|
37
|
+
testCount: 0,
|
|
38
|
+
passCount: 0,
|
|
39
|
+
skipCount: 0,
|
|
40
|
+
todoCount: 0,
|
|
41
|
+
failCount: 0
|
|
42
|
+
},
|
|
43
|
+
tests: []
|
|
44
|
+
};
|
|
45
|
+
}
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
47
|
+
class Api extends EventEmitter {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
super();
|
|
50
|
+
autoBind(this);
|
|
73
51
|
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
this.options = Object.assign({match: []}, options);
|
|
53
|
+
this.options.require = resolveModules(this.options.require);
|
|
54
|
+
}
|
|
55
|
+
_runFile(file, runStatus, execArgv) {
|
|
56
|
+
const hash = this.precompiler.precompileFile(file);
|
|
57
|
+
const precompiled = Object.assign({}, this._precompiledHelpers);
|
|
58
|
+
const resolvedfpath = fs.realpathSync(file);
|
|
59
|
+
precompiled[resolvedfpath] = hash;
|
|
76
60
|
|
|
77
|
-
|
|
78
|
-
|
|
61
|
+
const options = Object.assign({}, this.options, {precompiled});
|
|
62
|
+
const emitter = fork(file, options, execArgv);
|
|
63
|
+
runStatus.observeFork(emitter);
|
|
79
64
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
65
|
+
return emitter;
|
|
66
|
+
}
|
|
67
|
+
run(files, options) {
|
|
68
|
+
return new AvaFiles({cwd: this.options.resolveTestsFrom, files})
|
|
69
|
+
.findTestFiles()
|
|
70
|
+
.then(files => this._run(files, options));
|
|
71
|
+
}
|
|
72
|
+
_onTimeout(runStatus) {
|
|
73
|
+
const timeout = ms(this.options.timeout);
|
|
74
|
+
const err = new AvaError(`Exited because no new tests completed within the last ${timeout}ms of inactivity`);
|
|
75
|
+
this._handleError(runStatus, err);
|
|
76
|
+
runStatus.emit('timeout');
|
|
77
|
+
}
|
|
78
|
+
_setupTimeout(runStatus) {
|
|
79
|
+
const timeout = ms(this.options.timeout);
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
runStatus._restartTimer = debounce(function () {
|
|
98
|
-
self._onTimeout(runStatus);
|
|
81
|
+
runStatus._restartTimer = debounce(() => {
|
|
82
|
+
this._onTimeout(runStatus);
|
|
99
83
|
}, timeout);
|
|
84
|
+
|
|
100
85
|
runStatus._restartTimer();
|
|
101
86
|
runStatus.on('test', runStatus._restartTimer);
|
|
102
87
|
}
|
|
88
|
+
_cancelTimeout(runStatus) {
|
|
89
|
+
runStatus._restartTimer.cancel();
|
|
90
|
+
}
|
|
91
|
+
_setupPrecompiler(files) {
|
|
92
|
+
const isCacheEnabled = this.options.cacheEnabled !== false;
|
|
93
|
+
let cacheDir = uniqueTempDir();
|
|
94
|
+
|
|
95
|
+
if (isCacheEnabled) {
|
|
96
|
+
const foundDir = findCacheDir({
|
|
97
|
+
name: 'ava',
|
|
98
|
+
files
|
|
99
|
+
});
|
|
100
|
+
if (foundDir !== null) {
|
|
101
|
+
cacheDir = foundDir;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
this.options.cacheDir = cacheDir;
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
const isPowerAssertEnabled = this.options.powerAssert !== false;
|
|
108
|
+
this.precompiler = new CachingPrecompiler({
|
|
109
|
+
path: cacheDir,
|
|
110
|
+
babel: this.options.babelConfig,
|
|
111
|
+
powerAssert: isPowerAssertEnabled
|
|
110
112
|
});
|
|
111
|
-
|
|
112
|
-
return Promise.resolve(runStatus);
|
|
113
113
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
} else {
|
|
129
|
-
// _runNoPool exists to preserve legacy behavior, specifically around `.only`
|
|
130
|
-
overwatch = this._runNoPool(files, runStatus);
|
|
114
|
+
_precompileHelpers() {
|
|
115
|
+
this._precompiledHelpers = {};
|
|
116
|
+
|
|
117
|
+
// Assumes the tests only load helpers from within the `resolveTestsFrom`
|
|
118
|
+
// directory. Without arguments this is the `projectDir`, else it's
|
|
119
|
+
// `process.cwd()` which may be nested too deeply. This will be solved
|
|
120
|
+
// as we implement RFC 001 and move helper compilation into the worker
|
|
121
|
+
// processes, avoiding the need for precompilation.
|
|
122
|
+
return new AvaFiles({cwd: this.options.resolveTestsFrom})
|
|
123
|
+
.findTestHelpers()
|
|
124
|
+
.map(file => { // eslint-disable-line array-callback-return
|
|
125
|
+
const hash = this.precompiler.precompileFile(file);
|
|
126
|
+
this._precompiledHelpers[file] = hash;
|
|
127
|
+
});
|
|
131
128
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// TODO: thid should be cleared at the end of the run
|
|
141
|
-
runStatus.on('timeout', function () {
|
|
142
|
-
tests.forEach(function (fork) {
|
|
143
|
-
fork.exit();
|
|
129
|
+
_run(files, options) {
|
|
130
|
+
options = options || {};
|
|
131
|
+
|
|
132
|
+
const runStatus = new RunStatus({
|
|
133
|
+
runOnlyExclusive: options.runOnlyExclusive,
|
|
134
|
+
prefixTitles: this.options.explicitTitles || files.length > 1,
|
|
135
|
+
base: path.relative(process.cwd(), commonPathPrefix(files)) + path.sep,
|
|
136
|
+
failFast: this.options.failFast
|
|
144
137
|
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
return new Promise(function (resolve) {
|
|
148
|
-
function run() {
|
|
149
|
-
if (self.options.match.length > 0 && !runStatus.hasExclusive) {
|
|
150
|
-
runStatus.handleExceptions({
|
|
151
|
-
exception: new AvaError('Couldn\'t find any matching tests'),
|
|
152
|
-
file: undefined
|
|
153
|
-
});
|
|
154
138
|
|
|
155
|
-
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
139
|
+
this.emit('test-run', runStatus, files);
|
|
158
140
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
resolve(Promise[method](files, function (file, index) {
|
|
165
|
-
return tests[index].run(options).catch(function (err) {
|
|
166
|
-
// The test failed catastrophically. Flag it up as an
|
|
167
|
-
// exception, then return an empty result. Other tests may
|
|
168
|
-
// continue to run.
|
|
169
|
-
runStatus.handleExceptions({
|
|
170
|
-
exception: err,
|
|
171
|
-
file: path.relative('.', file)
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
return getBlankResults();
|
|
175
|
-
});
|
|
176
|
-
}));
|
|
141
|
+
if (files.length === 0) {
|
|
142
|
+
const err = new AvaError('Couldn\'t find any files to test');
|
|
143
|
+
this._handleError(runStatus, err);
|
|
144
|
+
return Promise.resolve(runStatus);
|
|
177
145
|
}
|
|
178
146
|
|
|
179
|
-
|
|
180
|
-
var unreportedFiles = self.fileCount;
|
|
181
|
-
var bailed = false;
|
|
182
|
-
|
|
183
|
-
files.every(function (file, index) {
|
|
184
|
-
var tried = false;
|
|
147
|
+
this._setupPrecompiler(files);
|
|
185
148
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
149
|
+
return this._precompileHelpers()
|
|
150
|
+
.then(() => {
|
|
151
|
+
if (this.options.timeout) {
|
|
152
|
+
this._setupTimeout(runStatus);
|
|
153
|
+
}
|
|
190
154
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
155
|
+
let overwatch;
|
|
156
|
+
if (this.options.concurrency > 0) {
|
|
157
|
+
const concurrency = this.options.serial ? 1 : this.options.concurrency;
|
|
158
|
+
overwatch = this._runWithPool(files, runStatus, concurrency);
|
|
159
|
+
} else {
|
|
160
|
+
// _runWithoutPool exists to preserve legacy behavior, specifically around `.only`
|
|
161
|
+
overwatch = this._runWithoutPool(files, runStatus);
|
|
194
162
|
}
|
|
163
|
+
|
|
164
|
+
return overwatch;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
_computeForkExecArgs(files) {
|
|
168
|
+
const execArgv = this.options.testOnlyExecArgv || process.execArgv;
|
|
169
|
+
let debugArgIndex = -1;
|
|
170
|
+
|
|
171
|
+
// --debug-brk is used in addition to --inspect to break on first line and wait
|
|
172
|
+
execArgv.some((arg, index) => {
|
|
173
|
+
const isDebugArg = arg === '--inspect' || arg.indexOf('--inspect=') === 0;
|
|
174
|
+
if (isDebugArg) {
|
|
175
|
+
debugArgIndex = index;
|
|
195
176
|
}
|
|
196
177
|
|
|
197
|
-
|
|
198
|
-
|
|
178
|
+
return isDebugArg;
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const isInspect = debugArgIndex >= 0;
|
|
182
|
+
if (!isInspect) {
|
|
183
|
+
execArgv.some((arg, index) => {
|
|
184
|
+
const isDebugArg = arg === '--debug' || arg === '--debug-brk' || arg.indexOf('--debug-brk=') === 0 || arg.indexOf('--debug=') === 0;
|
|
185
|
+
if (isDebugArg) {
|
|
186
|
+
debugArgIndex = index;
|
|
187
|
+
}
|
|
199
188
|
|
|
200
|
-
|
|
201
|
-
|
|
189
|
+
return isDebugArg;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
202
192
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
193
|
+
if (debugArgIndex === -1) {
|
|
194
|
+
return Promise.resolve([]);
|
|
195
|
+
}
|
|
206
196
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
197
|
+
return Promise
|
|
198
|
+
.map(files, getPort)
|
|
199
|
+
.map(port => {
|
|
200
|
+
const forkExecArgv = execArgv.slice();
|
|
201
|
+
let flagName = isInspect ? '--inspect' : '--debug';
|
|
202
|
+
const oldValue = forkExecArgv[debugArgIndex];
|
|
203
|
+
if (oldValue.indexOf('brk') > 0) {
|
|
204
|
+
flagName += '-brk';
|
|
205
|
+
}
|
|
211
206
|
|
|
212
|
-
|
|
207
|
+
forkExecArgv[debugArgIndex] = `${flagName}=${port}`;
|
|
213
208
|
|
|
214
|
-
return
|
|
215
|
-
}
|
|
209
|
+
return forkExecArgv;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
_handleError(runStatus, err) {
|
|
213
|
+
runStatus.handleExceptions({
|
|
214
|
+
exception: err,
|
|
215
|
+
file: err.file ? path.relative(process.cwd(), err.file) : undefined
|
|
216
216
|
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
}
|
|
218
|
+
_runWithoutPool(files, runStatus) {
|
|
219
|
+
const tests = [];
|
|
220
|
+
let execArgvList;
|
|
221
|
+
|
|
222
|
+
// TODO: This should be cleared at the end of the run
|
|
223
|
+
runStatus.on('timeout', () => {
|
|
224
|
+
tests.forEach(fork => {
|
|
225
|
+
fork.exit();
|
|
222
226
|
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return results;
|
|
226
|
-
}).then(function (results) {
|
|
227
|
-
// cancel debounced _onTimeout() from firing
|
|
228
|
-
if (self.options.timeout) {
|
|
229
|
-
runStatus._restartTimer.cancel();
|
|
230
|
-
}
|
|
227
|
+
});
|
|
231
228
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
229
|
+
return this._computeForkExecArgs(files)
|
|
230
|
+
.then(argvList => {
|
|
231
|
+
execArgvList = argvList;
|
|
232
|
+
})
|
|
233
|
+
.return(files)
|
|
234
|
+
.each((file, index) => {
|
|
235
|
+
return new Promise(resolve => {
|
|
236
|
+
const forkArgs = execArgvList[index];
|
|
237
|
+
const test = this._runFile(file, runStatus, forkArgs);
|
|
238
|
+
tests.push(test);
|
|
239
|
+
test.on('stats', resolve);
|
|
240
|
+
test.catch(resolve);
|
|
241
|
+
}).catch(err => {
|
|
242
|
+
err.results = [];
|
|
243
|
+
err.file = file;
|
|
244
|
+
return Promise.reject(err);
|
|
245
|
+
});
|
|
246
|
+
})
|
|
247
|
+
.then(() => {
|
|
248
|
+
if (this.options.match.length > 0 && !runStatus.hasExclusive) {
|
|
249
|
+
const err = new AvaError('Couldn\'t find any matching tests');
|
|
250
|
+
err.file = undefined;
|
|
251
|
+
err.results = [];
|
|
252
|
+
return Promise.reject(err);
|
|
253
|
+
}
|
|
236
254
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
passCount: 0,
|
|
242
|
-
knownFailureCount: 0,
|
|
243
|
-
skipCount: 0,
|
|
244
|
-
todoCount: 0,
|
|
245
|
-
failCount: 0
|
|
246
|
-
},
|
|
247
|
-
tests: []
|
|
248
|
-
};
|
|
249
|
-
}
|
|
255
|
+
const method = this.options.serial ? 'mapSeries' : 'map';
|
|
256
|
+
const options = {
|
|
257
|
+
runOnlyExclusive: runStatus.hasExclusive
|
|
258
|
+
};
|
|
250
259
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
return Promise[method](files, (file, index) => {
|
|
261
|
+
return tests[index].run(options).catch(err => {
|
|
262
|
+
err.file = file;
|
|
263
|
+
this._handleError(runStatus, err);
|
|
264
|
+
return getBlankResults();
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
})
|
|
268
|
+
.catch(err => {
|
|
269
|
+
this._handleError(runStatus, err);
|
|
270
|
+
return err.results;
|
|
271
|
+
})
|
|
272
|
+
.tap(results => {
|
|
273
|
+
// If no tests ran, make sure to tear down the child processes
|
|
274
|
+
if (results.length === 0) {
|
|
275
|
+
tests.forEach(test => {
|
|
276
|
+
test.send('teardown');
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
.then(results => {
|
|
281
|
+
// Cancel debounced _onTimeout() from firing
|
|
282
|
+
if (this.options.timeout) {
|
|
283
|
+
this._cancelTimeout(runStatus);
|
|
284
|
+
}
|
|
254
285
|
|
|
255
|
-
|
|
256
|
-
Object.keys(tests).forEach(function (file) {
|
|
257
|
-
var fork = tests[file];
|
|
258
|
-
fork.exit();
|
|
259
|
-
});
|
|
260
|
-
});
|
|
286
|
+
runStatus.processResults(results);
|
|
261
287
|
|
|
262
|
-
|
|
263
|
-
var handleException = function (err) {
|
|
264
|
-
runStatus.handleExceptions({
|
|
265
|
-
exception: err,
|
|
266
|
-
file: path.relative('.', file)
|
|
288
|
+
return runStatus;
|
|
267
289
|
});
|
|
268
|
-
|
|
290
|
+
}
|
|
291
|
+
_runWithPool(files, runStatus, concurrency) {
|
|
292
|
+
const tests = [];
|
|
293
|
+
let execArgvList;
|
|
269
294
|
|
|
270
|
-
|
|
271
|
-
|
|
295
|
+
runStatus.on('timeout', () => {
|
|
296
|
+
tests.forEach(fork => {
|
|
297
|
+
fork.exit();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
272
300
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
301
|
+
return this._computeForkExecArgs(files)
|
|
302
|
+
.then(argvList => {
|
|
303
|
+
execArgvList = argvList;
|
|
304
|
+
})
|
|
305
|
+
.return(files)
|
|
306
|
+
.map((file, index) => {
|
|
307
|
+
return new Promise(resolve => {
|
|
308
|
+
const forkArgs = execArgvList[index];
|
|
309
|
+
const test = this._runFile(file, runStatus, forkArgs);
|
|
310
|
+
tests.push(test);
|
|
311
|
+
|
|
312
|
+
// If we're looking for matches, run every single test process in exclusive-only mode
|
|
313
|
+
const options = {
|
|
314
|
+
runOnlyExclusive: this.options.match.length > 0
|
|
278
315
|
};
|
|
279
|
-
test.run(options)
|
|
280
|
-
.then(resolve)
|
|
281
|
-
.catch(reject);
|
|
282
|
-
};
|
|
283
316
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
317
|
+
resolve(test.run(options));
|
|
318
|
+
}).catch(err => {
|
|
319
|
+
err.file = file;
|
|
320
|
+
this._handleError(runStatus, err);
|
|
321
|
+
return getBlankResults();
|
|
287
322
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
// cancel debounced _onTimeout() from firing
|
|
299
|
-
if (self.options.timeout) {
|
|
300
|
-
runStatus._restartTimer.cancel();
|
|
301
|
-
}
|
|
323
|
+
}, {concurrency})
|
|
324
|
+
.then(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 (this.options.timeout) {
|
|
330
|
+
this._cancelTimeout(runStatus);
|
|
331
|
+
}
|
|
302
332
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
results = [];
|
|
306
|
-
runStatus.handleExceptions({
|
|
307
|
-
exception: new AvaError('Couldn\'t find any matching tests'),
|
|
308
|
-
file: undefined
|
|
309
|
-
});
|
|
310
|
-
}
|
|
333
|
+
if (this.options.match.length > 0 && !runStatus.hasExclusive) {
|
|
334
|
+
results = [];
|
|
311
335
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
336
|
+
const err = new AvaError('Couldn\'t find any matching tests');
|
|
337
|
+
this._handleError(runStatus, err);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
runStatus.processResults(results);
|
|
341
|
+
|
|
342
|
+
return runStatus;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
module.exports = Api;
|