ava 7.0.0 → 8.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/{eslint-plugin-helper.cjs → eslint-plugin-helper.js} +10 -13
- package/entrypoints/{internal.d.mts → internal.d.ts} +1 -1
- package/entrypoints/{main.d.mts → main.d.ts} +5 -5
- package/entrypoints/{main.mjs → main.js} +1 -1
- package/entrypoints/{plugin.d.cts → plugin.d.ts} +2 -2
- package/entrypoints/plugin.js +1 -0
- package/index.d.ts +2 -2
- package/lib/api-event-iterator.js +2 -2
- package/lib/api.js +6 -6
- package/lib/assert.js +6 -5
- package/lib/cli.js +7 -27
- package/lib/create-chain.js +68 -25
- package/lib/extensions.js +5 -7
- package/lib/fork.js +3 -3
- package/lib/{glob-helpers.cjs → glob-helpers.js} +16 -30
- package/lib/globs.js +3 -3
- package/lib/{ipc-flow-control.cjs → ipc-flow-control.js} +1 -4
- package/lib/load-config.js +2 -3
- package/lib/{now-and-timers.cjs → now-and-timers.js} +11 -8
- package/lib/pkg.js +1 -0
- package/lib/plugin-support/shared-worker-loader.js +2 -2
- package/lib/plugin-support/shared-workers.js +3 -3
- package/lib/provider-manager.js +6 -5
- package/lib/reporters/default.js +1 -1
- package/lib/reporters/improper-usage-messages.js +1 -1
- package/lib/reporters/tap.js +10 -4
- package/lib/runner.js +5 -5
- package/lib/scheduler.js +1 -1
- package/lib/snapshot-manager.js +2 -2
- package/lib/test.js +15 -8
- package/lib/watcher.js +10 -18
- package/lib/worker/base.js +17 -41
- package/lib/worker/{channel.cjs → channel.js} +21 -25
- package/lib/worker/completion-handlers.js +3 -3
- package/lib/worker/{guard-environment.cjs → guard-environment.js} +4 -5
- package/lib/worker/line-numbers.js +3 -7
- package/lib/worker/main.js +11 -0
- package/lib/worker/{options.cjs → options.js} +4 -5
- package/lib/worker/{plugin.cjs → plugin.js} +8 -10
- package/lib/worker/state.js +5 -0
- package/lib/worker/utils.js +5 -0
- package/package.json +28 -36
- package/plugin.d.ts +1 -1
- package/types/{test-fn.d.cts → test-fn.d.ts} +24 -3
- package/types/{try-fn.d.cts → try-fn.d.ts} +1 -2
- package/entrypoints/main.cjs +0 -2
- package/entrypoints/main.d.cts +0 -12
- package/entrypoints/plugin.cjs +0 -2
- package/entrypoints/plugin.d.mts +0 -6
- package/entrypoints/plugin.mjs +0 -4
- package/lib/module-types.js +0 -85
- package/lib/pkg.cjs +0 -2
- package/lib/slash.cjs +0 -36
- package/lib/worker/main.cjs +0 -12
- package/lib/worker/state.cjs +0 -6
- package/lib/worker/utils.cjs +0 -6
- /package/entrypoints/{cli.mjs → cli.js} +0 -0
- /package/types/{assertions.d.cts → assertions.d.ts} +0 -0
- /package/types/{shared-worker.d.cts → shared-worker.d.ts} +0 -0
- /package/types/{state-change-events.d.cts → state-change-events.d.ts} +0 -0
- /package/types/{subscribable.d.cts → subscribable.d.ts} +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const {Worker} = require('node:worker_threads');
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {pathToFileURL} from 'node:url';
|
|
3
|
+
import v8 from 'node:v8';
|
|
4
|
+
import {Worker} from 'node:worker_threads';
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
import {
|
|
8
7
|
classify,
|
|
9
8
|
hasExtension,
|
|
10
9
|
isHelperish,
|
|
11
10
|
matches,
|
|
12
11
|
normalizeFileForMatching,
|
|
13
12
|
normalizePatterns,
|
|
14
|
-
}
|
|
13
|
+
} from '../lib/glob-helpers.js';
|
|
15
14
|
|
|
16
15
|
const MAX_DATA_LENGTH_EXCLUSIVE = 100 * 1024; // Allocate 100 KiB to exchange globs.
|
|
17
16
|
|
|
@@ -27,8 +26,8 @@ const resolveGlobsSync = (projectDir, overrideExtensions, overrideFiles) => {
|
|
|
27
26
|
const syncBuffer = new SharedArrayBuffer(4);
|
|
28
27
|
sync = new Int32Array(syncBuffer);
|
|
29
28
|
|
|
30
|
-
const filename = path.join(
|
|
31
|
-
worker = new Worker(
|
|
29
|
+
const filename = path.join(import.meta.dirname, '../lib/eslint-plugin-helper-worker.js');
|
|
30
|
+
worker = new Worker(pathToFileURL(filename), {
|
|
32
31
|
workerData: {
|
|
33
32
|
dataBuffer,
|
|
34
33
|
syncBuffer,
|
|
@@ -60,7 +59,7 @@ const resolveGlobsSync = (projectDir, overrideExtensions, overrideFiles) => {
|
|
|
60
59
|
|
|
61
60
|
const helperCache = new Map();
|
|
62
61
|
|
|
63
|
-
function load(projectDir, overrides) {
|
|
62
|
+
export function load(projectDir, overrides) {
|
|
64
63
|
const cacheKey = `${JSON.stringify(overrides)}\n${projectDir}`;
|
|
65
64
|
if (helperCache.has(cacheKey)) {
|
|
66
65
|
return helperCache.get(cacheKey);
|
|
@@ -69,7 +68,7 @@ function load(projectDir, overrides) {
|
|
|
69
68
|
let helperPatterns = [];
|
|
70
69
|
if (overrides && overrides.helpers !== undefined) {
|
|
71
70
|
if (!Array.isArray(overrides.helpers) || overrides.helpers.length === 0) {
|
|
72
|
-
throw new Error('The
|
|
71
|
+
throw new Error('The \u2018helpers\u2019 override must be an array containing glob patterns.');
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
helperPatterns = normalizePatterns(overrides.helpers);
|
|
@@ -105,5 +104,3 @@ function load(projectDir, overrides) {
|
|
|
105
104
|
helperCache.set(cacheKey, helper);
|
|
106
105
|
return helper;
|
|
107
106
|
}
|
|
108
|
-
|
|
109
|
-
exports.load = load;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {TestFn} from '../types/test-fn.
|
|
1
|
+
import type {TestFn} from '../types/test-fn.js';
|
|
2
2
|
|
|
3
|
-
export type * from '../types/assertions.
|
|
4
|
-
export type * from '../types/try-fn.
|
|
5
|
-
export type * from '../types/test-fn.
|
|
6
|
-
export type * from '../types/subscribable.
|
|
3
|
+
export type * from '../types/assertions.js';
|
|
4
|
+
export type * from '../types/try-fn.js';
|
|
5
|
+
export type * from '../types/test-fn.js';
|
|
6
|
+
export type * from '../types/subscribable.js';
|
|
7
7
|
|
|
8
8
|
/** Call to declare a test, or chain to declare hooks or test modifiers */
|
|
9
9
|
declare const test: TestFn;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {default} from '../lib/worker/main.
|
|
1
|
+
export {default} from '../lib/worker/main.js';
|
|
2
2
|
export {registerCompletionHandler} from '../lib/worker/completion-handlers.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {SharedWorker} from '../types/shared-worker.
|
|
1
|
+
import type {SharedWorker} from '../types/shared-worker.js';
|
|
2
2
|
|
|
3
3
|
export function registerSharedWorker<Data = unknown>(options: SharedWorker.Plugin.RegistrationOptions<'ava-4', Data>): SharedWorker.Plugin.Protocol<Data>;
|
|
4
4
|
// Add overloads for additional protocols.
|
|
5
5
|
|
|
6
|
-
export type {SharedWorker} from '../types/shared-worker.
|
|
6
|
+
export type {SharedWorker} from '../types/shared-worker.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {registerSharedWorker} from '../lib/worker/plugin.js';
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export async function * asyncEventIteratorFromApi(api) {
|
|
2
2
|
// TODO: support multiple runs (watch mode)
|
|
3
|
-
const {value: plan} = await api.events('run').next();
|
|
3
|
+
const {value: {data: plan}} = await api.events('run').next();
|
|
4
4
|
|
|
5
|
-
for await (const stateChange of plan.status.events('stateChange')) {
|
|
5
|
+
for await (const {data: stateChange} of plan.status.events('stateChange')) {
|
|
6
6
|
yield stateChange;
|
|
7
7
|
|
|
8
8
|
if (stateChange.type === 'end' || stateChange.type === 'interrupt') {
|
package/lib/api.js
CHANGED
|
@@ -15,7 +15,7 @@ import fork from './fork.js';
|
|
|
15
15
|
import * as globs from './globs.js';
|
|
16
16
|
import isCi from './is-ci.js';
|
|
17
17
|
import {getApplicableLineNumbers} from './line-numbers.js';
|
|
18
|
-
import {setCappedTimeout} from './now-and-timers.
|
|
18
|
+
import {setCappedTimeout} from './now-and-timers.js';
|
|
19
19
|
import {observeWorkerProcess} from './plugin-support/shared-workers.js';
|
|
20
20
|
import RunStatus from './run-status.js';
|
|
21
21
|
import scheduler from './scheduler.js';
|
|
@@ -77,7 +77,7 @@ export default class Api extends Emittery {
|
|
|
77
77
|
constructor(options) {
|
|
78
78
|
super();
|
|
79
79
|
|
|
80
|
-
this.options = {match: [],
|
|
80
|
+
this.options = {match: [], ...options};
|
|
81
81
|
this.options.require = normalizeRequireOption(this.options.require);
|
|
82
82
|
|
|
83
83
|
this._cacheDir = null;
|
|
@@ -180,7 +180,7 @@ export default class Api extends Emittery {
|
|
|
180
180
|
|
|
181
181
|
// The files must be in the same order across all runs, so sort them.
|
|
182
182
|
const defaultComparator = (a, b) => a.localeCompare(b, [], {numeric: true});
|
|
183
|
-
selectedFiles = selectedFiles.
|
|
183
|
+
selectedFiles = selectedFiles.toSorted(this.options.sortTestFiles ?? defaultComparator);
|
|
184
184
|
selectedFiles = chunkd(selectedFiles, currentIndex, totalRuns);
|
|
185
185
|
|
|
186
186
|
const currentFileCount = selectedFiles.length;
|
|
@@ -189,7 +189,7 @@ export default class Api extends Emittery {
|
|
|
189
189
|
} else {
|
|
190
190
|
// If a custom sorter was configured, use it.
|
|
191
191
|
if (this.options.sortTestFiles) {
|
|
192
|
-
selectedFiles = selectedFiles.
|
|
192
|
+
selectedFiles = selectedFiles.toSorted(this.options.sortTestFiles);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
runStatus = new RunStatus(selectedFiles.length, null, selectionInsights);
|
|
@@ -220,7 +220,7 @@ export default class Api extends Emittery {
|
|
|
220
220
|
return runStatus;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
runStatus.on('stateChange', record => {
|
|
223
|
+
runStatus.on('stateChange', ({data: record}) => {
|
|
224
224
|
if (record.testFile && !timedOutWorkerFiles.has(record.testFile) && record.type !== 'worker-stderr' && record.type !== 'worker-stdout') {
|
|
225
225
|
// Debounce the timer whenever there is test-related activity from workers that haven't already timed out.
|
|
226
226
|
timeoutTrigger.debounce();
|
|
@@ -293,7 +293,7 @@ export default class Api extends Emittery {
|
|
|
293
293
|
deregisteredSharedWorkers.push(observeWorkerProcess(worker, runStatus));
|
|
294
294
|
|
|
295
295
|
pendingWorkers.add(worker);
|
|
296
|
-
worker.promise.then(() => {
|
|
296
|
+
worker.promise.then(() => {
|
|
297
297
|
pendingWorkers.delete(worker);
|
|
298
298
|
});
|
|
299
299
|
timeoutTrigger.debounce();
|
package/lib/assert.js
CHANGED
|
@@ -29,6 +29,7 @@ function formatWithLabel(label, value) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const noop = () => {};
|
|
32
|
+
|
|
32
33
|
const notImplemented = () => {
|
|
33
34
|
throw new Error('not implemented');
|
|
34
35
|
};
|
|
@@ -423,7 +424,7 @@ export class Assertions {
|
|
|
423
424
|
retval = fn();
|
|
424
425
|
if (isPromise(retval)) {
|
|
425
426
|
// Here isPromise() checks if something is "promise like". Cast to an actual promise.
|
|
426
|
-
Promise.resolve(retval).catch(noop);
|
|
427
|
+
Promise.resolve(retval).catch(noop);
|
|
427
428
|
throw fail(new AssertionError(message, {
|
|
428
429
|
assertion: 't.throws()',
|
|
429
430
|
formattedDetails: [formatWithLabel('Function returned a promise. Use `t.throwsAsync()` instead:', retval)],
|
|
@@ -490,7 +491,7 @@ export class Assertions {
|
|
|
490
491
|
// Record the stack before it gets lost in the promise chain.
|
|
491
492
|
const assertionStack = getAssertionStack();
|
|
492
493
|
// Handle "promise like" objects by casting to a real Promise.
|
|
493
|
-
const intermediate = Promise.resolve(promise).then(value => {
|
|
494
|
+
const intermediate = Promise.resolve(promise).then(value => {
|
|
494
495
|
throw failPending(new AssertionError(message, {
|
|
495
496
|
assertion: 't.throwsAsync()',
|
|
496
497
|
assertionStack,
|
|
@@ -512,7 +513,7 @@ export class Assertions {
|
|
|
512
513
|
}
|
|
513
514
|
});
|
|
514
515
|
|
|
515
|
-
pending(intermediate);
|
|
516
|
+
pending(intermediate, assertionStack);
|
|
516
517
|
return intermediate;
|
|
517
518
|
};
|
|
518
519
|
|
|
@@ -592,14 +593,14 @@ export class Assertions {
|
|
|
592
593
|
// Create an error object to record the stack before it gets lost in the promise chain.
|
|
593
594
|
const assertionStack = getAssertionStack();
|
|
594
595
|
// Handle "promise like" objects by casting to a real Promise.
|
|
595
|
-
const intermediate = Promise.resolve(promise).then(noop, error => {
|
|
596
|
+
const intermediate = Promise.resolve(promise).then(noop, error => {
|
|
596
597
|
throw failPending(new AssertionError(message, {
|
|
597
598
|
assertion: 't.notThrowsAsync()',
|
|
598
599
|
assertionStack,
|
|
599
600
|
formattedDetails: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} rejected with:`, error)],
|
|
600
601
|
}));
|
|
601
602
|
});
|
|
602
|
-
pending(intermediate);
|
|
603
|
+
pending(intermediate, assertionStack);
|
|
603
604
|
|
|
604
605
|
await intermediate;
|
|
605
606
|
return true;
|
package/lib/cli.js
CHANGED
|
@@ -17,9 +17,8 @@ import {normalizeGlobs, normalizePattern} from './globs.js';
|
|
|
17
17
|
import isCi from './is-ci.js';
|
|
18
18
|
import {splitPatternAndLineNumbers} from './line-numbers.js';
|
|
19
19
|
import {loadConfig} from './load-config.js';
|
|
20
|
-
import normalizeModuleTypes from './module-types.js';
|
|
21
20
|
import normalizeNodeArguments from './node-arguments.js';
|
|
22
|
-
import pkg from './pkg.
|
|
21
|
+
import pkg from './pkg.js';
|
|
23
22
|
|
|
24
23
|
function exit(message) {
|
|
25
24
|
console.error(`\n ${chalk.red(figures.cross)} ${message}`);
|
|
@@ -334,17 +333,6 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
334
333
|
console.log(chalk.magenta(` ${figures.warning} Experiments are enabled. These are unsupported and may change or be removed at any time.`));
|
|
335
334
|
}
|
|
336
335
|
|
|
337
|
-
let projectPackageObject;
|
|
338
|
-
try {
|
|
339
|
-
projectPackageObject = JSON.parse(fs.readFileSync(path.resolve(projectDir, 'package.json')));
|
|
340
|
-
} catch (error) {
|
|
341
|
-
if (error.code !== 'ENOENT') {
|
|
342
|
-
throw error;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const {type: defaultModuleType = 'commonjs'} = projectPackageObject ?? {};
|
|
347
|
-
|
|
348
336
|
const providers = [];
|
|
349
337
|
if (Object.hasOwn(conf, 'typescript')) {
|
|
350
338
|
const {default: providerManager} = await import('./provider-manager.js');
|
|
@@ -375,13 +363,6 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
375
363
|
exit(error.message);
|
|
376
364
|
}
|
|
377
365
|
|
|
378
|
-
let moduleTypes;
|
|
379
|
-
try {
|
|
380
|
-
moduleTypes = normalizeModuleTypes(conf.extensions, defaultModuleType, experiments);
|
|
381
|
-
} catch (error) {
|
|
382
|
-
exit(error.message);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
366
|
let globs;
|
|
386
367
|
try {
|
|
387
368
|
globs = normalizeGlobs({
|
|
@@ -436,7 +417,6 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
436
417
|
failWithoutAssertions: combined.failWithoutAssertions !== false,
|
|
437
418
|
globs,
|
|
438
419
|
match,
|
|
439
|
-
moduleTypes,
|
|
440
420
|
nodeArguments,
|
|
441
421
|
parallelRuns,
|
|
442
422
|
sortTestFiles: conf.sortTestFiles,
|
|
@@ -472,11 +452,11 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
472
452
|
}
|
|
473
453
|
|
|
474
454
|
if (process.env.TEST_AVA) {
|
|
475
|
-
const {controlFlow} = await import('./ipc-flow-control.
|
|
455
|
+
const {controlFlow} = await import('./ipc-flow-control.js');
|
|
476
456
|
const bufferedSend = controlFlow(process);
|
|
477
457
|
|
|
478
|
-
api.on('run', plan => {
|
|
479
|
-
plan.status.on('stateChange', evt => {
|
|
458
|
+
api.on('run', ({data: plan}) => {
|
|
459
|
+
plan.status.on('stateChange', ({data: evt}) => {
|
|
480
460
|
bufferedSend(evt);
|
|
481
461
|
});
|
|
482
462
|
});
|
|
@@ -488,10 +468,10 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
488
468
|
});
|
|
489
469
|
}
|
|
490
470
|
|
|
491
|
-
api.on('run', plan => {
|
|
471
|
+
api.on('run', ({data: plan}) => {
|
|
492
472
|
reporter.startRun(plan);
|
|
493
473
|
|
|
494
|
-
plan.status.on('stateChange', evt => {
|
|
474
|
+
plan.status.on('stateChange', ({data: evt}) => {
|
|
495
475
|
if (evt.type === 'end' || evt.type === 'interrupt') {
|
|
496
476
|
// Write out code coverage data when the run ends, lest a process
|
|
497
477
|
// interrupt causes it to be lost.
|
|
@@ -537,7 +517,7 @@ export default async function loadCli() { // eslint-disable-line complexity
|
|
|
537
517
|
});
|
|
538
518
|
} else {
|
|
539
519
|
let debugWithoutSpecificFile = false;
|
|
540
|
-
api.on('run', plan => {
|
|
520
|
+
api.on('run', ({data: plan}) => {
|
|
541
521
|
if (debug !== null && plan.files.length !== 1) {
|
|
542
522
|
debugWithoutSpecificFile = true;
|
|
543
523
|
}
|
package/lib/create-chain.js
CHANGED
|
@@ -39,6 +39,70 @@ function callWithFlag(previous, flag, args) {
|
|
|
39
39
|
} while (previous);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function getSkippedTarget(target) {
|
|
43
|
+
let current = target;
|
|
44
|
+
while (current) {
|
|
45
|
+
if (current.skip) {
|
|
46
|
+
return current.skip;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
current = chainRegistry.get(current)?.prev;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return target;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createConditionalChain(node, shouldSkip) {
|
|
56
|
+
return new Proxy(node, {
|
|
57
|
+
apply(target, thisArg, argumentsList) {
|
|
58
|
+
return (shouldSkip ? getSkippedTarget(target) : target).apply(thisArg, argumentsList);
|
|
59
|
+
},
|
|
60
|
+
get(target, prop, receiver) {
|
|
61
|
+
// Proxy invariant: non-configurable properties must return invariant-safe values.
|
|
62
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
|
|
63
|
+
if (descriptor && !descriptor.configurable) {
|
|
64
|
+
if ('value' in descriptor && !descriptor.writable) {
|
|
65
|
+
return descriptor.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ('get' in descriptor && descriptor.get === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (prop === 'skipIf' || prop === 'runIf') {
|
|
74
|
+
return typeof target[prop] === 'function'
|
|
75
|
+
? condition => createConditionalChain(target, shouldSkip || (prop === 'skipIf' ? condition : !condition))
|
|
76
|
+
: undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const value = Reflect.get(target, prop, receiver);
|
|
80
|
+
if (chainRegistry.has(value)) {
|
|
81
|
+
const {call, defaults} = chainRegistry.get(value);
|
|
82
|
+
if (!call || (defaults.type === 'test' && !defaults.todo)) {
|
|
83
|
+
return createConditionalChain(value, shouldSkip);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
shouldSkip
|
|
91
|
+
&& value === undefined
|
|
92
|
+
) {
|
|
93
|
+
return Reflect.get(getSkippedTarget(target), prop);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return value;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function addConditionalModifiers(node) {
|
|
102
|
+
node.skipIf = condition => createConditionalChain(node, condition);
|
|
103
|
+
node.runIf = condition => createConditionalChain(node, !condition);
|
|
104
|
+
}
|
|
105
|
+
|
|
42
106
|
function createHookChain(hook, isAfterHook) {
|
|
43
107
|
// Hook chaining rules:
|
|
44
108
|
// * `always` comes immediately after "after hooks"
|
|
@@ -74,6 +138,10 @@ export default function createChain(fn, defaults, meta) {
|
|
|
74
138
|
extendChain(root.serial.failing, 'only', 'exclusive');
|
|
75
139
|
extendChain(root.serial.failing, 'skip', 'skipped');
|
|
76
140
|
|
|
141
|
+
for (const node of [root, root.serial, root.failing, root.serial.failing]) {
|
|
142
|
+
addConditionalModifiers(node);
|
|
143
|
+
}
|
|
144
|
+
|
|
77
145
|
root.after = createHookChain(startChain('test.after', fn, {...defaults, type: 'after'}), true);
|
|
78
146
|
root.afterEach = createHookChain(startChain('test.afterEach', fn, {...defaults, type: 'afterEach'}), true);
|
|
79
147
|
root.before = createHookChain(startChain('test.before', fn, {...defaults, type: 'before'}), false);
|
|
@@ -101,30 +169,5 @@ export default function createChain(fn, defaults, meta) {
|
|
|
101
169
|
|
|
102
170
|
root.meta = meta;
|
|
103
171
|
|
|
104
|
-
// The ESM and CJS type definitions export the chain (`test()` function) as
|
|
105
|
-
// the default. TypeScript's CJS output (when `esModuleInterop` is disabled)
|
|
106
|
-
// assume `require('ava').default` is available. The same goes for `import ava
|
|
107
|
-
// = require('ava')` syntax.
|
|
108
|
-
//
|
|
109
|
-
// Add `test.default` to make this work. Use a proxy to avoid
|
|
110
|
-
// `test.default.default` chains.
|
|
111
|
-
Object.defineProperty(root, 'default', {
|
|
112
|
-
configurable: false,
|
|
113
|
-
enumerable: false,
|
|
114
|
-
writable: false,
|
|
115
|
-
value: new Proxy(root, {
|
|
116
|
-
apply(target, thisArg, argumentsList) {
|
|
117
|
-
target.apply(thisArg, argumentsList);
|
|
118
|
-
},
|
|
119
|
-
get(target, prop) {
|
|
120
|
-
if (prop === 'default') {
|
|
121
|
-
throw new TypeError('Cannot access default.default');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return target[prop];
|
|
125
|
-
},
|
|
126
|
-
}),
|
|
127
|
-
});
|
|
128
|
-
|
|
129
172
|
return root;
|
|
130
173
|
}
|
package/lib/extensions.js
CHANGED
|
@@ -3,10 +3,8 @@ export default function resolveExtensions(configuredExtensions, providers = [])
|
|
|
3
3
|
const duplicates = new Set();
|
|
4
4
|
const seen = new Set();
|
|
5
5
|
|
|
6
|
-
const normalize = extensions => Array.isArray(extensions) ? extensions : Object.keys(extensions);
|
|
7
|
-
|
|
8
6
|
const combine = extensions => {
|
|
9
|
-
for (const ext of
|
|
7
|
+
for (const ext of extensions) {
|
|
10
8
|
if (seen.has(ext)) {
|
|
11
9
|
duplicates.add(ext);
|
|
12
10
|
} else {
|
|
@@ -16,6 +14,10 @@ export default function resolveExtensions(configuredExtensions, providers = [])
|
|
|
16
14
|
};
|
|
17
15
|
|
|
18
16
|
if (configuredExtensions !== undefined) {
|
|
17
|
+
if (!Array.isArray(configuredExtensions)) {
|
|
18
|
+
throw new TypeError('The extensions option must be an array');
|
|
19
|
+
}
|
|
20
|
+
|
|
19
21
|
combine(configuredExtensions);
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -29,10 +31,6 @@ export default function resolveExtensions(configuredExtensions, providers = [])
|
|
|
29
31
|
|
|
30
32
|
// Unless the default was used by providers, as long as the extensions aren't explicitly set, set the default.
|
|
31
33
|
if (configuredExtensions === undefined) {
|
|
32
|
-
if (!seen.has('cjs')) {
|
|
33
|
-
seen.add('cjs');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
34
|
if (!seen.has('mjs')) {
|
|
37
35
|
seen.add('mjs');
|
|
38
36
|
}
|
package/lib/fork.js
CHANGED
|
@@ -5,7 +5,7 @@ import {Worker} from 'node:worker_threads';
|
|
|
5
5
|
|
|
6
6
|
import Emittery from 'emittery';
|
|
7
7
|
|
|
8
|
-
import {controlFlow} from './ipc-flow-control.
|
|
8
|
+
import {controlFlow} from './ipc-flow-control.js';
|
|
9
9
|
import serializeError, {tagWorkerError} from './serialize-error.js';
|
|
10
10
|
|
|
11
11
|
let workerPath = new URL('worker/base.js', import.meta.url);
|
|
@@ -168,11 +168,11 @@ export default function loadFork(file, options, execArgv = process.execArgv) {
|
|
|
168
168
|
},
|
|
169
169
|
|
|
170
170
|
onConnectSharedWorker(listener) {
|
|
171
|
-
return emitter.on('connectSharedWorker', listener);
|
|
171
|
+
return emitter.on('connectSharedWorker', ({data}) => listener(data));
|
|
172
172
|
},
|
|
173
173
|
|
|
174
174
|
onStateChange(listener) {
|
|
175
|
-
return emitter.on('stateChange', listener);
|
|
175
|
+
return emitter.on('stateChange', ({data}) => listener(data));
|
|
176
176
|
},
|
|
177
177
|
};
|
|
178
178
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const process = require('node:process');
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import process from 'node:process';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const slash = require('./slash.cjs');
|
|
4
|
+
import ignoreByDefault from 'ignore-by-default';
|
|
5
|
+
import picomatch from 'picomatch';
|
|
6
|
+
import slash from 'slash';
|
|
9
7
|
|
|
10
8
|
const defaultIgnorePatterns = [...ignoreByDefault.directories(), '**/node_modules'];
|
|
11
|
-
|
|
9
|
+
export {defaultIgnorePatterns};
|
|
12
10
|
|
|
13
11
|
const defaultPicomatchIgnorePatterns = [
|
|
14
12
|
...defaultIgnorePatterns,
|
|
@@ -42,22 +40,20 @@ const processMatchingPatterns = input => {
|
|
|
42
40
|
return result;
|
|
43
41
|
};
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
export {processMatchingPatterns};
|
|
46
44
|
|
|
47
|
-
function classify(file, {cwd, extensions, filePatterns}) {
|
|
45
|
+
export function classify(file, {cwd, extensions, filePatterns}) {
|
|
48
46
|
file = normalizeFileForMatching(cwd, file);
|
|
49
47
|
return {
|
|
50
48
|
isTest: hasExtension(extensions, file) && !isHelperish(file) && filePatterns.length > 0 && matches(file, filePatterns),
|
|
51
49
|
};
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
exports.hasExtension = hasExtension;
|
|
52
|
+
export function hasExtension(extensions, file) {
|
|
53
|
+
return extensions.includes(path.extname(file).slice(1));
|
|
54
|
+
}
|
|
59
55
|
|
|
60
|
-
function isHelperish(file) { // Assume file has been normalized already.
|
|
56
|
+
export function isHelperish(file) { // Assume file has been normalized already.
|
|
61
57
|
// File names starting with an underscore are deemed "helpers".
|
|
62
58
|
if (path.basename(file).startsWith('_')) {
|
|
63
59
|
return true;
|
|
@@ -75,16 +71,12 @@ function isHelperish(file) { // Assume file has been normalized already.
|
|
|
75
71
|
return path.dirname(file).split('/').some(dir => /^_(?:$|[^_])/.test(dir));
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
function matches(file, patterns) {
|
|
74
|
+
export function matches(file, patterns) {
|
|
81
75
|
const {match} = processMatchingPatterns(patterns);
|
|
82
76
|
return match(file);
|
|
83
77
|
}
|
|
84
78
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
function normalizeFileForMatching(cwd, file) {
|
|
79
|
+
export function normalizeFileForMatching(cwd, file) {
|
|
88
80
|
if (process.platform === 'win32') {
|
|
89
81
|
cwd = slash(cwd);
|
|
90
82
|
file = slash(file);
|
|
@@ -101,9 +93,7 @@ function normalizeFileForMatching(cwd, file) {
|
|
|
101
93
|
return file.slice(cwd.length + 1);
|
|
102
94
|
}
|
|
103
95
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
function normalizePattern(pattern) {
|
|
96
|
+
export function normalizePattern(pattern) {
|
|
107
97
|
// Always use `/` in patterns, harmonizing matching across platforms
|
|
108
98
|
if (process.platform === 'win32') {
|
|
109
99
|
pattern = slash(pattern);
|
|
@@ -124,10 +114,6 @@ function normalizePattern(pattern) {
|
|
|
124
114
|
return pattern;
|
|
125
115
|
}
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
function normalizePatterns(patterns) {
|
|
117
|
+
export function normalizePatterns(patterns) {
|
|
130
118
|
return patterns.map(pattern => normalizePattern(pattern));
|
|
131
119
|
}
|
|
132
|
-
|
|
133
|
-
exports.normalizePatterns = normalizePatterns;
|
package/lib/globs.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
normalizeFileForMatching,
|
|
11
11
|
normalizePatterns,
|
|
12
12
|
processMatchingPatterns,
|
|
13
|
-
} from './glob-helpers.
|
|
13
|
+
} from './glob-helpers.js';
|
|
14
14
|
|
|
15
15
|
export {
|
|
16
16
|
classify,
|
|
@@ -21,12 +21,12 @@ export {
|
|
|
21
21
|
hasExtension,
|
|
22
22
|
normalizeFileForMatching,
|
|
23
23
|
normalizePatterns,
|
|
24
|
-
} from './glob-helpers.
|
|
24
|
+
} from './glob-helpers.js';
|
|
25
25
|
|
|
26
26
|
const defaultIgnoredByWatcherPatterns = [
|
|
27
27
|
'**/*.snap.md', // No need to rerun tests when the Markdown files change.
|
|
28
|
+
'**/*.tsbuildinfo', // No need to rerun tests when TypeScript build info files change.
|
|
28
29
|
'ava.config.js', // Config is not reloaded so avoid rerunning tests when it changes.
|
|
29
|
-
'ava.config.cjs', // Config is not reloaded so avoid rerunning tests when it changes.
|
|
30
30
|
'ava.config.mjs', // Config is not reloaded so avoid rerunning tests when it changes.
|
|
31
31
|
];
|
|
32
32
|
|
package/lib/load-config.js
CHANGED
|
@@ -94,8 +94,8 @@ export async function loadConfig({configFile, resolveFrom = process.cwd(), defau
|
|
|
94
94
|
try {
|
|
95
95
|
loaded = await loadConfigFile({projectDir, configFile});
|
|
96
96
|
} catch (error) {
|
|
97
|
-
if (!configFile.endsWith('.js') && !configFile.endsWith('.
|
|
98
|
-
throw Object.assign(new Error('Could not load config file; it should have .js
|
|
97
|
+
if (!configFile.endsWith('.js') && !configFile.endsWith('.mjs')) {
|
|
98
|
+
throw Object.assign(new Error('Could not load config file; it should have .js or .mjs extension'), {cause: error});
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
throw error;
|
|
@@ -111,7 +111,6 @@ export async function loadConfig({configFile, resolveFrom = process.cwd(), defau
|
|
|
111
111
|
const [jsonFile, ...results] = await Promise.all([ // eslint-disable-line no-await-in-loop
|
|
112
112
|
checkJsonFile(searchDir),
|
|
113
113
|
loadConfigFile({projectDir, configFile: path.join(searchDir, 'ava.config.js')}),
|
|
114
|
-
loadConfigFile({projectDir, configFile: path.join(searchDir, 'ava.config.cjs')}),
|
|
115
114
|
loadConfigFile({projectDir, configFile: path.join(searchDir, 'ava.config.mjs')}),
|
|
116
115
|
]);
|
|
117
116
|
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export {
|
|
2
|
+
setTimeout,
|
|
3
|
+
clearTimeout,
|
|
4
|
+
setImmediate,
|
|
5
|
+
setInterval,
|
|
6
|
+
clearInterval,
|
|
7
|
+
clearImmediate,
|
|
8
|
+
} from 'node:timers';
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
exports.now = Date.now;
|
|
10
|
+
export const {now} = Date;
|
|
6
11
|
|
|
7
12
|
// Any delay larger than this value is ignored by Node.js, with a delay of `1`
|
|
8
13
|
// used instead. See <https://nodejs.org/api/timers.html#settimeoutcallback-delay-args>.
|
|
9
14
|
const MAX_DELAY = (2 ** 31) - 1;
|
|
10
15
|
|
|
11
|
-
function setCappedTimeout(callback, delay) {
|
|
16
|
+
export function setCappedTimeout(callback, delay) {
|
|
12
17
|
const safeDelay = Math.min(delay, MAX_DELAY);
|
|
13
|
-
return
|
|
18
|
+
return globalThis.setTimeout(callback, safeDelay);
|
|
14
19
|
}
|
|
15
|
-
|
|
16
|
-
exports.setCappedTimeout = setCappedTimeout;
|
package/lib/pkg.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from '../package.json' with {type: 'json'};
|