ava 0.21.0 → 0.25.0
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 +20 -79
- package/cli.js +1 -1
- package/index.js.flow +3 -1
- package/lib/assert.js +40 -8
- package/lib/ava-files.js +5 -0
- package/lib/babel-config.js +8 -0
- package/lib/beautify-stack.js +43 -8
- package/lib/caching-precompiler.js +6 -3
- package/lib/cli.js +10 -4
- package/lib/colors.js +1 -0
- package/lib/enhance-assert.js +4 -18
- package/lib/fork.js +1 -3
- package/lib/logger.js +11 -0
- package/lib/main.js +2 -3
- package/lib/process-adapter.js +2 -2
- package/lib/reporters/improper-usage-messages.js +3 -1
- package/lib/reporters/mini.js +42 -11
- package/lib/reporters/tap.js +33 -59
- package/lib/reporters/verbose.js +55 -21
- package/lib/run-status.js +9 -0
- package/lib/runner.js +6 -1
- package/lib/serialize-error.js +7 -2
- package/lib/snapshot-manager.js +26 -4
- package/lib/test-collection.js +28 -4
- package/lib/test-worker.js +10 -9
- package/lib/test.js +10 -0
- package/lib/watcher.js +19 -1
- package/package.json +31 -58
- package/readme.md +49 -14
- package/types/generated.d.ts +12 -0
- package/lib/extract-stack.js +0 -10
package/api.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
const EventEmitter = require('events');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
5
6
|
const commonPathPrefix = require('common-path-prefix');
|
|
6
7
|
const uniqueTempDir = require('unique-temp-dir');
|
|
7
8
|
const findCacheDir = require('find-cache-dir');
|
|
9
|
+
const isCi = require('is-ci');
|
|
8
10
|
const resolveCwd = require('resolve-cwd');
|
|
9
11
|
const debounce = require('lodash.debounce');
|
|
10
12
|
const autoBind = require('auto-bind');
|
|
@@ -53,6 +55,7 @@ class Api extends EventEmitter {
|
|
|
53
55
|
this.options = Object.assign({match: []}, options);
|
|
54
56
|
this.options.require = resolveModules(this.options.require);
|
|
55
57
|
}
|
|
58
|
+
|
|
56
59
|
_runFile(file, runStatus, execArgv) {
|
|
57
60
|
const hash = this.precompiler.precompileFile(file);
|
|
58
61
|
const precompiled = Object.assign({}, this._precompiledHelpers);
|
|
@@ -69,17 +72,20 @@ class Api extends EventEmitter {
|
|
|
69
72
|
|
|
70
73
|
return emitter;
|
|
71
74
|
}
|
|
75
|
+
|
|
72
76
|
run(files, options) {
|
|
73
77
|
return new AvaFiles({cwd: this.options.resolveTestsFrom, files})
|
|
74
78
|
.findTestFiles()
|
|
75
79
|
.then(files => this._run(files, options));
|
|
76
80
|
}
|
|
81
|
+
|
|
77
82
|
_onTimeout(runStatus) {
|
|
78
83
|
const timeout = ms(this.options.timeout);
|
|
79
84
|
const err = new AvaError(`Exited because no new tests completed within the last ${timeout}ms of inactivity`);
|
|
80
85
|
this._handleError(runStatus, err);
|
|
81
86
|
runStatus.emit('timeout');
|
|
82
87
|
}
|
|
88
|
+
|
|
83
89
|
_setupTimeout(runStatus) {
|
|
84
90
|
const timeout = ms(this.options.timeout);
|
|
85
91
|
|
|
@@ -90,9 +96,11 @@ class Api extends EventEmitter {
|
|
|
90
96
|
runStatus._restartTimer();
|
|
91
97
|
runStatus.on('test', runStatus._restartTimer);
|
|
92
98
|
}
|
|
99
|
+
|
|
93
100
|
_cancelTimeout(runStatus) {
|
|
94
101
|
runStatus._restartTimer.cancel();
|
|
95
102
|
}
|
|
103
|
+
|
|
96
104
|
_setupPrecompiler(files) {
|
|
97
105
|
const isCacheEnabled = this.options.cacheEnabled !== false;
|
|
98
106
|
let cacheDir = uniqueTempDir();
|
|
@@ -119,6 +127,7 @@ class Api extends EventEmitter {
|
|
|
119
127
|
});
|
|
120
128
|
});
|
|
121
129
|
}
|
|
130
|
+
|
|
122
131
|
_precompileHelpers() {
|
|
123
132
|
this._precompiledHelpers = {};
|
|
124
133
|
|
|
@@ -134,6 +143,7 @@ class Api extends EventEmitter {
|
|
|
134
143
|
this._precompiledHelpers[file] = hash;
|
|
135
144
|
});
|
|
136
145
|
}
|
|
146
|
+
|
|
137
147
|
_run(files, options) {
|
|
138
148
|
options = options || {};
|
|
139
149
|
|
|
@@ -160,18 +170,20 @@ class Api extends EventEmitter {
|
|
|
160
170
|
this._setupTimeout(runStatus);
|
|
161
171
|
}
|
|
162
172
|
|
|
163
|
-
let
|
|
173
|
+
let concurrency = Math.min(os.cpus().length, isCi ? 2 : Infinity);
|
|
174
|
+
|
|
164
175
|
if (this.options.concurrency > 0) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
concurrency = this.options.concurrency;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (this.options.serial) {
|
|
180
|
+
concurrency = 1;
|
|
170
181
|
}
|
|
171
182
|
|
|
172
|
-
return
|
|
183
|
+
return this._runWithPool(files, runStatus, concurrency);
|
|
173
184
|
});
|
|
174
185
|
}
|
|
186
|
+
|
|
175
187
|
_computeForkExecArgs(files) {
|
|
176
188
|
const execArgv = this.options.testOnlyExecArgv || process.execArgv;
|
|
177
189
|
let debugArgIndex = -1;
|
|
@@ -217,85 +229,14 @@ class Api extends EventEmitter {
|
|
|
217
229
|
return forkExecArgv;
|
|
218
230
|
});
|
|
219
231
|
}
|
|
232
|
+
|
|
220
233
|
_handleError(runStatus, err) {
|
|
221
234
|
runStatus.handleExceptions({
|
|
222
235
|
exception: err,
|
|
223
236
|
file: err.file ? path.relative(process.cwd(), err.file) : undefined
|
|
224
237
|
});
|
|
225
238
|
}
|
|
226
|
-
_runWithoutPool(files, runStatus) {
|
|
227
|
-
const tests = [];
|
|
228
|
-
let execArgvList;
|
|
229
|
-
|
|
230
|
-
// TODO: This should be cleared at the end of the run
|
|
231
|
-
runStatus.on('timeout', () => {
|
|
232
|
-
tests.forEach(fork => {
|
|
233
|
-
fork.exit();
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
239
|
|
|
237
|
-
return this._computeForkExecArgs(files)
|
|
238
|
-
.then(argvList => {
|
|
239
|
-
execArgvList = argvList;
|
|
240
|
-
})
|
|
241
|
-
.return(files)
|
|
242
|
-
.each((file, index) => {
|
|
243
|
-
return new Promise(resolve => {
|
|
244
|
-
const forkArgs = execArgvList[index];
|
|
245
|
-
const test = this._runFile(file, runStatus, forkArgs);
|
|
246
|
-
tests.push(test);
|
|
247
|
-
test.on('stats', resolve);
|
|
248
|
-
test.catch(resolve);
|
|
249
|
-
}).catch(err => {
|
|
250
|
-
err.results = [];
|
|
251
|
-
err.file = file;
|
|
252
|
-
return Promise.reject(err);
|
|
253
|
-
});
|
|
254
|
-
})
|
|
255
|
-
.then(() => {
|
|
256
|
-
if (this.options.match.length > 0 && !runStatus.hasExclusive) {
|
|
257
|
-
const err = new AvaError('Couldn\'t find any matching tests');
|
|
258
|
-
err.file = undefined;
|
|
259
|
-
err.results = [];
|
|
260
|
-
return Promise.reject(err);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const method = this.options.serial ? 'mapSeries' : 'map';
|
|
264
|
-
const options = {
|
|
265
|
-
runOnlyExclusive: runStatus.hasExclusive
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
return Promise[method](files, (file, index) => {
|
|
269
|
-
return tests[index].run(options).catch(err => {
|
|
270
|
-
err.file = file;
|
|
271
|
-
this._handleError(runStatus, err);
|
|
272
|
-
return getBlankResults();
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
})
|
|
276
|
-
.catch(err => {
|
|
277
|
-
this._handleError(runStatus, err);
|
|
278
|
-
return err.results;
|
|
279
|
-
})
|
|
280
|
-
.tap(results => {
|
|
281
|
-
// If no tests ran, make sure to tear down the child processes
|
|
282
|
-
if (results.length === 0) {
|
|
283
|
-
tests.forEach(test => {
|
|
284
|
-
test.send('teardown');
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
})
|
|
288
|
-
.then(results => {
|
|
289
|
-
// Cancel debounced _onTimeout() from firing
|
|
290
|
-
if (this.options.timeout) {
|
|
291
|
-
this._cancelTimeout(runStatus);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
runStatus.processResults(results);
|
|
295
|
-
|
|
296
|
-
return runStatus;
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
240
|
_runWithPool(files, runStatus, concurrency) {
|
|
300
241
|
const tests = [];
|
|
301
242
|
let execArgvList;
|
package/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ if (importLocal(__filename)) {
|
|
|
8
8
|
debug('Using local install of AVA');
|
|
9
9
|
} else {
|
|
10
10
|
if (debug.enabled) {
|
|
11
|
-
require('time-require'); // eslint-disable-line import/no-unassigned-import
|
|
11
|
+
require('@ladjs/time-require'); // eslint-disable-line import/no-unassigned-import
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
try {
|
package/index.js.flow
CHANGED
|
@@ -69,7 +69,7 @@ type AssertContext = {
|
|
|
69
69
|
// Assert that contents matches regex.
|
|
70
70
|
regex(contents: string, regex: RegExp, message?: string): void;
|
|
71
71
|
// Assert that contents matches a snapshot.
|
|
72
|
-
snapshot(contents: any, message?: string): void;
|
|
72
|
+
snapshot: ((contents: any, message?: string) => void) & ((contents: any, options: {id: string}, message?: string) => void);
|
|
73
73
|
// Assert that contents does not match regex.
|
|
74
74
|
notRegex(contents: string, regex: RegExp, message?: string): void;
|
|
75
75
|
// Assert that error is falsy.
|
|
@@ -81,8 +81,10 @@ type AssertContext = {
|
|
|
81
81
|
*/
|
|
82
82
|
|
|
83
83
|
type TestContext = AssertContext & {
|
|
84
|
+
title: string;
|
|
84
85
|
plan(count: number): void;
|
|
85
86
|
skip: AssertContext;
|
|
87
|
+
log(...values: Array<any>): void;
|
|
86
88
|
};
|
|
87
89
|
type ContextualTestContext = TestContext & { context: any; };
|
|
88
90
|
type ContextualCallbackTestContext = TestContext & { context: any; end(): void; };
|
package/lib/assert.js
CHANGED
|
@@ -49,14 +49,22 @@ class AssertionError extends Error {
|
|
|
49
49
|
|
|
50
50
|
if (opts.stack) {
|
|
51
51
|
this.stack = opts.stack;
|
|
52
|
+
} else {
|
|
53
|
+
const limitBefore = Error.stackTraceLimit;
|
|
54
|
+
Error.stackTraceLimit = Infinity;
|
|
55
|
+
Error.captureStackTrace(this);
|
|
56
|
+
Error.stackTraceLimit = limitBefore;
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
exports.AssertionError = AssertionError;
|
|
56
61
|
|
|
57
62
|
function getStack() {
|
|
63
|
+
const limitBefore = Error.stackTraceLimit;
|
|
64
|
+
Error.stackTraceLimit = Infinity;
|
|
58
65
|
const obj = {};
|
|
59
66
|
Error.captureStackTrace(obj, getStack);
|
|
67
|
+
Error.stackTraceLimit = limitBefore;
|
|
60
68
|
return obj.stack;
|
|
61
69
|
}
|
|
62
70
|
|
|
@@ -64,6 +72,7 @@ function wrapAssertions(callbacks) {
|
|
|
64
72
|
const pass = callbacks.pass;
|
|
65
73
|
const pending = callbacks.pending;
|
|
66
74
|
const fail = callbacks.fail;
|
|
75
|
+
const log = callbacks.log;
|
|
67
76
|
|
|
68
77
|
const noop = () => {};
|
|
69
78
|
const makeRethrow = reason => () => {
|
|
@@ -86,14 +95,25 @@ function wrapAssertions(callbacks) {
|
|
|
86
95
|
if (Object.is(actual, expected)) {
|
|
87
96
|
pass(this);
|
|
88
97
|
} else {
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
const result = concordance.compare(actual, expected, concordanceOptions);
|
|
99
|
+
const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
|
|
100
|
+
const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
|
|
101
|
+
|
|
102
|
+
if (result.pass) {
|
|
103
|
+
fail(this, new AssertionError({
|
|
104
|
+
assertion: 'is',
|
|
105
|
+
message,
|
|
106
|
+
raw: {actual, expected},
|
|
107
|
+
values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)]
|
|
108
|
+
}));
|
|
109
|
+
} else {
|
|
110
|
+
fail(this, new AssertionError({
|
|
111
|
+
assertion: 'is',
|
|
112
|
+
message,
|
|
113
|
+
raw: {actual, expected},
|
|
114
|
+
values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
97
117
|
}
|
|
98
118
|
},
|
|
99
119
|
|
|
@@ -110,6 +130,18 @@ function wrapAssertions(callbacks) {
|
|
|
110
130
|
}
|
|
111
131
|
},
|
|
112
132
|
|
|
133
|
+
log() {
|
|
134
|
+
const args = Array.from(arguments, value => {
|
|
135
|
+
return typeof value === 'string' ?
|
|
136
|
+
value :
|
|
137
|
+
concordance.format(value, concordanceOptions);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (args.length > 0) {
|
|
141
|
+
log(this, args.join(' '));
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
113
145
|
deepEqual(actual, expected, message) {
|
|
114
146
|
const result = concordance.compare(actual, expected, concordanceOptions);
|
|
115
147
|
if (result.pass) {
|
package/lib/ava-files.js
CHANGED
|
@@ -125,6 +125,7 @@ class AvaFiles {
|
|
|
125
125
|
|
|
126
126
|
autoBind(this);
|
|
127
127
|
}
|
|
128
|
+
|
|
128
129
|
findTestFiles() {
|
|
129
130
|
return handlePaths(this.files, this.excludePatterns, {
|
|
130
131
|
cwd: this.cwd,
|
|
@@ -134,6 +135,7 @@ class AvaFiles {
|
|
|
134
135
|
symlinks: Object.create(null)
|
|
135
136
|
});
|
|
136
137
|
}
|
|
138
|
+
|
|
137
139
|
findTestHelpers() {
|
|
138
140
|
return handlePaths(defaultHelperPatterns(), ['!**/node_modules/**'], {
|
|
139
141
|
cwd: this.cwd,
|
|
@@ -144,6 +146,7 @@ class AvaFiles {
|
|
|
144
146
|
symlinks: Object.create(null)
|
|
145
147
|
});
|
|
146
148
|
}
|
|
149
|
+
|
|
147
150
|
isSource(filePath) {
|
|
148
151
|
let mixedPatterns = [];
|
|
149
152
|
const defaultIgnorePatterns = getDefaultIgnorePatterns();
|
|
@@ -195,6 +198,7 @@ class AvaFiles {
|
|
|
195
198
|
|
|
196
199
|
return false;
|
|
197
200
|
}
|
|
201
|
+
|
|
198
202
|
isTest(filePath) {
|
|
199
203
|
const excludePatterns = this.excludePatterns;
|
|
200
204
|
const initialPatterns = this.files.concat(excludePatterns);
|
|
@@ -241,6 +245,7 @@ class AvaFiles {
|
|
|
241
245
|
// excludePatterns into account. This mimicks the behavior in api.js
|
|
242
246
|
return multimatch(matchable(filePath), recursivePatterns.concat(excludePatterns)).length === 1;
|
|
243
247
|
}
|
|
248
|
+
|
|
244
249
|
getChokidarPatterns() {
|
|
245
250
|
let paths = [];
|
|
246
251
|
let ignored = [];
|
package/lib/babel-config.js
CHANGED
|
@@ -6,6 +6,7 @@ const figures = require('figures');
|
|
|
6
6
|
const configManager = require('hullabaloo-config-manager');
|
|
7
7
|
const md5Hex = require('md5-hex');
|
|
8
8
|
const makeDir = require('make-dir');
|
|
9
|
+
const semver = require('semver');
|
|
9
10
|
const colors = require('./colors');
|
|
10
11
|
|
|
11
12
|
function validate(conf) {
|
|
@@ -99,6 +100,7 @@ function build(projectDir, cacheDir, userOptions, powerAssert) {
|
|
|
99
100
|
|
|
100
101
|
const baseOptions = {
|
|
101
102
|
babelrc: false,
|
|
103
|
+
plugins: [],
|
|
102
104
|
presets: [
|
|
103
105
|
['@ava/transform-test-files', {powerAssert}]
|
|
104
106
|
]
|
|
@@ -107,6 +109,12 @@ function build(projectDir, cacheDir, userOptions, powerAssert) {
|
|
|
107
109
|
baseOptions.presets.unshift('@ava/stage-4');
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
// Include object rest spread support for node versions that support it
|
|
113
|
+
// natively.
|
|
114
|
+
if (userOptions === 'default' && semver.satisfies(process.versions.node, '>= 8.3.0')) {
|
|
115
|
+
baseOptions.plugins.push('babel-plugin-syntax-object-rest-spread');
|
|
116
|
+
}
|
|
117
|
+
|
|
110
118
|
const baseConfig = configManager.createConfig({
|
|
111
119
|
dir: AVA_DIR, // Presets are resolved relative to this directory
|
|
112
120
|
hash: md5Hex(JSON.stringify(baseOptions)),
|
package/lib/beautify-stack.js
CHANGED
|
@@ -8,6 +8,7 @@ let ignoreStackLines = [];
|
|
|
8
8
|
|
|
9
9
|
const avaInternals = /\/ava\/(?:lib\/)?[\w-]+\.js:\d+:\d+\)?$/;
|
|
10
10
|
const avaDependencies = /\/node_modules\/(?:bluebird|empower-core|(?:ava\/node_modules\/)?(?:babel-runtime|core-js))\//;
|
|
11
|
+
const stackFrameLine = /^.+( \(.+:\d+:\d+\)|:\d+:\d+)$/;
|
|
11
12
|
|
|
12
13
|
if (!debug.enabled) {
|
|
13
14
|
ignoreStackLines = StackUtils.nodeInternals();
|
|
@@ -17,21 +18,55 @@ if (!debug.enabled) {
|
|
|
17
18
|
|
|
18
19
|
const stackUtils = new StackUtils({internals: ignoreStackLines});
|
|
19
20
|
|
|
21
|
+
function extractFrames(stack) {
|
|
22
|
+
return stack
|
|
23
|
+
.split('\n')
|
|
24
|
+
.map(line => line.trim())
|
|
25
|
+
.filter(line => stackFrameLine.test(line))
|
|
26
|
+
.join('\n');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Given a string value of the format generated for the `stack` property of a
|
|
31
|
+
* V8 error object, return a string that contains only stack frame information
|
|
32
|
+
* for frames that have relevance to the consumer.
|
|
33
|
+
*
|
|
34
|
+
* For example, given the following string value:
|
|
35
|
+
*
|
|
36
|
+
* ```
|
|
37
|
+
* Error
|
|
38
|
+
* at inner (/home/ava/ex.js:7:12)
|
|
39
|
+
* at /home/ava/ex.js:12:5
|
|
40
|
+
* at outer (/home/ava/ex.js:13:4)
|
|
41
|
+
* at Object.<anonymous> (/home/ava/ex.js:14:3)
|
|
42
|
+
* at Module._compile (module.js:570:32)
|
|
43
|
+
* at Object.Module._extensions..js (module.js:579:10)
|
|
44
|
+
* at Module.load (module.js:487:32)
|
|
45
|
+
* at tryModuleLoad (module.js:446:12)
|
|
46
|
+
* at Function.Module._load (module.js:438:3)
|
|
47
|
+
* at Module.runMain (module.js:604:10)
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* ...this function returns the following string value:
|
|
51
|
+
*
|
|
52
|
+
* ```
|
|
53
|
+
* inner (/home/ava/ex.js:7:12)
|
|
54
|
+
* /home/ava/ex.js:12:5
|
|
55
|
+
* outer (/home/ava/ex.js:13:4)
|
|
56
|
+
* Object.<anonymous> (/home/ava/ex.js:14:3)
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
20
59
|
module.exports = stack => {
|
|
21
60
|
if (!stack) {
|
|
22
61
|
return '';
|
|
23
62
|
}
|
|
24
63
|
|
|
64
|
+
stack = extractFrames(stack);
|
|
25
65
|
// Workaround for https://github.com/tapjs/stack-utils/issues/14
|
|
26
66
|
// TODO: fix it in `stack-utils`
|
|
27
67
|
stack = cleanStack(stack);
|
|
28
68
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
.split('\n')
|
|
33
|
-
.map(x => ` ${x}`)
|
|
34
|
-
.join('\n');
|
|
35
|
-
|
|
36
|
-
return `${title}\n${lines}`;
|
|
69
|
+
return stackUtils.clean(stack)
|
|
70
|
+
// Remove the trailing newline inserted by the `stack-utils` module
|
|
71
|
+
.trim();
|
|
37
72
|
};
|
|
@@ -33,6 +33,7 @@ class CachingPrecompiler {
|
|
|
33
33
|
this.fileHashes = {};
|
|
34
34
|
this.transform = this._createTransform();
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
precompileFile(filePath) {
|
|
37
38
|
if (!this.fileHashes[filePath]) {
|
|
38
39
|
const source = stripBomBuf(fs.readFileSync(filePath));
|
|
@@ -41,11 +42,13 @@ class CachingPrecompiler {
|
|
|
41
42
|
|
|
42
43
|
return this.fileHashes[filePath];
|
|
43
44
|
}
|
|
45
|
+
|
|
44
46
|
// Conditionally called by caching-transform when precompiling is required
|
|
45
47
|
_init() {
|
|
46
48
|
this.babel = require('babel-core');
|
|
47
49
|
return this._transform;
|
|
48
50
|
}
|
|
51
|
+
|
|
49
52
|
_transform(code, filePath, hash) {
|
|
50
53
|
code = code.toString();
|
|
51
54
|
|
|
@@ -73,12 +76,11 @@ class CachingPrecompiler {
|
|
|
73
76
|
|
|
74
77
|
// Append source map comment to transformed code
|
|
75
78
|
// So that other libraries (like nyc) can find the source map
|
|
76
|
-
const
|
|
77
|
-
const relativeMapPath = path.relative(dirPath, mapPath);
|
|
78
|
-
const comment = convertSourceMap.generateMapFileComment(relativeMapPath);
|
|
79
|
+
const comment = convertSourceMap.generateMapFileComment(mapPath);
|
|
79
80
|
|
|
80
81
|
return `${result.code}\n${comment}`;
|
|
81
82
|
}
|
|
83
|
+
|
|
82
84
|
_createTransform() {
|
|
83
85
|
const salt = packageHash.sync([
|
|
84
86
|
require.resolve('../package.json'),
|
|
@@ -93,6 +95,7 @@ class CachingPrecompiler {
|
|
|
93
95
|
ext: '.js'
|
|
94
96
|
});
|
|
95
97
|
}
|
|
98
|
+
|
|
96
99
|
_generateHash(code, filePath, salt) {
|
|
97
100
|
const hash = md5Hex([code, filePath, salt]);
|
|
98
101
|
this.fileHashes[filePath] = hash;
|
package/lib/cli.js
CHANGED
|
@@ -43,7 +43,7 @@ exports.run = () => {
|
|
|
43
43
|
--match, -m Only run tests with matching title (Can be repeated)
|
|
44
44
|
--watch, -w Re-run tests when tests and source files change
|
|
45
45
|
--timeout, -T Set global timeout
|
|
46
|
-
--concurrency, -c
|
|
46
|
+
--concurrency, -c Max number of test files running at the same time (Default: CPU cores)
|
|
47
47
|
--update-snapshots, -u Update snapshots
|
|
48
48
|
|
|
49
49
|
Examples
|
|
@@ -75,7 +75,7 @@ exports.run = () => {
|
|
|
75
75
|
],
|
|
76
76
|
default: {
|
|
77
77
|
cache: conf.cache,
|
|
78
|
-
color: 'color' in conf ? conf.color : require('supports-color') !== false,
|
|
78
|
+
color: 'color' in conf ? conf.color : require('supports-color').stdout !== false,
|
|
79
79
|
concurrency: conf.concurrency,
|
|
80
80
|
failFast: conf.failFast,
|
|
81
81
|
init: conf.init,
|
|
@@ -119,7 +119,12 @@ exports.run = () => {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
if (cli.flags.concurrency === '') {
|
|
122
|
-
throw new Error(colors.error(figures.cross) + ' The --concurrency and -c flags must be provided
|
|
122
|
+
throw new Error(colors.error(figures.cross) + ' The --concurrency and -c flags must be provided.');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (cli.flags.concurrency &&
|
|
126
|
+
(!Number.isInteger(Number.parseFloat(cli.flags.concurrency)) || parseInt(cli.flags.concurrency, 10) < 0)) {
|
|
127
|
+
throw new Error(colors.error(figures.cross) + ' The --concurrency and -c flags must be a nonnegative integer.');
|
|
123
128
|
}
|
|
124
129
|
|
|
125
130
|
if (hasFlag('--require') || hasFlag('-r')) {
|
|
@@ -144,6 +149,7 @@ exports.run = () => {
|
|
|
144
149
|
timeout: conf.timeout,
|
|
145
150
|
concurrency: conf.concurrency ? parseInt(conf.concurrency, 10) : 0,
|
|
146
151
|
updateSnapshots: conf.updateSnapshots,
|
|
152
|
+
snapshotDir: conf.snapshotDir ? path.resolve(projectDir, conf.snapshotDir) : null,
|
|
147
153
|
color: conf.color
|
|
148
154
|
});
|
|
149
155
|
|
|
@@ -152,7 +158,7 @@ exports.run = () => {
|
|
|
152
158
|
if (conf.tap && !conf.watch) {
|
|
153
159
|
reporter = new TapReporter();
|
|
154
160
|
} else if (conf.verbose || isCi) {
|
|
155
|
-
reporter = new VerboseReporter({color: conf.color});
|
|
161
|
+
reporter = new VerboseReporter({color: conf.color, watching: conf.watch});
|
|
156
162
|
} else {
|
|
157
163
|
reporter = new MiniReporter({color: conf.color, watching: conf.watch});
|
|
158
164
|
}
|
package/lib/colors.js
CHANGED
package/lib/enhance-assert.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const concordance = require('concordance');
|
|
3
3
|
const dotProp = require('dot-prop');
|
|
4
|
+
const generate = require('babel-generator').default;
|
|
4
5
|
const concordanceOptions = require('./concordance-options').default;
|
|
5
6
|
|
|
6
7
|
// When adding patterns, don't forget to add to
|
|
@@ -15,31 +16,16 @@ const PATTERNS = [
|
|
|
15
16
|
't.notRegex(contents, regex, [message])'
|
|
16
17
|
];
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
-
return (a[0] === b[0] && a[1] === b[1]) ||
|
|
20
|
-
(a[0] > b[0] && a[0] < b[1]) ||
|
|
21
|
-
(a[1] > b[0] && a[1] < b[1]);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const computeStatement = (tokens, range) => {
|
|
25
|
-
return tokens
|
|
26
|
-
.filter(token => isRangeMatch(token.range, range))
|
|
27
|
-
.map(token => token.value === undefined ? token.type.label : token.value)
|
|
28
|
-
.join('');
|
|
29
|
-
};
|
|
30
|
-
|
|
19
|
+
const computeStatement = node => generate(node, {quotes: 'single'}).code;
|
|
31
20
|
const getNode = (ast, path) => dotProp.get(ast, path.replace(/\//g, '.'));
|
|
32
21
|
|
|
33
22
|
const formatter = context => {
|
|
34
23
|
const ast = JSON.parse(context.source.ast);
|
|
35
|
-
const tokens = JSON.parse(context.source.tokens);
|
|
36
24
|
const args = context.args[0].events;
|
|
37
|
-
|
|
38
25
|
return args
|
|
39
26
|
.map(arg => {
|
|
40
|
-
const
|
|
41
|
-
const statement = computeStatement(
|
|
42
|
-
|
|
27
|
+
const node = getNode(ast, arg.espath);
|
|
28
|
+
const statement = computeStatement(node);
|
|
43
29
|
const formatted = concordance.format(arg.value, concordanceOptions);
|
|
44
30
|
return [statement, formatted];
|
|
45
31
|
})
|
package/lib/fork.js
CHANGED
|
@@ -10,12 +10,10 @@ if (fs.realpathSync(__filename) !== __filename) {
|
|
|
10
10
|
console.warn('WARNING: `npm link ava` and the `--preserve-symlink` flag are incompatible. We have detected that AVA is linked via `npm link`, and that you are using either an early version of Node 6, or the `--preserve-symlink` flag. This breaks AVA. You should upgrade to Node 6.2.0+, avoid the `--preserve-symlink` flag, or avoid using `npm link ava`.');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const env = Object.assign({NODE_ENV: 'test'}, process.env);
|
|
14
14
|
|
|
15
15
|
// Ensure NODE_PATH paths are absolute
|
|
16
16
|
if (env.NODE_PATH) {
|
|
17
|
-
env = Object.assign({}, env);
|
|
18
|
-
|
|
19
17
|
env.NODE_PATH = env.NODE_PATH
|
|
20
18
|
.split(path.delimiter)
|
|
21
19
|
.map(x => path.resolve(x))
|
package/lib/logger.js
CHANGED
|
@@ -6,6 +6,7 @@ class Logger {
|
|
|
6
6
|
this.reporter = reporter;
|
|
7
7
|
autoBind(this);
|
|
8
8
|
}
|
|
9
|
+
|
|
9
10
|
start(runStatus) {
|
|
10
11
|
if (!this.reporter.start) {
|
|
11
12
|
return;
|
|
@@ -13,6 +14,7 @@ class Logger {
|
|
|
13
14
|
|
|
14
15
|
this.write(this.reporter.start(runStatus), runStatus);
|
|
15
16
|
}
|
|
17
|
+
|
|
16
18
|
reset(runStatus) {
|
|
17
19
|
if (!this.reporter.reset) {
|
|
18
20
|
return;
|
|
@@ -20,9 +22,11 @@ class Logger {
|
|
|
20
22
|
|
|
21
23
|
this.write(this.reporter.reset(runStatus), runStatus);
|
|
22
24
|
}
|
|
25
|
+
|
|
23
26
|
test(test, runStatus) {
|
|
24
27
|
this.write(this.reporter.test(test, runStatus), runStatus);
|
|
25
28
|
}
|
|
29
|
+
|
|
26
30
|
unhandledError(err, runStatus) {
|
|
27
31
|
if (!this.reporter.unhandledError) {
|
|
28
32
|
return;
|
|
@@ -30,6 +34,7 @@ class Logger {
|
|
|
30
34
|
|
|
31
35
|
this.write(this.reporter.unhandledError(err, runStatus), runStatus);
|
|
32
36
|
}
|
|
37
|
+
|
|
33
38
|
finish(runStatus) {
|
|
34
39
|
if (!this.reporter.finish) {
|
|
35
40
|
return;
|
|
@@ -37,6 +42,7 @@ class Logger {
|
|
|
37
42
|
|
|
38
43
|
this.write(this.reporter.finish(runStatus), runStatus);
|
|
39
44
|
}
|
|
45
|
+
|
|
40
46
|
section() {
|
|
41
47
|
if (!this.reporter.section) {
|
|
42
48
|
return;
|
|
@@ -44,6 +50,7 @@ class Logger {
|
|
|
44
50
|
|
|
45
51
|
this.write(this.reporter.section());
|
|
46
52
|
}
|
|
53
|
+
|
|
47
54
|
clear() {
|
|
48
55
|
if (!this.reporter.clear) {
|
|
49
56
|
return false;
|
|
@@ -52,6 +59,7 @@ class Logger {
|
|
|
52
59
|
this.write(this.reporter.clear());
|
|
53
60
|
return true;
|
|
54
61
|
}
|
|
62
|
+
|
|
55
63
|
write(str, runStatus) {
|
|
56
64
|
if (typeof str === 'undefined') {
|
|
57
65
|
return;
|
|
@@ -59,6 +67,7 @@ class Logger {
|
|
|
59
67
|
|
|
60
68
|
this.reporter.write(str, runStatus);
|
|
61
69
|
}
|
|
70
|
+
|
|
62
71
|
stdout(data, runStatus) {
|
|
63
72
|
if (!this.reporter.stdout) {
|
|
64
73
|
return;
|
|
@@ -66,6 +75,7 @@ class Logger {
|
|
|
66
75
|
|
|
67
76
|
this.reporter.stdout(data, runStatus);
|
|
68
77
|
}
|
|
78
|
+
|
|
69
79
|
stderr(data, runStatus) {
|
|
70
80
|
if (!this.reporter.stderr) {
|
|
71
81
|
return;
|
|
@@ -73,6 +83,7 @@ class Logger {
|
|
|
73
83
|
|
|
74
84
|
this.reporter.stderr(data, runStatus);
|
|
75
85
|
}
|
|
86
|
+
|
|
76
87
|
exit(code) {
|
|
77
88
|
process.exit(code); // eslint-disable-line unicorn/no-process-exit
|
|
78
89
|
}
|
package/lib/main.js
CHANGED
|
@@ -13,7 +13,8 @@ const runner = new Runner({
|
|
|
13
13
|
match: opts.match,
|
|
14
14
|
projectDir: opts.projectDir,
|
|
15
15
|
serial: opts.serial,
|
|
16
|
-
updateSnapshots: opts.updateSnapshots
|
|
16
|
+
updateSnapshots: opts.updateSnapshots,
|
|
17
|
+
snapshotDir: opts.snapshotDir
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
worker.setRunner(runner);
|
|
@@ -22,8 +23,6 @@ worker.setRunner(runner);
|
|
|
22
23
|
// that no more tests should be logged
|
|
23
24
|
let isFailed = false;
|
|
24
25
|
|
|
25
|
-
Error.stackTraceLimit = Infinity;
|
|
26
|
-
|
|
27
26
|
function test(props) {
|
|
28
27
|
if (isFailed) {
|
|
29
28
|
return;
|