ava 4.0.0-alpha.1 → 4.0.1
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/{eslint-plugin-helper.js → entrypoints/eslint-plugin-helper.cjs} +20 -7
- 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 -709
- package/lib/api.js +95 -46
- package/lib/assert.js +122 -173
- package/lib/chalk.js +9 -14
- package/lib/cli.js +105 -97
- package/lib/code-excerpt.js +12 -17
- package/lib/concordance-options.js +30 -31
- package/lib/context-ref.js +3 -6
- package/lib/create-chain.js +32 -4
- package/lib/environment-variables.js +1 -4
- package/lib/eslint-plugin-helper-worker.js +16 -26
- package/lib/extensions.js +2 -2
- package/lib/fork.js +42 -83
- 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 +10 -17
- package/lib/load-config.js +62 -56
- package/lib/module-types.js +3 -3
- 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 -43
- package/lib/provider-manager.js +20 -14
- package/lib/reporters/beautify-stack.js +6 -11
- package/lib/reporters/colors.js +40 -15
- package/lib/reporters/default.js +115 -350
- 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 +15 -16
- package/lib/run-status.js +25 -23
- package/lib/runner.js +138 -127
- package/lib/scheduler.js +42 -36
- package/lib/serialize-error.js +34 -34
- package/lib/snapshot-manager.js +83 -76
- package/lib/test.js +114 -195
- package/lib/watcher.js +65 -40
- package/lib/worker/base.js +48 -99
- package/lib/worker/channel.cjs +290 -0
- package/lib/worker/dependency-tracker.js +22 -22
- package/lib/worker/guard-environment.cjs +19 -0
- package/lib/worker/line-numbers.js +57 -19
- package/lib/worker/main.cjs +12 -0
- package/lib/worker/{options.js → options.cjs} +0 -0
- package/lib/worker/{plugin.js → plugin.cjs} +31 -16
- package/lib/worker/state.cjs +5 -0
- package/lib/worker/{utils.js → utils.cjs} +1 -1
- package/package.json +60 -68
- package/plugin.d.ts +51 -53
- package/readme.md +5 -12
- 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/index.js +0 -8
- package/lib/worker/channel.js +0 -218
- package/lib/worker/main.js +0 -20
- package/plugin.js +0 -9
package/lib/api.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
|
|
6
|
+
import arrify from 'arrify';
|
|
7
|
+
import chunkd from 'chunkd';
|
|
8
|
+
import commonPathPrefix from 'common-path-prefix';
|
|
9
|
+
import Emittery from 'emittery';
|
|
10
|
+
import ms from 'ms';
|
|
11
|
+
import pMap from 'p-map';
|
|
12
|
+
import resolveCwd from 'resolve-cwd';
|
|
13
|
+
import tempDir from 'temp-dir';
|
|
14
|
+
|
|
15
|
+
import fork from './fork.js';
|
|
16
|
+
import * as globs from './globs.js';
|
|
17
|
+
import isCi from './is-ci.js';
|
|
18
|
+
import {getApplicableLineNumbers} from './line-numbers.js';
|
|
19
|
+
import {observeWorkerProcess} from './plugin-support/shared-workers.js';
|
|
20
|
+
import RunStatus from './run-status.js';
|
|
21
|
+
import scheduler from './scheduler.js';
|
|
22
|
+
import serializeError from './serialize-error.js';
|
|
22
23
|
|
|
23
24
|
function resolveModules(modules) {
|
|
24
25
|
return arrify(modules).map(name => {
|
|
@@ -41,7 +42,40 @@ function getFilePathPrefix(files) {
|
|
|
41
42
|
return commonPathPrefix(files);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
class
|
|
45
|
+
class TimeoutTrigger {
|
|
46
|
+
constructor(fn, waitMs = 0) {
|
|
47
|
+
this.fn = fn.bind(null);
|
|
48
|
+
this.ignoreUntil = 0;
|
|
49
|
+
this.waitMs = waitMs;
|
|
50
|
+
this.timer = undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
debounce() {
|
|
54
|
+
if (this.timer === undefined) {
|
|
55
|
+
this.timer = setTimeout(() => this.trigger(), this.waitMs);
|
|
56
|
+
} else {
|
|
57
|
+
this.timer.refresh();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
discard() {
|
|
62
|
+
// N.B. this.timer is not cleared so if debounce() is called after it will
|
|
63
|
+
// not run again.
|
|
64
|
+
clearTimeout(this.timer);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ignoreFor(periodMs) {
|
|
68
|
+
this.ignoreUntil = Math.max(this.ignoreUntil, Date.now() + periodMs);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
trigger() {
|
|
72
|
+
if (Date.now() >= this.ignoreUntil) {
|
|
73
|
+
this.fn();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default class Api extends Emittery {
|
|
45
79
|
constructor(options) {
|
|
46
80
|
super();
|
|
47
81
|
|
|
@@ -71,11 +105,11 @@ class Api extends Emittery {
|
|
|
71
105
|
let bailed = false;
|
|
72
106
|
const pendingWorkers = new Set();
|
|
73
107
|
const timedOutWorkerFiles = new Set();
|
|
74
|
-
let
|
|
108
|
+
let timeoutTrigger;
|
|
75
109
|
if (apiOptions.timeout && !apiOptions.debug) {
|
|
76
110
|
const timeout = ms(apiOptions.timeout);
|
|
77
111
|
|
|
78
|
-
|
|
112
|
+
timeoutTrigger = new TimeoutTrigger(() => {
|
|
79
113
|
// If failFast is active, prevent new test files from running after
|
|
80
114
|
// the current ones are exited.
|
|
81
115
|
if (failFast) {
|
|
@@ -90,7 +124,7 @@ class Api extends Emittery {
|
|
|
90
124
|
}
|
|
91
125
|
}, timeout);
|
|
92
126
|
} else {
|
|
93
|
-
|
|
127
|
+
timeoutTrigger = new TimeoutTrigger(() => {});
|
|
94
128
|
}
|
|
95
129
|
|
|
96
130
|
this._interruptHandler = () => {
|
|
@@ -103,7 +137,7 @@ class Api extends Emittery {
|
|
|
103
137
|
bailed = true;
|
|
104
138
|
|
|
105
139
|
// Make sure we don't run the timeout handler
|
|
106
|
-
|
|
140
|
+
timeoutTrigger.discard();
|
|
107
141
|
|
|
108
142
|
runStatus.emitStateChange({type: 'interrupt'});
|
|
109
143
|
|
|
@@ -112,6 +146,8 @@ class Api extends Emittery {
|
|
|
112
146
|
}
|
|
113
147
|
};
|
|
114
148
|
|
|
149
|
+
const {providers = []} = this.options;
|
|
150
|
+
|
|
115
151
|
let testFiles;
|
|
116
152
|
try {
|
|
117
153
|
testFiles = await globs.findTests({cwd: this.options.projectDir, ...apiOptions.globs});
|
|
@@ -119,7 +155,8 @@ class Api extends Emittery {
|
|
|
119
155
|
selectedFiles = filter.length === 0 ? testFiles : globs.applyTestFileFilter({
|
|
120
156
|
cwd: this.options.projectDir,
|
|
121
157
|
filter: filter.map(({pattern}) => pattern),
|
|
122
|
-
|
|
158
|
+
providers,
|
|
159
|
+
testFiles,
|
|
123
160
|
});
|
|
124
161
|
}
|
|
125
162
|
} catch (error) {
|
|
@@ -127,6 +164,13 @@ class Api extends Emittery {
|
|
|
127
164
|
setupOrGlobError = error;
|
|
128
165
|
}
|
|
129
166
|
|
|
167
|
+
const selectionInsights = {
|
|
168
|
+
filter,
|
|
169
|
+
ignoredFilterPatternFiles: selectedFiles.ignoredFilterPatternFiles || [],
|
|
170
|
+
testFileCount: testFiles.length,
|
|
171
|
+
selectionCount: selectedFiles.length,
|
|
172
|
+
};
|
|
173
|
+
|
|
130
174
|
try {
|
|
131
175
|
if (this.options.parallelRuns) {
|
|
132
176
|
const {currentIndex, totalRuns} = this.options.parallelRuns;
|
|
@@ -138,9 +182,9 @@ class Api extends Emittery {
|
|
|
138
182
|
|
|
139
183
|
const currentFileCount = selectedFiles.length;
|
|
140
184
|
|
|
141
|
-
runStatus = new RunStatus(fileCount, {currentFileCount, currentIndex, totalRuns});
|
|
185
|
+
runStatus = new RunStatus(fileCount, {currentFileCount, currentIndex, totalRuns}, selectionInsights);
|
|
142
186
|
} else {
|
|
143
|
-
runStatus = new RunStatus(selectedFiles.length, null);
|
|
187
|
+
runStatus = new RunStatus(selectedFiles.length, null, selectionInsights);
|
|
144
188
|
}
|
|
145
189
|
|
|
146
190
|
selectedFiles = scheduler.failingTestsFirst(selectedFiles, this._getLocalCacheDir(), this.options.cacheEnabled);
|
|
@@ -158,7 +202,7 @@ class Api extends Emittery {
|
|
|
158
202
|
previousFailures: runtimeOptions.previousFailures || 0,
|
|
159
203
|
runOnlyExclusive: runtimeOptions.runOnlyExclusive === true,
|
|
160
204
|
runVector: runtimeOptions.runVector || 0,
|
|
161
|
-
status: runStatus
|
|
205
|
+
status: runStatus,
|
|
162
206
|
});
|
|
163
207
|
|
|
164
208
|
if (setupOrGlobError) {
|
|
@@ -172,9 +216,9 @@ class Api extends Emittery {
|
|
|
172
216
|
|
|
173
217
|
runStatus.on('stateChange', record => {
|
|
174
218
|
if (record.testFile && !timedOutWorkerFiles.has(record.testFile)) {
|
|
175
|
-
//
|
|
219
|
+
// Debounce the timer whenever there is activity from workers that
|
|
176
220
|
// haven't already timed out.
|
|
177
|
-
|
|
221
|
+
timeoutTrigger.debounce();
|
|
178
222
|
}
|
|
179
223
|
|
|
180
224
|
if (failFast && (record.type === 'hook-failed' || record.type === 'test-failed' || record.type === 'worker-failed')) {
|
|
@@ -188,11 +232,13 @@ class Api extends Emittery {
|
|
|
188
232
|
}
|
|
189
233
|
});
|
|
190
234
|
|
|
191
|
-
const
|
|
192
|
-
|
|
235
|
+
const providerStates = [];
|
|
236
|
+
await Promise.all(providers.map(async ({type, main}) => {
|
|
193
237
|
const state = await main.compile({cacheDir: this._createCacheDir(), files: testFiles});
|
|
194
|
-
|
|
195
|
-
|
|
238
|
+
if (state !== null) {
|
|
239
|
+
providerStates.push({type, state});
|
|
240
|
+
}
|
|
241
|
+
}));
|
|
196
242
|
|
|
197
243
|
// Resolve the correct concurrency value.
|
|
198
244
|
let concurrency = Math.min(os.cpus().length, isCi ? 2 : Number.POSITIVE_INFINITY);
|
|
@@ -223,7 +269,7 @@ class Api extends Emittery {
|
|
|
223
269
|
lineNumbers,
|
|
224
270
|
recordNewSnapshots: !isCi,
|
|
225
271
|
// If we're looking for matches, run every single test process in exclusive-only mode
|
|
226
|
-
runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true
|
|
272
|
+
runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true,
|
|
227
273
|
};
|
|
228
274
|
|
|
229
275
|
if (runtimeOptions.updateSnapshots) {
|
|
@@ -232,14 +278,19 @@ class Api extends Emittery {
|
|
|
232
278
|
}
|
|
233
279
|
|
|
234
280
|
const worker = fork(file, options, apiOptions.nodeArguments);
|
|
281
|
+
worker.onStateChange(data => {
|
|
282
|
+
if (data.type === 'test-timeout-configured' && !apiOptions.debug) {
|
|
283
|
+
timeoutTrigger.ignoreFor(data.period);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
235
286
|
runStatus.observeWorker(worker, file, {selectingLines: lineNumbers.length > 0});
|
|
236
|
-
deregisteredSharedWorkers.push(
|
|
287
|
+
deregisteredSharedWorkers.push(observeWorkerProcess(worker, runStatus));
|
|
237
288
|
|
|
238
289
|
pendingWorkers.add(worker);
|
|
239
290
|
worker.promise.then(() => {
|
|
240
291
|
pendingWorkers.delete(worker);
|
|
241
292
|
});
|
|
242
|
-
|
|
293
|
+
timeoutTrigger.debounce();
|
|
243
294
|
|
|
244
295
|
await worker.promise;
|
|
245
296
|
}, {concurrency, stopOnError: false});
|
|
@@ -249,7 +300,7 @@ class Api extends Emittery {
|
|
|
249
300
|
scheduler.storeFailedTestFiles(runStatus, this.options.cacheEnabled === false ? null : this._createCacheDir());
|
|
250
301
|
} catch (error) {
|
|
251
302
|
if (error && error.name === 'AggregateError') {
|
|
252
|
-
for (const error_ of error) {
|
|
303
|
+
for (const error_ of error.errors) {
|
|
253
304
|
runStatus.emitStateChange({type: 'internal-error', err: serializeError('Internal error', false, error_)});
|
|
254
305
|
}
|
|
255
306
|
} else {
|
|
@@ -257,7 +308,7 @@ class Api extends Emittery {
|
|
|
257
308
|
}
|
|
258
309
|
}
|
|
259
310
|
|
|
260
|
-
|
|
311
|
+
timeoutTrigger.discard();
|
|
261
312
|
return runStatus;
|
|
262
313
|
}
|
|
263
314
|
|
|
@@ -270,9 +321,9 @@ class Api extends Emittery {
|
|
|
270
321
|
return this._cacheDir;
|
|
271
322
|
}
|
|
272
323
|
|
|
273
|
-
const cacheDir = this.options.cacheEnabled === false
|
|
274
|
-
fs.mkdtempSync(`${tempDir}${path.sep}`)
|
|
275
|
-
this._getLocalCacheDir();
|
|
324
|
+
const cacheDir = this.options.cacheEnabled === false
|
|
325
|
+
? fs.mkdtempSync(`${tempDir}${path.sep}`)
|
|
326
|
+
: this._getLocalCacheDir();
|
|
276
327
|
|
|
277
328
|
// Ensure cacheDir exists
|
|
278
329
|
fs.mkdirSync(cacheDir, {recursive: true});
|
|
@@ -282,5 +333,3 @@ class Api extends Emittery {
|
|
|
282
333
|
return cacheDir;
|
|
283
334
|
}
|
|
284
335
|
}
|
|
285
|
-
|
|
286
|
-
module.exports = Api;
|