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/readme.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Build Status](https://travis-ci.org/avajs/ava.svg?branch=master)](https://travis-ci.org/avajs/ava) [![Coverage Status](https://codecov.io/gh/avajs/ava/branch/master/graph/badge.svg)](https://codecov.io/gh/avajs/ava/branch/master) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/ava)
4
4
  [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs)
5
5
 
6
- Testing can be a drag. AVA helps you get it done. AVA is a test runner for Node.js with a concise API, detailed error output, embrace of new language features and process isolation that let you write tests more effectively. So you can ship more awesome code. 🚀
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
 
@@ -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
- };
@@ -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;