ava 3.15.0 → 4.0.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/entrypoints/cli.mjs +4 -0
- package/entrypoints/eslint-plugin-helper.cjs +109 -0
- package/entrypoints/main.cjs +2 -0
- package/entrypoints/main.mjs +1 -0
- package/entrypoints/plugin.cjs +2 -0
- package/entrypoints/plugin.mjs +4 -0
- package/index.d.ts +6 -816
- package/lib/api.js +108 -49
- package/lib/assert.js +255 -270
- package/lib/chalk.js +9 -14
- package/lib/cli.js +118 -112
- package/lib/code-excerpt.js +12 -17
- package/lib/concordance-options.js +29 -65
- package/lib/context-ref.js +3 -6
- package/lib/create-chain.js +32 -20
- package/lib/environment-variables.js +1 -4
- package/lib/eslint-plugin-helper-worker.js +73 -0
- package/lib/extensions.js +2 -2
- package/lib/fork.js +81 -84
- package/lib/glob-helpers.cjs +140 -0
- package/lib/globs.js +136 -163
- package/lib/{ipc-flow-control.js → ipc-flow-control.cjs} +1 -0
- package/lib/is-ci.js +4 -2
- package/lib/like-selector.js +7 -13
- package/lib/line-numbers.js +11 -18
- package/lib/load-config.js +56 -180
- package/lib/module-types.js +3 -7
- package/lib/node-arguments.js +4 -5
- package/lib/{now-and-timers.js → now-and-timers.cjs} +0 -0
- package/lib/parse-test-args.js +22 -11
- package/lib/pkg.cjs +2 -0
- package/lib/plugin-support/shared-worker-loader.js +45 -48
- package/lib/plugin-support/shared-workers.js +24 -46
- package/lib/provider-manager.js +20 -14
- package/lib/reporters/beautify-stack.js +6 -12
- package/lib/reporters/colors.js +40 -15
- package/lib/reporters/default.js +114 -364
- package/lib/reporters/format-serialized-error.js +7 -18
- package/lib/reporters/improper-usage-messages.js +8 -9
- package/lib/reporters/prefix-title.js +17 -15
- package/lib/reporters/tap.js +18 -25
- package/lib/run-status.js +29 -23
- package/lib/runner.js +157 -172
- package/lib/scheduler.js +53 -0
- package/lib/serialize-error.js +61 -64
- package/lib/snapshot-manager.js +271 -289
- package/lib/test.js +135 -291
- package/lib/watcher.js +69 -44
- package/lib/worker/base.js +208 -0
- package/lib/worker/channel.cjs +290 -0
- package/lib/worker/dependency-tracker.js +24 -23
- package/lib/worker/{ensure-forked.js → guard-environment.cjs} +5 -4
- package/lib/worker/line-numbers.js +58 -20
- package/lib/worker/main.cjs +12 -0
- package/lib/worker/{options.js → options.cjs} +0 -0
- package/lib/worker/{plugin.js → plugin.cjs} +30 -21
- package/lib/worker/state.cjs +5 -0
- package/lib/worker/utils.cjs +6 -0
- package/package.json +71 -68
- package/plugin.d.ts +51 -53
- package/readme.md +5 -13
- package/types/assertions.d.ts +327 -0
- package/types/subscribable.ts +6 -0
- package/types/test-fn.d.ts +231 -0
- package/types/try-fn.d.ts +58 -0
- package/cli.js +0 -11
- package/eslint-plugin-helper.js +0 -201
- package/index.js +0 -8
- package/lib/worker/ipc.js +0 -201
- package/lib/worker/main.js +0 -21
- package/lib/worker/subprocess.js +0 -266
- package/plugin.js +0 -9
package/lib/watcher.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import nodePath from 'node:path';
|
|
2
|
+
|
|
3
|
+
import chokidar_ from 'chokidar';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
|
|
6
|
+
import {chalk} from './chalk.js';
|
|
7
|
+
import {applyTestFileFilter, classify, getChokidarIgnorePatterns} from './globs.js';
|
|
8
|
+
|
|
9
|
+
let chokidar = chokidar_;
|
|
10
|
+
export function _testOnlyReplaceChokidar(replacement) {
|
|
11
|
+
chokidar = replacement;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let debug = createDebug('ava:watcher');
|
|
15
|
+
export function _testOnlyReplaceDebug(replacement) {
|
|
16
|
+
debug = replacement('ava:watcher');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function rethrowAsync(error) {
|
|
12
20
|
// Don't swallow exceptions. Note that any
|
|
13
21
|
// expected error should already have been logged
|
|
14
22
|
setImmediate(() => {
|
|
15
|
-
throw
|
|
23
|
+
throw error;
|
|
16
24
|
});
|
|
17
25
|
}
|
|
18
26
|
|
|
@@ -77,7 +85,7 @@ class TestDependency {
|
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
class Watcher {
|
|
88
|
+
export default class Watcher {
|
|
81
89
|
constructor({api, filter = [], globs, projectDir, providers, reporter}) {
|
|
82
90
|
this.debouncer = new Debouncer(this);
|
|
83
91
|
|
|
@@ -88,7 +96,7 @@ class Watcher {
|
|
|
88
96
|
|
|
89
97
|
const patternFilters = filter.map(({pattern}) => pattern);
|
|
90
98
|
|
|
91
|
-
this.providers = providers
|
|
99
|
+
this.providers = providers;
|
|
92
100
|
this.run = (specificFiles = [], updateSnapshots = false) => {
|
|
93
101
|
const clearLogOnNextRun = this.clearLogOnNextRun && this.runVector > 0;
|
|
94
102
|
if (this.runVector > 0) {
|
|
@@ -104,12 +112,18 @@ class Watcher {
|
|
|
104
112
|
if (runOnlyExclusive) {
|
|
105
113
|
// The test files that previously contained exclusive tests are always
|
|
106
114
|
// run, together with the remaining specific files.
|
|
107
|
-
const remainingFiles =
|
|
108
|
-
specificFiles = this.filesWithExclusiveTests
|
|
115
|
+
const remainingFiles = specificFiles.filter(file => !exclusiveFiles.includes(file));
|
|
116
|
+
specificFiles = [...this.filesWithExclusiveTests, ...remainingFiles];
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
if (filter.length > 0) {
|
|
112
|
-
specificFiles = applyTestFileFilter({
|
|
120
|
+
specificFiles = applyTestFileFilter({
|
|
121
|
+
cwd: projectDir,
|
|
122
|
+
expandDirectories: false,
|
|
123
|
+
filter: patternFilters,
|
|
124
|
+
testFiles: specificFiles,
|
|
125
|
+
treatFilterPatternsAsFiles: false,
|
|
126
|
+
});
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
this.pruneFailures(specificFiles);
|
|
@@ -125,21 +139,21 @@ class Watcher {
|
|
|
125
139
|
previousFailures: this.sumPreviousFailures(this.runVector),
|
|
126
140
|
runOnlyExclusive,
|
|
127
141
|
runVector: this.runVector,
|
|
128
|
-
updateSnapshots: updateSnapshots === true
|
|
129
|
-
}
|
|
142
|
+
updateSnapshots: updateSnapshots === true,
|
|
143
|
+
},
|
|
130
144
|
})
|
|
131
|
-
.then(runStatus => {
|
|
145
|
+
.then(runStatus => {
|
|
132
146
|
reporter.endRun();
|
|
133
147
|
reporter.lineWriter.writeLine(END_MESSAGE);
|
|
134
148
|
|
|
135
149
|
if (this.clearLogOnNextRun && (
|
|
136
|
-
runStatus.stats.failedHooks > 0
|
|
137
|
-
runStatus.stats.failedTests > 0
|
|
138
|
-
runStatus.stats.failedWorkers > 0
|
|
139
|
-
runStatus.stats.internalErrors > 0
|
|
140
|
-
runStatus.stats.timeouts > 0
|
|
141
|
-
runStatus.stats.uncaughtExceptions > 0
|
|
142
|
-
runStatus.stats.unhandledRejections > 0
|
|
150
|
+
runStatus.stats.failedHooks > 0
|
|
151
|
+
|| runStatus.stats.failedTests > 0
|
|
152
|
+
|| runStatus.stats.failedWorkers > 0
|
|
153
|
+
|| runStatus.stats.internalErrors > 0
|
|
154
|
+
|| runStatus.stats.timeouts > 0
|
|
155
|
+
|| runStatus.stats.uncaughtExceptions > 0
|
|
156
|
+
|| runStatus.stats.unhandledRejections > 0
|
|
143
157
|
)) {
|
|
144
158
|
this.clearLogOnNextRun = false;
|
|
145
159
|
}
|
|
@@ -150,6 +164,7 @@ class Watcher {
|
|
|
150
164
|
this.testDependencies = [];
|
|
151
165
|
this.trackTestDependencies(api);
|
|
152
166
|
|
|
167
|
+
this.temporaryFiles = new Set();
|
|
153
168
|
this.touchedFiles = new Set();
|
|
154
169
|
this.trackTouchedFiles(api);
|
|
155
170
|
|
|
@@ -168,7 +183,7 @@ class Watcher {
|
|
|
168
183
|
chokidar.watch(['**/*'], {
|
|
169
184
|
cwd: this.globs.cwd,
|
|
170
185
|
ignored: getChokidarIgnorePatterns(this.globs),
|
|
171
|
-
ignoreInitial: true
|
|
186
|
+
ignoreInitial: true,
|
|
172
187
|
}).on('all', (event, path) => {
|
|
173
188
|
if (event === 'add' || event === 'change' || event === 'unlink') {
|
|
174
189
|
debug('Detected %s of %s', event, path);
|
|
@@ -231,9 +246,13 @@ class Watcher {
|
|
|
231
246
|
return;
|
|
232
247
|
}
|
|
233
248
|
|
|
234
|
-
for (const file of evt.files) {
|
|
249
|
+
for (const file of evt.files.changedFiles) {
|
|
235
250
|
this.touchedFiles.add(file);
|
|
236
251
|
}
|
|
252
|
+
|
|
253
|
+
for (const file of evt.files.temporaryFiles) {
|
|
254
|
+
this.temporaryFiles.add(file);
|
|
255
|
+
}
|
|
237
256
|
});
|
|
238
257
|
});
|
|
239
258
|
}
|
|
@@ -307,7 +326,7 @@ class Watcher {
|
|
|
307
326
|
this.filesWithFailures.push({
|
|
308
327
|
file,
|
|
309
328
|
vector,
|
|
310
|
-
count: 1
|
|
329
|
+
count: 1,
|
|
311
330
|
});
|
|
312
331
|
}
|
|
313
332
|
}
|
|
@@ -379,6 +398,14 @@ class Watcher {
|
|
|
379
398
|
return false;
|
|
380
399
|
}
|
|
381
400
|
|
|
401
|
+
// Unlike touched files, temporary files are never cleared. We may see
|
|
402
|
+
// adds and unlinks detected separately, so we track the temporary files
|
|
403
|
+
// as long as AVA is running.
|
|
404
|
+
if (this.temporaryFiles.has(path)) {
|
|
405
|
+
debug('Ignoring known temporary file %s', path);
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
382
409
|
return true;
|
|
383
410
|
});
|
|
384
411
|
|
|
@@ -394,21 +421,23 @@ class Watcher {
|
|
|
394
421
|
}
|
|
395
422
|
|
|
396
423
|
const dirtyHelpersAndSources = [];
|
|
397
|
-
const
|
|
424
|
+
const addedOrChangedTests = [];
|
|
425
|
+
const unlinkedTests = [];
|
|
398
426
|
for (const filePath of dirtyPaths) {
|
|
399
427
|
const {isIgnoredByWatcher, isTest} = classify(filePath, this.globs);
|
|
400
428
|
if (!isIgnoredByWatcher) {
|
|
401
429
|
if (isTest) {
|
|
402
|
-
|
|
430
|
+
if (dirtyStates[filePath] === 'unlink') {
|
|
431
|
+
unlinkedTests.push(filePath);
|
|
432
|
+
} else {
|
|
433
|
+
addedOrChangedTests.push(filePath);
|
|
434
|
+
}
|
|
403
435
|
} else {
|
|
404
436
|
dirtyHelpersAndSources.push(filePath);
|
|
405
437
|
}
|
|
406
438
|
}
|
|
407
439
|
}
|
|
408
440
|
|
|
409
|
-
const addedOrChangedTests = dirtyTests.filter(path => dirtyStates[path] !== 'unlink');
|
|
410
|
-
const unlinkedTests = diff(dirtyTests, addedOrChangedTests);
|
|
411
|
-
|
|
412
441
|
this.cleanUnlinkedTests(unlinkedTests);
|
|
413
442
|
|
|
414
443
|
// No need to rerun tests if the only change is that tests were deleted
|
|
@@ -423,12 +452,10 @@ class Watcher {
|
|
|
423
452
|
}
|
|
424
453
|
|
|
425
454
|
// Try to find tests that depend on the changed source files
|
|
426
|
-
const testsByHelpersOrSource = dirtyHelpersAndSources.map(path => {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
});
|
|
431
|
-
}, this).filter(tests => tests.length > 0);
|
|
455
|
+
const testsByHelpersOrSource = dirtyHelpersAndSources.map(path => this.testDependencies.filter(dep => dep.contains(path)).map(dep => {
|
|
456
|
+
debug('%s is a dependency of %s', path, dep.file);
|
|
457
|
+
return dep.file;
|
|
458
|
+
})).filter(tests => tests.length > 0);
|
|
432
459
|
|
|
433
460
|
// Rerun all tests if source files were changed that could not be traced to
|
|
434
461
|
// specific tests
|
|
@@ -440,8 +467,6 @@ class Watcher {
|
|
|
440
467
|
}
|
|
441
468
|
|
|
442
469
|
// Run all affected tests
|
|
443
|
-
this.run([...new Set(addedOrChangedTests.
|
|
470
|
+
this.run([...new Set([addedOrChangedTests, testsByHelpersOrSource].flat(2))]);
|
|
444
471
|
}
|
|
445
472
|
}
|
|
446
|
-
|
|
447
|
-
module.exports = Watcher;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {createRequire} from 'node:module';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import {pathToFileURL} from 'node:url';
|
|
4
|
+
import {workerData} from 'node:worker_threads';
|
|
5
|
+
|
|
6
|
+
import setUpCurrentlyUnhandled from 'currently-unhandled';
|
|
7
|
+
|
|
8
|
+
import {set as setChalk} from '../chalk.js';
|
|
9
|
+
import nowAndTimers from '../now-and-timers.cjs';
|
|
10
|
+
import providerManager from '../provider-manager.js';
|
|
11
|
+
import Runner from '../runner.js';
|
|
12
|
+
import serializeError from '../serialize-error.js';
|
|
13
|
+
|
|
14
|
+
import channel from './channel.cjs';
|
|
15
|
+
import dependencyTracking from './dependency-tracker.js';
|
|
16
|
+
import lineNumberSelection from './line-numbers.js';
|
|
17
|
+
import {set as setOptions} from './options.cjs';
|
|
18
|
+
import {flags, refs, sharedWorkerTeardowns} from './state.cjs';
|
|
19
|
+
import {isRunningInThread, isRunningInChildProcess} from './utils.cjs';
|
|
20
|
+
|
|
21
|
+
const currentlyUnhandled = setUpCurrentlyUnhandled();
|
|
22
|
+
|
|
23
|
+
const run = async options => {
|
|
24
|
+
setOptions(options);
|
|
25
|
+
setChalk(options.chalkOptions);
|
|
26
|
+
|
|
27
|
+
if (options.chalkOptions.level > 0) {
|
|
28
|
+
const {stdout, stderr} = process;
|
|
29
|
+
global.console = Object.assign(global.console, new console.Console({stdout, stderr, colorMode: true}));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function exit(code) {
|
|
33
|
+
if (!process.exitCode) {
|
|
34
|
+
process.exitCode = code;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
dependencyTracking.flush();
|
|
38
|
+
await channel.flush();
|
|
39
|
+
process.exit(); // eslint-disable-line unicorn/no-process-exit
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let checkSelectedByLineNumbers;
|
|
43
|
+
try {
|
|
44
|
+
checkSelectedByLineNumbers = lineNumberSelection({
|
|
45
|
+
file: options.file,
|
|
46
|
+
lineNumbers: options.lineNumbers,
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
channel.send({type: 'line-number-selection-error', err: serializeError('Line number selection error', false, error, options.file)});
|
|
50
|
+
checkSelectedByLineNumbers = () => false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const runner = new Runner({
|
|
54
|
+
checkSelectedByLineNumbers,
|
|
55
|
+
experiments: options.experiments,
|
|
56
|
+
failFast: options.failFast,
|
|
57
|
+
failWithoutAssertions: options.failWithoutAssertions,
|
|
58
|
+
file: options.file,
|
|
59
|
+
match: options.match,
|
|
60
|
+
projectDir: options.projectDir,
|
|
61
|
+
recordNewSnapshots: options.recordNewSnapshots,
|
|
62
|
+
runOnlyExclusive: options.runOnlyExclusive,
|
|
63
|
+
serial: options.serial,
|
|
64
|
+
snapshotDir: options.snapshotDir,
|
|
65
|
+
updateSnapshots: options.updateSnapshots,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
refs.runnerChain = runner.chain;
|
|
69
|
+
|
|
70
|
+
channel.peerFailed.then(() => {
|
|
71
|
+
runner.interrupt();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
runner.on('dependency', dependencyTracking.track);
|
|
75
|
+
runner.on('stateChange', state => channel.send(state));
|
|
76
|
+
|
|
77
|
+
runner.on('error', error => {
|
|
78
|
+
channel.send({type: 'internal-error', err: serializeError('Internal runner error', false, error, runner.file)});
|
|
79
|
+
exit(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
runner.on('finish', async () => {
|
|
83
|
+
try {
|
|
84
|
+
const {touchedFiles} = runner.saveSnapshotState();
|
|
85
|
+
if (touchedFiles) {
|
|
86
|
+
channel.send({type: 'touched-files', files: touchedFiles});
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
channel.send({type: 'internal-error', err: serializeError('Internal runner error', false, error, runner.file)});
|
|
90
|
+
exit(1);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await Promise.all(sharedWorkerTeardowns.map(fn => fn()));
|
|
96
|
+
} catch (error) {
|
|
97
|
+
channel.send({type: 'uncaught-exception', err: serializeError('Shared worker teardown error', false, error, runner.file)});
|
|
98
|
+
exit(1);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
nowAndTimers.setImmediate(() => {
|
|
103
|
+
for (const rejection of currentlyUnhandled()) {
|
|
104
|
+
channel.send({type: 'unhandled-rejection', err: serializeError('Unhandled rejection', true, rejection.reason, runner.file)});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exit(0);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
process.on('uncaughtException', error => {
|
|
112
|
+
channel.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, error, runner.file)});
|
|
113
|
+
exit(1);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Store value to prevent required modules from modifying it.
|
|
117
|
+
const testPath = options.file;
|
|
118
|
+
|
|
119
|
+
const extensionsToLoadAsModules = Object.entries(options.moduleTypes)
|
|
120
|
+
.filter(([, type]) => type === 'module')
|
|
121
|
+
.map(([extension]) => extension);
|
|
122
|
+
|
|
123
|
+
// Install before processing options.require, so if helpers are added to the
|
|
124
|
+
// require configuration the *compiled* helper will be loaded.
|
|
125
|
+
const {projectDir, providerStates = []} = options;
|
|
126
|
+
const providers = [];
|
|
127
|
+
await Promise.all(providerStates.map(async ({type, state}) => {
|
|
128
|
+
if (type === 'typescript') {
|
|
129
|
+
const provider = await providerManager.typescript(projectDir);
|
|
130
|
+
providers.push(provider.worker({extensionsToLoadAsModules, state}));
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
133
|
+
|
|
134
|
+
const require = createRequire(import.meta.url);
|
|
135
|
+
const load = async ref => {
|
|
136
|
+
for (const provider of providers) {
|
|
137
|
+
if (provider.canLoad(ref)) {
|
|
138
|
+
return provider.load(ref, {requireFn: require});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const extension of extensionsToLoadAsModules) {
|
|
143
|
+
if (ref.endsWith(`.${extension}`)) {
|
|
144
|
+
return import(pathToFileURL(ref)); // eslint-disable-line node/no-unsupported-features/es-syntax
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// We still support require() since it's more easily monkey-patched.
|
|
149
|
+
return require(ref);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
for await (const ref of (options.require || [])) {
|
|
154
|
+
await load(ref);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Install dependency tracker after the require configuration has been evaluated
|
|
158
|
+
// to make sure we also track dependencies with custom require hooks
|
|
159
|
+
dependencyTracking.install(require.extensions, testPath);
|
|
160
|
+
|
|
161
|
+
if (options.debug && options.debug.port !== undefined && options.debug.host !== undefined) {
|
|
162
|
+
// If an inspector was active when the main process started, and is
|
|
163
|
+
// already active for the worker process, do not open a new one.
|
|
164
|
+
const {default: inspector} = await import('node:inspector'); // eslint-disable-line node/no-unsupported-features/es-syntax
|
|
165
|
+
if (!options.debug.active || inspector.url() === undefined) {
|
|
166
|
+
inspector.open(options.debug.port, options.debug.host, true);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (options.debug.break) {
|
|
170
|
+
debugger; // eslint-disable-line no-debugger
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await load(testPath);
|
|
175
|
+
|
|
176
|
+
if (flags.loadedMain) {
|
|
177
|
+
// Unreference the channel if the test file required AVA. This stops it
|
|
178
|
+
// from keeping the event loop busy, which means the `beforeExit` event can be
|
|
179
|
+
// used to detect when tests stall.
|
|
180
|
+
channel.unref();
|
|
181
|
+
} else {
|
|
182
|
+
channel.send({type: 'missing-ava-import'});
|
|
183
|
+
exit(1);
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
channel.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, error, runner.file)});
|
|
187
|
+
exit(1);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const onError = error => {
|
|
192
|
+
// There shouldn't be any errors, but if there are we may not have managed
|
|
193
|
+
// to bootstrap enough code to serialize them. Re-throw and let the process
|
|
194
|
+
// crash.
|
|
195
|
+
setImmediate(() => {
|
|
196
|
+
throw error;
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
if (isRunningInThread) {
|
|
201
|
+
channel.send({type: 'starting'}); // AVA won't terminate the worker thread until it's seen this message.
|
|
202
|
+
const {options} = workerData;
|
|
203
|
+
delete workerData.options; // Don't allow user code access.
|
|
204
|
+
run(options).catch(onError);
|
|
205
|
+
} else if (isRunningInChildProcess) {
|
|
206
|
+
channel.send({type: 'ready-for-options'});
|
|
207
|
+
channel.options.then(run).catch(onError);
|
|
208
|
+
}
|