ava 3.7.1 → 3.9.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/index.d.ts +18 -1
- package/lib/api.js +9 -2
- package/lib/assert.js +62 -6
- package/lib/cli.js +28 -15
- package/lib/code-excerpt.js +1 -1
- package/lib/concordance-options.js +0 -1
- package/lib/fork.js +3 -1
- package/lib/globs.js +17 -13
- package/lib/like-selector.js +37 -0
- package/lib/line-numbers.js +64 -0
- package/lib/load-config.js +1 -1
- package/lib/reporters/beautify-stack.js +73 -0
- package/lib/reporters/colors.js +1 -0
- package/lib/reporters/default.js +834 -0
- package/lib/reporters/tap.js +3 -2
- package/lib/run-status.js +8 -2
- package/lib/runner.js +21 -3
- package/lib/serialize-error.js +30 -17
- package/lib/test.js +43 -1
- package/lib/watcher.js +4 -1
- package/lib/worker/line-numbers.js +90 -0
- package/lib/worker/subprocess.js +21 -6
- package/package.json +27 -72
- package/readme.md +1 -1
- package/lib/beautify-stack.js +0 -75
- package/lib/reporters/mini.js +0 -573
- package/lib/reporters/verbose.js +0 -440
package/readme.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://travis-ci.org/avajs/ava) [](https://codecov.io/gh/avajs/ava/branch/master) [](https://github.com/xojs/xo) [](https://spectrum.chat/ava)
|
|
4
4
|
[](https://github.com/sindresorhus/awesome-nodejs)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
AVA is a test runner for Node.js with a concise API, detailed error output, embrace of new language features and process isolation that lets you develop with confidence 🚀
|
|
7
7
|
|
|
8
8
|
Follow the [AVA Twitter account](https://twitter.com/ava__js) for updates.
|
|
9
9
|
|
package/lib/beautify-stack.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const StackUtils = require('stack-utils');
|
|
3
|
-
const cleanStack = require('clean-stack');
|
|
4
|
-
const debug = require('debug')('ava');
|
|
5
|
-
|
|
6
|
-
// Ignore unimportant stack trace lines
|
|
7
|
-
let ignoreStackLines = [];
|
|
8
|
-
|
|
9
|
-
const avaInternals = /\/ava\/(?:lib\/|lib\/worker\/)?[\w-]+\.js:\d+:\d+\)?$/;
|
|
10
|
-
const avaDependencies = /\/node_modules\/(?:@ava\/babel|@ava\/require-precompiled|append-transform|empower-core|nyc|require-precompiled|(?:ava\/node_modules\/)?(?:babel-runtime|core-js))\//;
|
|
11
|
-
const stackFrameLine = /^.+( \(.+:\d+:\d+\)|:\d+:\d+)$/;
|
|
12
|
-
|
|
13
|
-
if (!debug.enabled) {
|
|
14
|
-
ignoreStackLines = StackUtils.nodeInternals();
|
|
15
|
-
ignoreStackLines.push(avaInternals);
|
|
16
|
-
ignoreStackLines.push(avaDependencies);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const stackUtils = new StackUtils({internals: ignoreStackLines});
|
|
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
|
-
*/
|
|
59
|
-
module.exports = stack => {
|
|
60
|
-
if (!stack) {
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
stack = extractFrames(stack);
|
|
65
|
-
// Workaround for https://github.com/tapjs/stack-utils/issues/14
|
|
66
|
-
// TODO: fix it in `stack-utils`
|
|
67
|
-
stack = cleanStack(stack);
|
|
68
|
-
|
|
69
|
-
return stackUtils.clean(stack)
|
|
70
|
-
// Remove the trailing newline inserted by the `stack-utils` module
|
|
71
|
-
.trim()
|
|
72
|
-
// Remove remaining file:// prefixes, inserted by `esm`, that are not
|
|
73
|
-
// cleaned up by `stack-utils`
|
|
74
|
-
.split('\n').map(line => line.replace(/\(file:\/\/(?<path>[^/].+:\d+:\d+)\)$/, '($<path>)')).join('\n');
|
|
75
|
-
};
|
package/lib/reporters/mini.js
DELETED
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const stream = require('stream');
|
|
5
|
-
|
|
6
|
-
const cliCursor = require('cli-cursor');
|
|
7
|
-
const figures = require('figures');
|
|
8
|
-
const indentString = require('indent-string');
|
|
9
|
-
const ora = require('ora');
|
|
10
|
-
const plur = require('plur');
|
|
11
|
-
const trimOffNewlines = require('trim-off-newlines');
|
|
12
|
-
|
|
13
|
-
const chalk = require('../chalk').get();
|
|
14
|
-
const codeExcerpt = require('../code-excerpt');
|
|
15
|
-
const colors = require('./colors');
|
|
16
|
-
const formatSerializedError = require('./format-serialized-error');
|
|
17
|
-
const improperUsageMessages = require('./improper-usage-messages');
|
|
18
|
-
const prefixTitle = require('./prefix-title');
|
|
19
|
-
const whileCorked = require('./while-corked');
|
|
20
|
-
|
|
21
|
-
class LineWriter extends stream.Writable {
|
|
22
|
-
constructor(dest, spinner) {
|
|
23
|
-
super();
|
|
24
|
-
|
|
25
|
-
this.dest = dest;
|
|
26
|
-
this.columns = dest.columns || 80;
|
|
27
|
-
this.spinner = spinner;
|
|
28
|
-
this.lastSpinnerText = '';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
_write(chunk, encoding, callback) {
|
|
32
|
-
// Discard the current spinner output. Any lines that were meant to be
|
|
33
|
-
// preserved should be rewritten.
|
|
34
|
-
this.spinner.clear();
|
|
35
|
-
|
|
36
|
-
this._writeWithSpinner(chunk.toString('utf8'));
|
|
37
|
-
callback();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
_writev(pieces, callback) {
|
|
41
|
-
// Discard the current spinner output. Any lines that were meant to be
|
|
42
|
-
// preserved should be rewritten.
|
|
43
|
-
this.spinner.clear();
|
|
44
|
-
|
|
45
|
-
const last = pieces.pop();
|
|
46
|
-
for (const piece of pieces) {
|
|
47
|
-
this.dest.write(piece.chunk);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this._writeWithSpinner(last.chunk.toString('utf8'));
|
|
51
|
-
callback();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
_writeWithSpinner(string) {
|
|
55
|
-
if (!this.spinner.id) {
|
|
56
|
-
this.dest.write(string);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this.lastSpinnerText = string;
|
|
61
|
-
// Ignore whitespace at the end of the chunk. We're continiously rewriting
|
|
62
|
-
// the last line through the spinner. Also be careful to remove the indent
|
|
63
|
-
// as the spinner adds its own.
|
|
64
|
-
this.spinner.text = string.trimEnd().slice(2);
|
|
65
|
-
this.spinner.render();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
writeLine(string) {
|
|
69
|
-
if (string) {
|
|
70
|
-
this.write(indentString(string, 2) + os.EOL);
|
|
71
|
-
} else {
|
|
72
|
-
this.write(os.EOL);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
class MiniReporter {
|
|
78
|
-
constructor(options) {
|
|
79
|
-
this.reportStream = options.reportStream;
|
|
80
|
-
this.stdStream = options.stdStream;
|
|
81
|
-
this.watching = options.watching;
|
|
82
|
-
|
|
83
|
-
this.spinner = ora({
|
|
84
|
-
isEnabled: true,
|
|
85
|
-
color: options.spinner ? options.spinner.color : 'gray',
|
|
86
|
-
hideCursor: false,
|
|
87
|
-
spinner: options.spinner || (process.platform === 'win32' ? 'line' : 'dots'),
|
|
88
|
-
stream: options.reportStream
|
|
89
|
-
});
|
|
90
|
-
this.lineWriter = new LineWriter(this.reportStream, this.spinner);
|
|
91
|
-
|
|
92
|
-
this.consumeStateChange = whileCorked(this.reportStream, whileCorked(this.lineWriter, this.consumeStateChange));
|
|
93
|
-
this.endRun = whileCorked(this.reportStream, whileCorked(this.lineWriter, this.endRun));
|
|
94
|
-
this.relativeFile = file => path.relative(options.projectDir, file);
|
|
95
|
-
|
|
96
|
-
this.reset();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
reset() {
|
|
100
|
-
if (this.removePreviousListener) {
|
|
101
|
-
this.removePreviousListener();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.failFastEnabled = false;
|
|
105
|
-
this.failures = [];
|
|
106
|
-
this.filesWithMissingAvaImports = new Set();
|
|
107
|
-
this.filesWithoutDeclaredTests = new Set();
|
|
108
|
-
this.internalErrors = [];
|
|
109
|
-
this.knownFailures = [];
|
|
110
|
-
this.matching = false;
|
|
111
|
-
this.prefixTitle = (testFile, title) => title;
|
|
112
|
-
this.previousFailures = 0;
|
|
113
|
-
this.removePreviousListener = null;
|
|
114
|
-
this.stats = null;
|
|
115
|
-
this.uncaughtExceptions = [];
|
|
116
|
-
this.unhandledRejections = [];
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
startRun(plan) {
|
|
120
|
-
if (plan.bailWithoutReporting) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
this.reset();
|
|
125
|
-
|
|
126
|
-
this.failFastEnabled = plan.failFastEnabled;
|
|
127
|
-
this.matching = plan.matching;
|
|
128
|
-
this.previousFailures = plan.previousFailures;
|
|
129
|
-
|
|
130
|
-
if (this.watching || plan.files.length > 1) {
|
|
131
|
-
this.prefixTitle = (testFile, title) => prefixTitle(plan.filePathPrefix, testFile, title);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
this.removePreviousListener = plan.status.on('stateChange', evt => this.consumeStateChange(evt));
|
|
135
|
-
|
|
136
|
-
if (this.watching && plan.runVector > 1) {
|
|
137
|
-
this.reportStream.write(chalk.gray.dim('\u2500'.repeat(this.lineWriter.columns)) + os.EOL);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
cliCursor.hide(this.reportStream);
|
|
141
|
-
this.lineWriter.writeLine();
|
|
142
|
-
|
|
143
|
-
this.spinner.start();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
consumeStateChange(evt) { // eslint-disable-line complexity
|
|
147
|
-
switch (evt.type) {
|
|
148
|
-
case 'declared-test':
|
|
149
|
-
// Ignore
|
|
150
|
-
break;
|
|
151
|
-
case 'hook-failed':
|
|
152
|
-
this.failures.push(evt);
|
|
153
|
-
this.writeTestSummary(evt);
|
|
154
|
-
break;
|
|
155
|
-
case 'internal-error':
|
|
156
|
-
this.internalErrors.push(evt);
|
|
157
|
-
if (evt.testFile) {
|
|
158
|
-
this.writeWithCounts(colors.error(`${figures.cross} Internal error when running ${this.relativeFile(evt.testFile)}`));
|
|
159
|
-
} else {
|
|
160
|
-
this.writeWithCounts(colors.error(`${figures.cross} Internal error`));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
break;
|
|
164
|
-
case 'missing-ava-import':
|
|
165
|
-
this.filesWithMissingAvaImports.add(evt.testFile);
|
|
166
|
-
this.writeWithCounts(colors.error(`${figures.cross} No tests found in ${this.relativeFile(evt.testFile)}, make sure to import "ava" at the top of your test file`));
|
|
167
|
-
break;
|
|
168
|
-
case 'selected-test':
|
|
169
|
-
// Ignore
|
|
170
|
-
break;
|
|
171
|
-
case 'stats':
|
|
172
|
-
this.stats = evt.stats;
|
|
173
|
-
break;
|
|
174
|
-
case 'test-failed':
|
|
175
|
-
this.failures.push(evt);
|
|
176
|
-
this.writeTestSummary(evt);
|
|
177
|
-
break;
|
|
178
|
-
case 'test-passed':
|
|
179
|
-
if (evt.knownFailing) {
|
|
180
|
-
this.knownFailures.push(evt);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
this.writeTestSummary(evt);
|
|
184
|
-
break;
|
|
185
|
-
case 'timeout':
|
|
186
|
-
this.lineWriter.writeLine(colors.error(`\n${figures.cross} Timed out while running tests`));
|
|
187
|
-
this.lineWriter.writeLine('');
|
|
188
|
-
this.writePendingTests(evt);
|
|
189
|
-
break;
|
|
190
|
-
case 'interrupt':
|
|
191
|
-
this.lineWriter.writeLine(colors.error(`\n${figures.cross} Exiting due to SIGINT`));
|
|
192
|
-
this.lineWriter.writeLine('');
|
|
193
|
-
this.writePendingTests(evt);
|
|
194
|
-
break;
|
|
195
|
-
case 'uncaught-exception':
|
|
196
|
-
this.uncaughtExceptions.push(evt);
|
|
197
|
-
break;
|
|
198
|
-
case 'unhandled-rejection':
|
|
199
|
-
this.unhandledRejections.push(evt);
|
|
200
|
-
break;
|
|
201
|
-
case 'worker-failed':
|
|
202
|
-
if (this.stats.byFile.get(evt.testFile).declaredTests === 0) {
|
|
203
|
-
this.filesWithoutDeclaredTests.add(evt.testFile);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
break;
|
|
207
|
-
case 'worker-finished':
|
|
208
|
-
if (this.stats.byFile.get(evt.testFile).declaredTests === 0) {
|
|
209
|
-
this.filesWithoutDeclaredTests.add(evt.testFile);
|
|
210
|
-
this.writeWithCounts(colors.error(`${figures.cross} No tests found in ${this.relativeFile(evt.testFile)}`));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
break;
|
|
214
|
-
case 'worker-stderr':
|
|
215
|
-
case 'worker-stdout':
|
|
216
|
-
// Forcibly clear the spinner, writing the chunk corrupts the TTY.
|
|
217
|
-
this.spinner.clear();
|
|
218
|
-
|
|
219
|
-
this.stdStream.write(evt.chunk);
|
|
220
|
-
// If the chunk does not end with a linebreak, *forcibly* write one to
|
|
221
|
-
// ensure it remains visible in the TTY.
|
|
222
|
-
// Tests cannot assume their standard output is not interrupted. Indeed
|
|
223
|
-
// we multiplex stdout and stderr into a single stream. However as
|
|
224
|
-
// long as stdStream is different from reportStream users can read
|
|
225
|
-
// their original output by redirecting the streams.
|
|
226
|
-
if (evt.chunk[evt.chunk.length - 1] !== 0x0A) {
|
|
227
|
-
// Use write() rather than writeLine() so the (presumably corked)
|
|
228
|
-
// line writer will actually write the empty line before re-rendering
|
|
229
|
-
// the last spinner text below.
|
|
230
|
-
this.lineWriter.write(os.EOL);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
this.lineWriter.write(this.lineWriter.lastSpinnerText);
|
|
234
|
-
break;
|
|
235
|
-
default:
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
writeWithCounts(string) {
|
|
241
|
-
if (!this.stats) {
|
|
242
|
-
return this.lineWriter.writeLine(string);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
string = string || '';
|
|
246
|
-
if (string !== '') {
|
|
247
|
-
string += os.EOL;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
let firstLinePostfix = this.watching ?
|
|
251
|
-
' ' + chalk.gray.dim('[' + new Date().toLocaleTimeString('en-US', {hour12: false}) + ']') :
|
|
252
|
-
'';
|
|
253
|
-
|
|
254
|
-
if (this.stats.passedTests > 0) {
|
|
255
|
-
string += os.EOL + colors.pass(`${this.stats.passedTests} passed`) + firstLinePostfix;
|
|
256
|
-
firstLinePostfix = '';
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (this.stats.passedKnownFailingTests > 0) {
|
|
260
|
-
string += os.EOL + colors.error(`${this.stats.passedKnownFailingTests} ${plur('known failure', this.stats.passedKnownFailingTests)}`);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (this.stats.failedHooks > 0) {
|
|
264
|
-
string += os.EOL + colors.error(`${this.stats.failedHooks} ${plur('hook', this.stats.failedHooks)} failed`) + firstLinePostfix;
|
|
265
|
-
firstLinePostfix = '';
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (this.stats.failedTests > 0) {
|
|
269
|
-
string += os.EOL + colors.error(`${this.stats.failedTests} ${plur('test', this.stats.failedTests)} failed`) + firstLinePostfix;
|
|
270
|
-
firstLinePostfix = '';
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (this.stats.skippedTests > 0) {
|
|
274
|
-
string += os.EOL + colors.skip(`${this.stats.skippedTests} skipped`);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (this.stats.todoTests > 0) {
|
|
278
|
-
string += os.EOL + colors.todo(`${this.stats.todoTests} todo`);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this.lineWriter.writeLine(string);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
writeErr(evt) {
|
|
285
|
-
if (evt.err.name === 'TSError' && evt.err.object && evt.err.object.diagnosticText) {
|
|
286
|
-
this.lineWriter.writeLine(colors.errorStack(trimOffNewlines(evt.err.object.diagnosticText)));
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (evt.err.source) {
|
|
291
|
-
this.lineWriter.writeLine(colors.errorSource(`${this.relativeFile(evt.err.source.file)}:${evt.err.source.line}`));
|
|
292
|
-
const excerpt = codeExcerpt(evt.err.source, {maxWidth: this.lineWriter.columns - 2});
|
|
293
|
-
if (excerpt) {
|
|
294
|
-
this.lineWriter.writeLine();
|
|
295
|
-
this.lineWriter.writeLine(excerpt);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (evt.err.avaAssertionError) {
|
|
300
|
-
const result = formatSerializedError(evt.err);
|
|
301
|
-
if (result.printMessage) {
|
|
302
|
-
this.lineWriter.writeLine();
|
|
303
|
-
this.lineWriter.writeLine(evt.err.message);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (result.formatted) {
|
|
307
|
-
this.lineWriter.writeLine();
|
|
308
|
-
this.lineWriter.writeLine(result.formatted);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const message = improperUsageMessages.forError(evt.err);
|
|
312
|
-
if (message) {
|
|
313
|
-
this.lineWriter.writeLine();
|
|
314
|
-
this.lineWriter.writeLine(message);
|
|
315
|
-
}
|
|
316
|
-
} else if (evt.err.nonErrorObject) {
|
|
317
|
-
this.lineWriter.writeLine(trimOffNewlines(evt.err.formatted));
|
|
318
|
-
} else {
|
|
319
|
-
this.lineWriter.writeLine();
|
|
320
|
-
this.lineWriter.writeLine(evt.err.summary);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (evt.err.stack) {
|
|
324
|
-
const {stack} = evt.err;
|
|
325
|
-
if (stack.includes(os.EOL)) {
|
|
326
|
-
this.lineWriter.writeLine();
|
|
327
|
-
this.lineWriter.writeLine(colors.errorStack(stack));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
writeLogs(evt) {
|
|
333
|
-
if (evt.logs) {
|
|
334
|
-
for (const log of evt.logs) {
|
|
335
|
-
const logLines = indentString(colors.log(log), 4);
|
|
336
|
-
const logLinesWithLeadingFigure = logLines.replace(
|
|
337
|
-
/^ {4}/,
|
|
338
|
-
` ${colors.information(figures.info)} `
|
|
339
|
-
);
|
|
340
|
-
this.lineWriter.writeLine(logLinesWithLeadingFigure);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
writeTestSummary(evt) {
|
|
346
|
-
if (evt.type === 'hook-failed' || evt.type === 'test-failed') {
|
|
347
|
-
this.writeWithCounts(`${this.prefixTitle(evt.testFile, evt.title)}`);
|
|
348
|
-
} else if (evt.knownFailing) {
|
|
349
|
-
this.writeWithCounts(`${colors.error(this.prefixTitle(evt.testFile, evt.title))}`);
|
|
350
|
-
} else {
|
|
351
|
-
this.writeWithCounts(`${this.prefixTitle(evt.testFile, evt.title)}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
writeFailure(evt) {
|
|
356
|
-
this.lineWriter.writeLine(`${colors.title(this.prefixTitle(evt.testFile, evt.title))}`);
|
|
357
|
-
this.writeLogs(evt);
|
|
358
|
-
this.lineWriter.writeLine();
|
|
359
|
-
this.writeErr(evt);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
writePendingTests(evt) {
|
|
363
|
-
for (const [file, testsInFile] of evt.pendingTests) {
|
|
364
|
-
if (testsInFile.size === 0) {
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
this.lineWriter.writeLine(`${testsInFile.size} tests were pending in ${this.relativeFile(file)}\n`);
|
|
369
|
-
for (const title of testsInFile) {
|
|
370
|
-
this.lineWriter.writeLine(`${figures.circleDotted} ${this.prefixTitle(file, title)}`);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
this.lineWriter.writeLine('');
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
endRun() { // eslint-disable-line complexity
|
|
378
|
-
this.spinner.stop();
|
|
379
|
-
cliCursor.show(this.reportStream);
|
|
380
|
-
|
|
381
|
-
if (!this.stats) {
|
|
382
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} Couldn’t find any files to test`));
|
|
383
|
-
this.lineWriter.writeLine();
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (this.matching && this.stats.selectedTests === 0) {
|
|
388
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} Couldn’t find any matching tests`));
|
|
389
|
-
this.lineWriter.writeLine();
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
this.lineWriter.writeLine();
|
|
394
|
-
|
|
395
|
-
let firstLinePostfix = this.watching ?
|
|
396
|
-
' ' + chalk.gray.dim('[' + new Date().toLocaleTimeString('en-US', {hour12: false}) + ']') :
|
|
397
|
-
'';
|
|
398
|
-
|
|
399
|
-
if (this.filesWithMissingAvaImports.size > 0) {
|
|
400
|
-
for (const testFile of this.filesWithMissingAvaImports) {
|
|
401
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} No tests found in ${this.relativeFile(testFile)}, make sure to import "ava" at the top of your test file`) + firstLinePostfix);
|
|
402
|
-
firstLinePostfix = '';
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (this.filesWithoutDeclaredTests.size > 0) {
|
|
407
|
-
for (const testFile of this.filesWithoutDeclaredTests) {
|
|
408
|
-
if (!this.filesWithMissingAvaImports.has(testFile)) {
|
|
409
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} No tests found in ${this.relativeFile(testFile)}`) + firstLinePostfix);
|
|
410
|
-
firstLinePostfix = '';
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (this.filesWithMissingAvaImports.size > 0 || this.filesWithoutDeclaredTests.size > 0) {
|
|
416
|
-
this.lineWriter.writeLine();
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (this.stats.failedHooks > 0) {
|
|
420
|
-
this.lineWriter.writeLine(colors.error(`${this.stats.failedHooks} ${plur('hook', this.stats.failedHooks)} failed`) + firstLinePostfix);
|
|
421
|
-
firstLinePostfix = '';
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (this.stats.failedTests > 0) {
|
|
425
|
-
this.lineWriter.writeLine(colors.error(`${this.stats.failedTests} ${plur('test', this.stats.failedTests)} failed`) + firstLinePostfix);
|
|
426
|
-
firstLinePostfix = '';
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (this.stats.failedHooks === 0 && this.stats.failedTests === 0 && this.stats.passedTests > 0) {
|
|
430
|
-
this.lineWriter.writeLine(colors.pass(`${this.stats.passedTests} ${plur('test', this.stats.passedTests)} passed`) + firstLinePostfix);
|
|
431
|
-
firstLinePostfix = '';
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (this.stats.passedKnownFailingTests > 0) {
|
|
435
|
-
this.lineWriter.writeLine(colors.error(`${this.stats.passedKnownFailingTests} ${plur('known failure', this.stats.passedKnownFailingTests)}`));
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if (this.stats.skippedTests > 0) {
|
|
439
|
-
this.lineWriter.writeLine(colors.skip(`${this.stats.skippedTests} ${plur('test', this.stats.skippedTests)} skipped`));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (this.stats.todoTests > 0) {
|
|
443
|
-
this.lineWriter.writeLine(colors.todo(`${this.stats.todoTests} ${plur('test', this.stats.todoTests)} todo`));
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (this.stats.unhandledRejections > 0) {
|
|
447
|
-
this.lineWriter.writeLine(colors.error(`${this.stats.unhandledRejections} unhandled ${plur('rejection', this.stats.unhandledRejections)}`));
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
if (this.stats.uncaughtExceptions > 0) {
|
|
451
|
-
this.lineWriter.writeLine(colors.error(`${this.stats.uncaughtExceptions} uncaught ${plur('exception', this.stats.uncaughtExceptions)}`));
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (this.previousFailures > 0) {
|
|
455
|
-
this.lineWriter.writeLine(colors.error(`${this.previousFailures} previous ${plur('failure', this.previousFailures)} in test files that were not rerun`));
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
if (this.stats.passedKnownFailingTests > 0) {
|
|
459
|
-
this.lineWriter.writeLine();
|
|
460
|
-
for (const evt of this.knownFailures) {
|
|
461
|
-
this.lineWriter.writeLine(colors.error(this.prefixTitle(evt.testFile, evt.title)));
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const shouldWriteFailFastDisclaimer = this.failFastEnabled && (this.stats.remainingTests > 0 || this.stats.files > this.stats.finishedWorkers);
|
|
466
|
-
|
|
467
|
-
if (this.failures.length > 0) {
|
|
468
|
-
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.internalErrors.length > 0 || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;
|
|
469
|
-
this.lineWriter.writeLine();
|
|
470
|
-
|
|
471
|
-
const last = this.failures[this.failures.length - 1];
|
|
472
|
-
for (const evt of this.failures) {
|
|
473
|
-
this.writeFailure(evt);
|
|
474
|
-
if (evt !== last || writeTrailingLines) {
|
|
475
|
-
this.lineWriter.writeLine();
|
|
476
|
-
this.lineWriter.writeLine();
|
|
477
|
-
this.lineWriter.writeLine();
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
if (this.internalErrors.length > 0) {
|
|
483
|
-
const writeLeadingLine = this.failures.length === 0;
|
|
484
|
-
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;
|
|
485
|
-
|
|
486
|
-
if (writeLeadingLine) {
|
|
487
|
-
this.lineWriter.writeLine();
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const last = this.internalErrors[this.internalErrors.length - 1];
|
|
491
|
-
for (const evt of this.internalErrors) {
|
|
492
|
-
if (evt.testFile) {
|
|
493
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} Internal error when running ${this.relativeFile(evt.testFile)}`));
|
|
494
|
-
} else {
|
|
495
|
-
this.lineWriter.writeLine(colors.error(`${figures.cross} Internal error`));
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
this.lineWriter.writeLine(colors.stack(evt.err.summary));
|
|
499
|
-
this.lineWriter.writeLine(colors.errorStack(evt.err.stack));
|
|
500
|
-
if (evt !== last || writeTrailingLines) {
|
|
501
|
-
this.lineWriter.writeLine();
|
|
502
|
-
this.lineWriter.writeLine();
|
|
503
|
-
this.lineWriter.writeLine();
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (this.uncaughtExceptions.length > 0) {
|
|
509
|
-
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0;
|
|
510
|
-
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.unhandledRejections.length > 0;
|
|
511
|
-
|
|
512
|
-
if (writeLeadingLine) {
|
|
513
|
-
this.lineWriter.writeLine();
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const last = this.uncaughtExceptions[this.uncaughtExceptions.length - 1];
|
|
517
|
-
for (const evt of this.uncaughtExceptions) {
|
|
518
|
-
this.lineWriter.writeLine(colors.title(`Uncaught exception in ${this.relativeFile(evt.testFile)}`));
|
|
519
|
-
this.lineWriter.writeLine();
|
|
520
|
-
this.writeErr(evt);
|
|
521
|
-
if (evt !== last || writeTrailingLines) {
|
|
522
|
-
this.lineWriter.writeLine();
|
|
523
|
-
this.lineWriter.writeLine();
|
|
524
|
-
this.lineWriter.writeLine();
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (this.unhandledRejections.length > 0) {
|
|
530
|
-
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0 && this.uncaughtExceptions.length === 0;
|
|
531
|
-
const writeTrailingLines = shouldWriteFailFastDisclaimer;
|
|
532
|
-
|
|
533
|
-
if (writeLeadingLine) {
|
|
534
|
-
this.lineWriter.writeLine();
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const last = this.unhandledRejections[this.unhandledRejections.length - 1];
|
|
538
|
-
for (const evt of this.unhandledRejections) {
|
|
539
|
-
this.lineWriter.writeLine(colors.title(`Unhandled rejection in ${this.relativeFile(evt.testFile)}`));
|
|
540
|
-
this.lineWriter.writeLine();
|
|
541
|
-
this.writeErr(evt);
|
|
542
|
-
if (evt !== last || writeTrailingLines) {
|
|
543
|
-
this.lineWriter.writeLine();
|
|
544
|
-
this.lineWriter.writeLine();
|
|
545
|
-
this.lineWriter.writeLine();
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (shouldWriteFailFastDisclaimer) {
|
|
551
|
-
let remaining = '';
|
|
552
|
-
if (this.stats.remainingTests > 0) {
|
|
553
|
-
remaining += `At least ${this.stats.remainingTests} ${plur('test was', 'tests were', this.stats.remainingTests)} skipped`;
|
|
554
|
-
if (this.stats.files > this.stats.finishedWorkers) {
|
|
555
|
-
remaining += ', as well as ';
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
if (this.stats.files > this.stats.finishedWorkers) {
|
|
560
|
-
const skippedFileCount = this.stats.files - this.stats.finishedWorkers;
|
|
561
|
-
remaining += `${skippedFileCount} ${plur('test file', 'test files', skippedFileCount)}`;
|
|
562
|
-
if (this.stats.remainingTests === 0) {
|
|
563
|
-
remaining += ` ${plur('was', 'were', skippedFileCount)} skipped`;
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
this.lineWriter.writeLine(colors.information(`\`--fail-fast\` is on. ${remaining}.`));
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
this.lineWriter.writeLine();
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
module.exports = MiniReporter;
|