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/lib/process-adapter.js
CHANGED
|
@@ -48,13 +48,13 @@ if (opts.tty) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (debug.enabled) {
|
|
51
|
-
// Forward the
|
|
51
|
+
// Forward the `@ladjs/time-require` `--sorted` flag.
|
|
52
52
|
// Intended for internal optimization tests only.
|
|
53
53
|
if (opts._sorted) {
|
|
54
54
|
process.argv.push('--sorted');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
require('time-require'); // eslint-disable-line import/no-unassigned-import
|
|
57
|
+
require('@ladjs/time-require'); // eslint-disable-line import/no-unassigned-import
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const sourceMapCache = new Map();
|
|
@@ -15,7 +15,9 @@ exports.forError = error => {
|
|
|
15
15
|
Visit the following URL for more details:
|
|
16
16
|
|
|
17
17
|
${chalk.blue.underline('https://github.com/avajs/ava#throwsfunctionpromise-error-message')}`;
|
|
18
|
-
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (assertion === 'snapshot') {
|
|
19
21
|
const name = error.improperUsage.name;
|
|
20
22
|
const snapPath = error.improperUsage.snapPath;
|
|
21
23
|
|
package/lib/reporters/mini.js
CHANGED
|
@@ -5,12 +5,12 @@ const lastLineTracker = require('last-line-stream/tracker');
|
|
|
5
5
|
const plur = require('plur');
|
|
6
6
|
const spinners = require('cli-spinners');
|
|
7
7
|
const chalk = require('chalk');
|
|
8
|
+
const figures = require('figures');
|
|
8
9
|
const cliTruncate = require('cli-truncate');
|
|
9
10
|
const cross = require('figures').cross;
|
|
10
11
|
const indentString = require('indent-string');
|
|
11
12
|
const ansiEscapes = require('ansi-escapes');
|
|
12
13
|
const trimOffNewlines = require('trim-off-newlines');
|
|
13
|
-
const extractStack = require('../extract-stack');
|
|
14
14
|
const codeExcerpt = require('../code-excerpt');
|
|
15
15
|
const colors = require('../colors');
|
|
16
16
|
const formatSerializedError = require('./format-serialized-error');
|
|
@@ -33,6 +33,7 @@ class MiniReporter {
|
|
|
33
33
|
this.stream = process.stderr;
|
|
34
34
|
this.stringDecoder = new StringDecoder();
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
start() {
|
|
37
38
|
this.interval = setInterval(() => {
|
|
38
39
|
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
|
|
@@ -41,6 +42,7 @@ class MiniReporter {
|
|
|
41
42
|
|
|
42
43
|
return this.prefix('');
|
|
43
44
|
}
|
|
45
|
+
|
|
44
46
|
reset() {
|
|
45
47
|
this.clearInterval();
|
|
46
48
|
this.passCount = 0;
|
|
@@ -56,13 +58,16 @@ class MiniReporter {
|
|
|
56
58
|
this.spinnerIndex = 0;
|
|
57
59
|
this.lastLineTracker = lastLineTracker();
|
|
58
60
|
}
|
|
61
|
+
|
|
59
62
|
spinnerChar() {
|
|
60
63
|
return this.spinnerFrames[this.spinnerIndex];
|
|
61
64
|
}
|
|
65
|
+
|
|
62
66
|
clearInterval() {
|
|
63
67
|
clearInterval(this.interval);
|
|
64
68
|
this.interval = null;
|
|
65
69
|
}
|
|
70
|
+
|
|
66
71
|
test(test) {
|
|
67
72
|
if (test.todo) {
|
|
68
73
|
this.todoCount++;
|
|
@@ -83,6 +88,7 @@ class MiniReporter {
|
|
|
83
88
|
|
|
84
89
|
return this.prefix(this._test(test));
|
|
85
90
|
}
|
|
91
|
+
|
|
86
92
|
prefix(str) {
|
|
87
93
|
str = str || this.currentTest;
|
|
88
94
|
this.currentTest = str;
|
|
@@ -91,6 +97,7 @@ class MiniReporter {
|
|
|
91
97
|
// TODO(jamestalmage): Figure out why it's needed and document it here
|
|
92
98
|
return ` \n ${this.spinnerChar()} ${str}`;
|
|
93
99
|
}
|
|
100
|
+
|
|
94
101
|
_test(test) {
|
|
95
102
|
const SPINNER_WIDTH = 3;
|
|
96
103
|
const PADDING = 1;
|
|
@@ -102,6 +109,7 @@ class MiniReporter {
|
|
|
102
109
|
|
|
103
110
|
return title + '\n' + this.reportCounts();
|
|
104
111
|
}
|
|
112
|
+
|
|
105
113
|
unhandledError(err) {
|
|
106
114
|
if (err.type === 'exception') {
|
|
107
115
|
this.exceptionCount++;
|
|
@@ -109,6 +117,7 @@ class MiniReporter {
|
|
|
109
117
|
this.rejectionCount++;
|
|
110
118
|
}
|
|
111
119
|
}
|
|
120
|
+
|
|
112
121
|
reportCounts(time) {
|
|
113
122
|
const lines = [
|
|
114
123
|
this.passCount > 0 ? '\n ' + colors.pass(this.passCount, 'passed') : '',
|
|
@@ -124,6 +133,7 @@ class MiniReporter {
|
|
|
124
133
|
|
|
125
134
|
return lines.join('');
|
|
126
135
|
}
|
|
136
|
+
|
|
127
137
|
finish(runStatus) {
|
|
128
138
|
this.clearInterval();
|
|
129
139
|
let time;
|
|
@@ -163,6 +173,21 @@ class MiniReporter {
|
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
status += ' ' + colors.title(test.title) + '\n';
|
|
176
|
+
|
|
177
|
+
if (test.logs) {
|
|
178
|
+
test.logs.forEach(log => {
|
|
179
|
+
const logLines = indentString(colors.log(log), 6);
|
|
180
|
+
const logLinesWithLeadingFigure = logLines.replace(
|
|
181
|
+
/^ {6}/,
|
|
182
|
+
` ${colors.information(figures.info)} `
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
status += logLinesWithLeadingFigure + '\n';
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
status += '\n';
|
|
189
|
+
}
|
|
190
|
+
|
|
166
191
|
if (test.error.source) {
|
|
167
192
|
status += ' ' + colors.errorSource(test.error.source.file + ':' + test.error.source.line) + '\n';
|
|
168
193
|
|
|
@@ -191,9 +216,9 @@ class MiniReporter {
|
|
|
191
216
|
}
|
|
192
217
|
|
|
193
218
|
if (test.error.stack) {
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
status += '\n' + indentString(colors.errorStack(
|
|
219
|
+
const stack = test.error.stack;
|
|
220
|
+
if (stack.includes('\n')) {
|
|
221
|
+
status += '\n' + indentString(colors.errorStack(stack), 2) + '\n';
|
|
197
222
|
}
|
|
198
223
|
}
|
|
199
224
|
|
|
@@ -212,14 +237,14 @@ class MiniReporter {
|
|
|
212
237
|
status += ' ' + colors.error(cross + ' ' + err.message) + '\n\n';
|
|
213
238
|
} else {
|
|
214
239
|
const title = err.type === 'rejection' ? 'Unhandled Rejection' : 'Uncaught Exception';
|
|
215
|
-
let description = err.stack ? err.stack.trimRight() : JSON.stringify(err);
|
|
216
|
-
description = description.split('\n');
|
|
217
|
-
const errorTitle = err.name ? description[0] : 'Threw non-error: ' + description[0];
|
|
218
|
-
const errorStack = description.slice(1).join('\n');
|
|
219
|
-
|
|
220
240
|
status += ' ' + colors.title(title) + '\n';
|
|
221
|
-
|
|
222
|
-
|
|
241
|
+
|
|
242
|
+
if (err.name) {
|
|
243
|
+
status += ' ' + colors.stack(err.summary) + '\n';
|
|
244
|
+
status += colors.errorStack(err.stack) + '\n\n';
|
|
245
|
+
} else {
|
|
246
|
+
status += ' Threw non-error: ' + err.summary + '\n';
|
|
247
|
+
}
|
|
223
248
|
}
|
|
224
249
|
});
|
|
225
250
|
}
|
|
@@ -235,24 +260,30 @@ class MiniReporter {
|
|
|
235
260
|
|
|
236
261
|
return '\n' + trimOffNewlines(status) + '\n';
|
|
237
262
|
}
|
|
263
|
+
|
|
238
264
|
section() {
|
|
239
265
|
return '\n' + chalk.gray.dim('\u2500'.repeat(process.stdout.columns || 80));
|
|
240
266
|
}
|
|
267
|
+
|
|
241
268
|
clear() {
|
|
242
269
|
return '';
|
|
243
270
|
}
|
|
271
|
+
|
|
244
272
|
write(str) {
|
|
245
273
|
cliCursor.hide();
|
|
246
274
|
this.currentStatus = str;
|
|
247
275
|
this._update();
|
|
248
276
|
this.statusLineCount = this.currentStatus.split('\n').length;
|
|
249
277
|
}
|
|
278
|
+
|
|
250
279
|
stdout(data) {
|
|
251
280
|
this._update(data);
|
|
252
281
|
}
|
|
282
|
+
|
|
253
283
|
stderr(data) {
|
|
254
284
|
this._update(data);
|
|
255
285
|
}
|
|
286
|
+
|
|
256
287
|
_update(data) {
|
|
257
288
|
let str = '';
|
|
258
289
|
let ct = this.statusLineCount;
|
package/lib/reporters/tap.js
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const
|
|
3
|
-
const indentString = require('indent-string');
|
|
2
|
+
const supertap = require('supertap');
|
|
4
3
|
const stripAnsi = require('strip-ansi');
|
|
5
|
-
const yaml = require('js-yaml');
|
|
6
|
-
const extractStack = require('../extract-stack');
|
|
7
|
-
|
|
8
|
-
// Parses stack trace and extracts original function name, file name and line
|
|
9
|
-
function getSourceFromStack(stack) {
|
|
10
|
-
return extractStack(stack).split('\n')[0];
|
|
11
|
-
}
|
|
12
4
|
|
|
13
5
|
function dumpError(error, includeMessage) {
|
|
14
6
|
const obj = Object.assign({}, error.object);
|
|
@@ -35,82 +27,64 @@ function dumpError(error, includeMessage) {
|
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
if (error.stack) {
|
|
38
|
-
obj.at =
|
|
30
|
+
obj.at = error.stack.split('\n')[0];
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
return
|
|
33
|
+
return obj;
|
|
42
34
|
}
|
|
43
35
|
|
|
44
36
|
class TapReporter {
|
|
45
37
|
constructor() {
|
|
46
38
|
this.i = 0;
|
|
47
39
|
}
|
|
40
|
+
|
|
48
41
|
start() {
|
|
49
|
-
return
|
|
42
|
+
return supertap.start();
|
|
50
43
|
}
|
|
51
|
-
test(test) {
|
|
52
|
-
let output;
|
|
53
|
-
|
|
54
|
-
let directive = '';
|
|
55
|
-
const passed = test.todo ? 'not ok' : 'ok';
|
|
56
44
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
output = [
|
|
67
|
-
'# ' + title,
|
|
68
|
-
format('not ok %d - %s', ++this.i, title),
|
|
69
|
-
dumpError(test.error, true)
|
|
70
|
-
];
|
|
71
|
-
} else {
|
|
72
|
-
output = [
|
|
73
|
-
`# ${title}`,
|
|
74
|
-
format('%s %d - %s %s', passed, ++this.i, title, directive).trim()
|
|
75
|
-
];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return output.join('\n');
|
|
45
|
+
test(test) {
|
|
46
|
+
return supertap.test(test.title, {
|
|
47
|
+
passed: !test.error,
|
|
48
|
+
index: ++this.i,
|
|
49
|
+
todo: test.todo,
|
|
50
|
+
skip: test.skip,
|
|
51
|
+
comment: test.logs,
|
|
52
|
+
error: test.error ? dumpError(test.error, true) : null
|
|
53
|
+
});
|
|
79
54
|
}
|
|
55
|
+
|
|
80
56
|
unhandledError(err) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
format('not ok %d - %s', ++this.i, err.message)
|
|
84
|
-
];
|
|
57
|
+
let error;
|
|
58
|
+
|
|
85
59
|
// AvaErrors don't have stack traces
|
|
86
60
|
if (err.type !== 'exception' || err.name !== 'AvaError') {
|
|
87
|
-
|
|
61
|
+
error = dumpError(err, false);
|
|
88
62
|
}
|
|
89
63
|
|
|
90
|
-
return
|
|
64
|
+
return supertap.test(err.message, {
|
|
65
|
+
passed: false,
|
|
66
|
+
index: ++this.i,
|
|
67
|
+
error
|
|
68
|
+
});
|
|
91
69
|
}
|
|
92
|
-
finish(runStatus) {
|
|
93
|
-
const output = [
|
|
94
|
-
'',
|
|
95
|
-
'1..' + (runStatus.passCount + runStatus.failCount + runStatus.skipCount),
|
|
96
|
-
'# tests ' + (runStatus.passCount + runStatus.failCount + runStatus.skipCount),
|
|
97
|
-
'# pass ' + runStatus.passCount
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
if (runStatus.skipCount > 0) {
|
|
101
|
-
output.push(`# skip ${runStatus.skipCount}`);
|
|
102
|
-
}
|
|
103
70
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
71
|
+
finish(runStatus) {
|
|
72
|
+
return supertap.finish({
|
|
73
|
+
passed: runStatus.passCount,
|
|
74
|
+
failed: runStatus.failCount,
|
|
75
|
+
skipped: runStatus.skipCount,
|
|
76
|
+
crashed: runStatus.rejectionCount + runStatus.exceptionCount
|
|
77
|
+
});
|
|
107
78
|
}
|
|
79
|
+
|
|
108
80
|
write(str) {
|
|
109
81
|
console.log(str);
|
|
110
82
|
}
|
|
83
|
+
|
|
111
84
|
stdout(data) {
|
|
112
85
|
process.stderr.write(data);
|
|
113
86
|
}
|
|
87
|
+
|
|
114
88
|
stderr(data) {
|
|
115
89
|
this.stdout(data);
|
|
116
90
|
}
|
package/lib/reporters/verbose.js
CHANGED
|
@@ -5,7 +5,6 @@ const figures = require('figures');
|
|
|
5
5
|
const chalk = require('chalk');
|
|
6
6
|
const plur = require('plur');
|
|
7
7
|
const trimOffNewlines = require('trim-off-newlines');
|
|
8
|
-
const extractStack = require('../extract-stack');
|
|
9
8
|
const codeExcerpt = require('../code-excerpt');
|
|
10
9
|
const colors = require('../colors');
|
|
11
10
|
const formatSerializedError = require('./format-serialized-error');
|
|
@@ -20,34 +19,46 @@ class VerboseReporter {
|
|
|
20
19
|
colors[key].enabled = this.options.color;
|
|
21
20
|
}
|
|
22
21
|
}
|
|
22
|
+
|
|
23
23
|
start() {
|
|
24
24
|
return '';
|
|
25
25
|
}
|
|
26
|
+
|
|
26
27
|
test(test, runStatus) {
|
|
28
|
+
const lines = [];
|
|
27
29
|
if (test.error) {
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (test.todo) {
|
|
32
|
-
return ' ' + colors.todo('- ' + test.title);
|
|
30
|
+
lines.push(' ' + colors.error(figures.cross) + ' ' + test.title + ' ' + colors.error(test.error.message));
|
|
31
|
+
} else if (test.todo) {
|
|
32
|
+
lines.push(' ' + colors.todo('- ' + test.title));
|
|
33
33
|
} else if (test.skip) {
|
|
34
|
-
|
|
35
|
-
}
|
|
34
|
+
lines.push(' ' + colors.skip('- ' + test.title));
|
|
35
|
+
} else if (test.failing) {
|
|
36
|
+
lines.push(' ' + colors.error(figures.tick) + ' ' + colors.error(test.title));
|
|
37
|
+
} else if (runStatus.fileCount === 1 && runStatus.testCount === 1 && test.title === '[anonymous]') {
|
|
38
|
+
// No output
|
|
39
|
+
} else {
|
|
40
|
+
// Display duration only over a threshold
|
|
41
|
+
const threshold = 100;
|
|
42
|
+
const duration = test.duration > threshold ? colors.duration(' (' + prettyMs(test.duration) + ')') : '';
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
return ' ' + colors.error(figures.tick) + ' ' + colors.error(test.title);
|
|
44
|
+
lines.push(' ' + colors.pass(figures.tick) + ' ' + test.title + duration);
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
if (test.logs) {
|
|
48
|
+
test.logs.forEach(log => {
|
|
49
|
+
const logLines = indentString(colors.log(log), 6);
|
|
50
|
+
const logLinesWithLeadingFigure = logLines.replace(
|
|
51
|
+
/^ {6}/,
|
|
52
|
+
` ${colors.information(figures.info)} `
|
|
53
|
+
);
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
lines.push(logLinesWithLeadingFigure);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
48
58
|
|
|
49
|
-
return
|
|
59
|
+
return lines.length > 0 ? lines.join('\n') : undefined;
|
|
50
60
|
}
|
|
61
|
+
|
|
51
62
|
unhandledError(err) {
|
|
52
63
|
if (err.type === 'exception' && err.name === 'AvaError') {
|
|
53
64
|
return colors.error(' ' + figures.cross + ' ' + err.message);
|
|
@@ -61,6 +72,7 @@ class VerboseReporter {
|
|
|
61
72
|
let output = colors.error(types[err.type] + ':', err.file) + '\n';
|
|
62
73
|
|
|
63
74
|
if (err.stack) {
|
|
75
|
+
output += ' ' + colors.stack(err.title || err.summary) + '\n';
|
|
64
76
|
output += ' ' + colors.stack(err.stack) + '\n';
|
|
65
77
|
} else {
|
|
66
78
|
output += ' ' + colors.stack(JSON.stringify(err)) + '\n';
|
|
@@ -70,6 +82,7 @@ class VerboseReporter {
|
|
|
70
82
|
|
|
71
83
|
return output;
|
|
72
84
|
}
|
|
85
|
+
|
|
73
86
|
finish(runStatus) {
|
|
74
87
|
let output = '';
|
|
75
88
|
|
|
@@ -86,7 +99,9 @@ class VerboseReporter {
|
|
|
86
99
|
].filter(Boolean);
|
|
87
100
|
|
|
88
101
|
if (lines.length > 0) {
|
|
89
|
-
|
|
102
|
+
if (this.options.watching) {
|
|
103
|
+
lines[0] += ' ' + chalk.gray.dim('[' + new Date().toLocaleTimeString('en-US', {hour12: false}) + ']');
|
|
104
|
+
}
|
|
90
105
|
output += lines.join('\n') + '\n';
|
|
91
106
|
}
|
|
92
107
|
|
|
@@ -104,6 +119,21 @@ class VerboseReporter {
|
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
output += ' ' + colors.title(test.title) + '\n';
|
|
122
|
+
|
|
123
|
+
if (test.logs) {
|
|
124
|
+
test.logs.forEach(log => {
|
|
125
|
+
const logLines = indentString(colors.log(log), 6);
|
|
126
|
+
const logLinesWithLeadingFigure = logLines.replace(
|
|
127
|
+
/^ {6}/,
|
|
128
|
+
` ${colors.information(figures.info)} `
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
output += logLinesWithLeadingFigure + '\n';
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
output += '\n';
|
|
135
|
+
}
|
|
136
|
+
|
|
107
137
|
if (test.error.source) {
|
|
108
138
|
output += ' ' + colors.errorSource(test.error.source.file + ':' + test.error.source.line) + '\n';
|
|
109
139
|
|
|
@@ -132,9 +162,9 @@ class VerboseReporter {
|
|
|
132
162
|
}
|
|
133
163
|
|
|
134
164
|
if (test.error.stack) {
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
output += '\n' + indentString(colors.errorStack(
|
|
165
|
+
const stack = test.error.stack;
|
|
166
|
+
if (stack.includes('\n')) {
|
|
167
|
+
output += '\n' + indentString(colors.errorStack(stack), 2) + '\n';
|
|
138
168
|
}
|
|
139
169
|
}
|
|
140
170
|
|
|
@@ -153,15 +183,19 @@ class VerboseReporter {
|
|
|
153
183
|
|
|
154
184
|
return '\n' + trimOffNewlines(output) + '\n';
|
|
155
185
|
}
|
|
186
|
+
|
|
156
187
|
section() {
|
|
157
188
|
return chalk.gray.dim('\u2500'.repeat(process.stdout.columns || 80));
|
|
158
189
|
}
|
|
190
|
+
|
|
159
191
|
write(str) {
|
|
160
192
|
console.error(str);
|
|
161
193
|
}
|
|
194
|
+
|
|
162
195
|
stdout(data) {
|
|
163
196
|
process.stderr.write(data);
|
|
164
197
|
}
|
|
198
|
+
|
|
165
199
|
stderr(data) {
|
|
166
200
|
process.stderr.write(data);
|
|
167
201
|
}
|
package/lib/run-status.js
CHANGED
|
@@ -44,6 +44,7 @@ class RunStatus extends EventEmitter {
|
|
|
44
44
|
|
|
45
45
|
autoBind(this);
|
|
46
46
|
}
|
|
47
|
+
|
|
47
48
|
observeFork(emitter) {
|
|
48
49
|
emitter
|
|
49
50
|
.on('teardown', this.handleTeardown)
|
|
@@ -54,6 +55,7 @@ class RunStatus extends EventEmitter {
|
|
|
54
55
|
.on('stdout', this.handleOutput.bind(this, 'stdout'))
|
|
55
56
|
.on('stderr', this.handleOutput.bind(this, 'stderr'));
|
|
56
57
|
}
|
|
58
|
+
|
|
57
59
|
handleRejections(data) {
|
|
58
60
|
this.rejectionCount += data.rejections.length;
|
|
59
61
|
|
|
@@ -64,6 +66,7 @@ class RunStatus extends EventEmitter {
|
|
|
64
66
|
this.errors.push(err);
|
|
65
67
|
});
|
|
66
68
|
}
|
|
69
|
+
|
|
67
70
|
handleExceptions(data) {
|
|
68
71
|
this.exceptionCount++;
|
|
69
72
|
const err = data.exception;
|
|
@@ -72,10 +75,12 @@ class RunStatus extends EventEmitter {
|
|
|
72
75
|
this.emit('error', err, this);
|
|
73
76
|
this.errors.push(err);
|
|
74
77
|
}
|
|
78
|
+
|
|
75
79
|
handleTeardown(data) {
|
|
76
80
|
this.emit('dependencies', data.file, data.dependencies, this);
|
|
77
81
|
this.emit('touchedFiles', data.touchedFiles);
|
|
78
82
|
}
|
|
83
|
+
|
|
79
84
|
handleStats(stats) {
|
|
80
85
|
this.emit('stats', stats, this);
|
|
81
86
|
|
|
@@ -85,6 +90,7 @@ class RunStatus extends EventEmitter {
|
|
|
85
90
|
|
|
86
91
|
this.testCount += stats.testCount;
|
|
87
92
|
}
|
|
93
|
+
|
|
88
94
|
handleTest(test) {
|
|
89
95
|
test.title = this.prefixTitle(test.file) + test.title;
|
|
90
96
|
|
|
@@ -98,6 +104,7 @@ class RunStatus extends EventEmitter {
|
|
|
98
104
|
|
|
99
105
|
this.emit('test', test, this);
|
|
100
106
|
}
|
|
107
|
+
|
|
101
108
|
prefixTitle(file) {
|
|
102
109
|
if (!this.prefixTitles) {
|
|
103
110
|
return '';
|
|
@@ -107,9 +114,11 @@ class RunStatus extends EventEmitter {
|
|
|
107
114
|
|
|
108
115
|
return prefixTitle(file, this.base, separator);
|
|
109
116
|
}
|
|
117
|
+
|
|
110
118
|
handleOutput(channel, data) {
|
|
111
119
|
this.emit(channel, data, this);
|
|
112
120
|
}
|
|
121
|
+
|
|
113
122
|
processResults(results) {
|
|
114
123
|
// Assemble stats from all tests
|
|
115
124
|
this.stats = results.map(result => result.stats);
|
package/lib/runner.js
CHANGED
|
@@ -52,6 +52,7 @@ class Runner extends EventEmitter {
|
|
|
52
52
|
this.projectDir = options.projectDir;
|
|
53
53
|
this.serial = options.serial;
|
|
54
54
|
this.updateSnapshots = options.updateSnapshots;
|
|
55
|
+
this.snapshotDir = options.snapshotDir;
|
|
55
56
|
|
|
56
57
|
this.hasStarted = false;
|
|
57
58
|
this.results = [];
|
|
@@ -112,7 +113,7 @@ class Runner extends EventEmitter {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
if (metadata.type === 'test' && this.match.length > 0) {
|
|
115
|
-
metadata.exclusive =
|
|
116
|
+
metadata.exclusive = matcher([title || ''], this.match).length === 1;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
const validationError = validateTest(title, fn, metadata);
|
|
@@ -130,6 +131,7 @@ class Runner extends EventEmitter {
|
|
|
130
131
|
addTestResult(result) {
|
|
131
132
|
const test = result.result;
|
|
132
133
|
const props = {
|
|
134
|
+
logs: test.logs,
|
|
133
135
|
duration: test.duration,
|
|
134
136
|
title: test.title,
|
|
135
137
|
error: result.reason,
|
|
@@ -183,6 +185,8 @@ class Runner extends EventEmitter {
|
|
|
183
185
|
compareTestSnapshot(options) {
|
|
184
186
|
if (!this.snapshots) {
|
|
185
187
|
this.snapshots = snapshotManager.load({
|
|
188
|
+
file: this.file,
|
|
189
|
+
fixedLocation: this.snapshotDir,
|
|
186
190
|
name: path.basename(this.file),
|
|
187
191
|
projectDir: this.projectDir,
|
|
188
192
|
relFile: path.relative(this.projectDir, this.file),
|
|
@@ -219,6 +223,7 @@ class Runner extends EventEmitter {
|
|
|
219
223
|
});
|
|
220
224
|
return Bluebird.try(() => this.tests.build().run());
|
|
221
225
|
}
|
|
226
|
+
|
|
222
227
|
attributeLeakedError(err) {
|
|
223
228
|
return this.tests.attributeLeakedError(err);
|
|
224
229
|
}
|
package/lib/serialize-error.js
CHANGED
|
@@ -4,7 +4,6 @@ const cleanYamlObject = require('clean-yaml-object');
|
|
|
4
4
|
const StackUtils = require('stack-utils');
|
|
5
5
|
const assert = require('./assert');
|
|
6
6
|
const beautifyStack = require('./beautify-stack');
|
|
7
|
-
const extractStack = require('./extract-stack');
|
|
8
7
|
|
|
9
8
|
function isAvaAssertionError(source) {
|
|
10
9
|
return source instanceof assert.AssertionError;
|
|
@@ -20,7 +19,7 @@ function extractSource(stack) {
|
|
|
20
19
|
return null;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
const firstStackLine =
|
|
22
|
+
const firstStackLine = stack.split('\n')[0];
|
|
24
23
|
return stackUtils.parseLine(firstStackLine);
|
|
25
24
|
}
|
|
26
25
|
function buildSource(source) {
|
|
@@ -90,5 +89,11 @@ module.exports = error => {
|
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
92
|
+
if (typeof error.stack === 'string') {
|
|
93
|
+
retval.summary = error.stack.split('\n')[0];
|
|
94
|
+
} else {
|
|
95
|
+
retval.summary = JSON.stringify(error);
|
|
96
|
+
}
|
|
97
|
+
|
|
93
98
|
return retval;
|
|
94
99
|
};
|
package/lib/snapshot-manager.js
CHANGED
|
@@ -11,6 +11,7 @@ const indentString = require('indent-string');
|
|
|
11
11
|
const makeDir = require('make-dir');
|
|
12
12
|
const md5Hex = require('md5-hex');
|
|
13
13
|
const Buffer = require('safe-buffer').Buffer;
|
|
14
|
+
const convertSourceMap = require('convert-source-map');
|
|
14
15
|
|
|
15
16
|
const concordanceOptions = require('./concordance-options').snapshotManager;
|
|
16
17
|
|
|
@@ -355,18 +356,39 @@ class Manager {
|
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
function determineSnapshotDir(
|
|
359
|
-
const
|
|
359
|
+
function determineSnapshotDir(options) {
|
|
360
|
+
const testDir = determineSourceMappedDir(options);
|
|
361
|
+
if (options.fixedLocation) {
|
|
362
|
+
const relativeTestLocation = path.relative(options.projectDir, testDir);
|
|
363
|
+
return path.join(options.fixedLocation, relativeTestLocation);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const parts = new Set(path.relative(options.projectDir, testDir).split(path.sep));
|
|
360
367
|
if (parts.has('__tests__')) {
|
|
361
368
|
return path.join(testDir, '__snapshots__');
|
|
362
|
-
}
|
|
369
|
+
}
|
|
370
|
+
if (parts.has('test') || parts.has('tests')) { // Accept tests, even though it's not in the default test patterns
|
|
363
371
|
return path.join(testDir, 'snapshots');
|
|
364
372
|
}
|
|
373
|
+
|
|
365
374
|
return testDir;
|
|
366
375
|
}
|
|
367
376
|
|
|
377
|
+
function determineSourceMappedDir(options) {
|
|
378
|
+
const source = tryRead(options.file).toString();
|
|
379
|
+
const converter = convertSourceMap.fromSource(source) || convertSourceMap.fromMapFileSource(source, options.testDir);
|
|
380
|
+
if (converter) {
|
|
381
|
+
const map = converter.toObject();
|
|
382
|
+
const firstSource = `${map.sourceRoot || ''}${map.sources[0]}`;
|
|
383
|
+
const sourceFile = path.resolve(options.testDir, firstSource);
|
|
384
|
+
return path.dirname(sourceFile);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return options.testDir;
|
|
388
|
+
}
|
|
389
|
+
|
|
368
390
|
function load(options) {
|
|
369
|
-
const dir = determineSnapshotDir(options
|
|
391
|
+
const dir = determineSnapshotDir(options);
|
|
370
392
|
const reportFile = `${options.name}.md`;
|
|
371
393
|
const snapFile = `${options.name}.snap`;
|
|
372
394
|
const snapPath = path.join(dir, snapFile);
|