ava 5.3.1 → 6.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/internal.d.mts +7 -0
- package/lib/api-event-iterator.js +12 -0
- package/lib/api.js +14 -23
- package/lib/assert.js +289 -444
- package/lib/cli.js +95 -61
- package/lib/code-excerpt.js +2 -2
- package/lib/eslint-plugin-helper-worker.js +3 -3
- package/lib/fork.js +3 -13
- package/lib/glob-helpers.cjs +1 -9
- package/lib/globs.js +7 -3
- package/lib/line-numbers.js +1 -1
- package/lib/load-config.js +3 -3
- package/lib/parse-test-args.js +3 -3
- package/lib/plugin-support/shared-workers.js +4 -4
- package/lib/provider-manager.js +11 -13
- package/lib/reporters/beautify-stack.js +0 -1
- package/lib/reporters/default.js +92 -45
- package/lib/reporters/format-serialized-error.js +6 -6
- package/lib/reporters/improper-usage-messages.js +5 -5
- package/lib/reporters/tap.js +30 -30
- package/lib/run-status.js +9 -0
- package/lib/runner.js +7 -7
- package/lib/scheduler.js +14 -1
- package/lib/serialize-error.js +44 -116
- package/lib/slash.cjs +1 -1
- package/lib/snapshot-manager.js +14 -8
- package/lib/test.js +90 -81
- package/lib/watcher.js +494 -365
- package/lib/worker/base.js +90 -51
- package/lib/worker/channel.cjs +9 -53
- package/license +1 -1
- package/package.json +36 -42
- package/readme.md +6 -12
- package/types/assertions.d.cts +107 -49
- package/types/shared-worker.d.cts +0 -2
- package/types/state-change-events.d.cts +143 -0
- package/types/test-fn.d.cts +10 -5
- package/lib/worker/dependency-tracker.js +0 -48
- /package/entrypoints/{main.d.ts → main.d.mts} +0 -0
- /package/entrypoints/{plugin.d.ts → plugin.d.mts} +0 -0
package/lib/worker/base.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import {mkdir} from 'node:fs/promises';
|
|
1
2
|
import {createRequire} from 'node:module';
|
|
3
|
+
import {join as joinPath, resolve as resolvePath} from 'node:path';
|
|
2
4
|
import process from 'node:process';
|
|
3
5
|
import {pathToFileURL} from 'node:url';
|
|
4
6
|
import {workerData} from 'node:worker_threads';
|
|
5
7
|
|
|
6
8
|
import setUpCurrentlyUnhandled from 'currently-unhandled';
|
|
9
|
+
import writeFileAtomic from 'write-file-atomic';
|
|
7
10
|
|
|
8
11
|
import {set as setChalk} from '../chalk.js';
|
|
9
12
|
import nowAndTimers from '../now-and-timers.cjs';
|
|
@@ -12,7 +15,6 @@ import Runner from '../runner.js';
|
|
|
12
15
|
import serializeError from '../serialize-error.js';
|
|
13
16
|
|
|
14
17
|
import channel from './channel.cjs';
|
|
15
|
-
import dependencyTracking from './dependency-tracker.js';
|
|
16
18
|
import lineNumberSelection from './line-numbers.js';
|
|
17
19
|
import {set as setOptions} from './options.cjs';
|
|
18
20
|
import {flags, refs, sharedWorkerTeardowns} from './state.cjs';
|
|
@@ -21,37 +23,26 @@ import {isRunningInThread, isRunningInChildProcess} from './utils.cjs';
|
|
|
21
23
|
const currentlyUnhandled = setUpCurrentlyUnhandled();
|
|
22
24
|
let runner;
|
|
23
25
|
|
|
26
|
+
let forcingExit = false;
|
|
27
|
+
|
|
28
|
+
const forceExit = () => {
|
|
29
|
+
forcingExit = true;
|
|
30
|
+
process.exit(1);
|
|
31
|
+
};
|
|
32
|
+
|
|
24
33
|
// Override process.exit with an undetectable replacement
|
|
25
34
|
// to report when it is called from a test (which it should never be).
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const flushing = channel.flush();
|
|
32
|
-
if (!forceSync) {
|
|
33
|
-
await flushing;
|
|
35
|
+
const handleProcessExit = (target, thisArg, args) => {
|
|
36
|
+
if (!forcingExit) {
|
|
37
|
+
const error = new Error('Unexpected process.exit()');
|
|
38
|
+
Error.captureStackTrace(error, handleProcessExit);
|
|
39
|
+
channel.send({type: 'process-exit', stack: error.stack});
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
apply(
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const handleProcessExit = (fn, receiver, args) => {
|
|
40
|
-
const error = new Error('Unexpected process.exit()');
|
|
41
|
-
Error.captureStackTrace(error, handleProcessExit);
|
|
42
|
-
const {stack} = serializeError('', true, error);
|
|
43
|
-
channel.send({type: 'process-exit', stack});
|
|
44
|
-
|
|
45
|
-
// Make sure to extract the code only from `args` rather than e.g. `Array.prototype`.
|
|
46
|
-
// This level of paranoia is usually unwarranted, but we're dealing with test code
|
|
47
|
-
// that has already colored outside the lines.
|
|
48
|
-
const code = args.length > 0 ? args[0] : undefined;
|
|
49
|
-
|
|
50
|
-
// Force a synchronous exit as guaranteed by the real process.exit().
|
|
51
|
-
exit(code, true);
|
|
42
|
+
target.apply(thisArg, args);
|
|
52
43
|
};
|
|
53
44
|
|
|
54
|
-
process.exit = new Proxy(
|
|
45
|
+
process.exit = new Proxy(process.exit, {
|
|
55
46
|
apply: handleProcessExit,
|
|
56
47
|
});
|
|
57
48
|
|
|
@@ -71,7 +62,7 @@ const run = async options => {
|
|
|
71
62
|
lineNumbers: options.lineNumbers,
|
|
72
63
|
});
|
|
73
64
|
} catch (error) {
|
|
74
|
-
channel.send({type: 'line-number-selection-error', err: serializeError(
|
|
65
|
+
channel.send({type: 'line-number-selection-error', err: serializeError(error)});
|
|
75
66
|
checkSelectedByLineNumbers = () => false;
|
|
76
67
|
}
|
|
77
68
|
|
|
@@ -96,12 +87,12 @@ const run = async options => {
|
|
|
96
87
|
runner.interrupt();
|
|
97
88
|
});
|
|
98
89
|
|
|
99
|
-
runner.on('
|
|
90
|
+
runner.on('accessed-snapshots', filename => channel.send({type: 'accessed-snapshots', filename}));
|
|
100
91
|
runner.on('stateChange', state => channel.send(state));
|
|
101
92
|
|
|
102
93
|
runner.on('error', error => {
|
|
103
|
-
channel.send({type: 'internal-error', err: serializeError(
|
|
104
|
-
|
|
94
|
+
channel.send({type: 'internal-error', err: serializeError(error)});
|
|
95
|
+
forceExit();
|
|
105
96
|
});
|
|
106
97
|
|
|
107
98
|
runner.on('finish', async () => {
|
|
@@ -111,31 +102,36 @@ const run = async options => {
|
|
|
111
102
|
channel.send({type: 'touched-files', files: touchedFiles});
|
|
112
103
|
}
|
|
113
104
|
} catch (error) {
|
|
114
|
-
channel.send({type: 'internal-error', err: serializeError(
|
|
115
|
-
|
|
105
|
+
channel.send({type: 'internal-error', err: serializeError(error)});
|
|
106
|
+
forceExit();
|
|
116
107
|
return;
|
|
117
108
|
}
|
|
118
109
|
|
|
119
110
|
try {
|
|
120
111
|
await Promise.all(sharedWorkerTeardowns.map(fn => fn()));
|
|
121
112
|
} catch (error) {
|
|
122
|
-
channel.send({type: 'uncaught-exception', err: serializeError(
|
|
123
|
-
|
|
113
|
+
channel.send({type: 'uncaught-exception', err: serializeError(error)});
|
|
114
|
+
forceExit();
|
|
124
115
|
return;
|
|
125
116
|
}
|
|
126
117
|
|
|
127
118
|
nowAndTimers.setImmediate(() => {
|
|
128
|
-
|
|
129
|
-
|
|
119
|
+
const unhandled = currentlyUnhandled();
|
|
120
|
+
if (unhandled.length === 0) {
|
|
121
|
+
return;
|
|
130
122
|
}
|
|
131
123
|
|
|
132
|
-
|
|
124
|
+
for (const rejection of unhandled) {
|
|
125
|
+
channel.send({type: 'unhandled-rejection', err: serializeError(rejection.reason, {testFile: options.file})});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
forceExit();
|
|
133
129
|
});
|
|
134
130
|
});
|
|
135
131
|
|
|
136
132
|
process.on('uncaughtException', error => {
|
|
137
|
-
channel.send({type: 'uncaught-exception', err: serializeError(
|
|
138
|
-
|
|
133
|
+
channel.send({type: 'uncaught-exception', err: serializeError(error, {testFile: options.file})});
|
|
134
|
+
forceExit();
|
|
139
135
|
});
|
|
140
136
|
|
|
141
137
|
// Store value to prevent required modules from modifying it.
|
|
@@ -149,9 +145,9 @@ const run = async options => {
|
|
|
149
145
|
// require configuration the *compiled* helper will be loaded.
|
|
150
146
|
const {projectDir, providerStates = []} = options;
|
|
151
147
|
const providers = [];
|
|
152
|
-
await Promise.all(providerStates.map(async ({type, state}) => {
|
|
148
|
+
await Promise.all(providerStates.map(async ({type, state, protocol}) => {
|
|
153
149
|
if (type === 'typescript') {
|
|
154
|
-
const provider = await providerManager.typescript(projectDir);
|
|
150
|
+
const provider = await providerManager.typescript(projectDir, {protocol});
|
|
155
151
|
providers.push(provider.worker({extensionsToLoadAsModules, state}));
|
|
156
152
|
}
|
|
157
153
|
}));
|
|
@@ -174,16 +170,59 @@ const run = async options => {
|
|
|
174
170
|
return require(ref);
|
|
175
171
|
};
|
|
176
172
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
173
|
+
const loadRequiredModule = async ref => {
|
|
174
|
+
// If the provider can load the module, assume it's a local file and not a
|
|
175
|
+
// dependency.
|
|
176
|
+
for (const provider of providers) {
|
|
177
|
+
if (provider.canLoad(ref)) {
|
|
178
|
+
return provider.load(ref, {requireFn: require});
|
|
179
|
+
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
182
|
+
// Try to load the module as a file, relative to the project directory.
|
|
183
|
+
// Match load() behavior.
|
|
184
|
+
const fullPath = resolvePath(projectDir, ref);
|
|
185
|
+
try {
|
|
186
|
+
for (const extension of extensionsToLoadAsModules) {
|
|
187
|
+
if (fullPath.endsWith(`.${extension}`)) {
|
|
188
|
+
return await import(pathToFileURL(fullPath)); // eslint-disable-line no-await-in-loop
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return require(fullPath);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
// If the module could not be found, assume it's not a file but a dependency.
|
|
195
|
+
if (error.code === 'ERR_MODULE_NOT_FOUND' || error.code === 'MODULE_NOT_FOUND') {
|
|
196
|
+
return importFromProject(ref);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
let importFromProject = async ref => {
|
|
204
|
+
// Do not use the cacheDir since it's not guaranteed to be inside node_modules.
|
|
205
|
+
const avaCacheDir = joinPath(projectDir, 'node_modules', '.cache', 'ava');
|
|
206
|
+
await mkdir(avaCacheDir, {recursive: true});
|
|
207
|
+
const stubPath = joinPath(avaCacheDir, 'import-from-project.mjs');
|
|
208
|
+
await writeFileAtomic(stubPath, 'export const importFromProject = ref => import(ref);\n');
|
|
209
|
+
({importFromProject} = await import(pathToFileURL(stubPath)));
|
|
210
|
+
return importFromProject(ref);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
for await (const [ref, ...args] of (options.require ?? [])) {
|
|
215
|
+
const loadedModule = await loadRequiredModule(ref);
|
|
216
|
+
|
|
217
|
+
if (typeof loadedModule === 'function') { // CJS module
|
|
218
|
+
await loadedModule(...args);
|
|
219
|
+
} else if (typeof loadedModule.default === 'function') { // ES module, or exports.default from CJS
|
|
220
|
+
const {default: fn} = loadedModule;
|
|
221
|
+
await fn(...args);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
185
224
|
|
|
186
|
-
if (options.debug
|
|
225
|
+
if (options.debug?.port !== undefined && options.debug?.host !== undefined) {
|
|
187
226
|
// If an inspector was active when the main process started, and is
|
|
188
227
|
// already active for the worker process, do not open a new one.
|
|
189
228
|
const {default: inspector} = await import('node:inspector');
|
|
@@ -205,11 +244,11 @@ const run = async options => {
|
|
|
205
244
|
channel.unref();
|
|
206
245
|
} else {
|
|
207
246
|
channel.send({type: 'missing-ava-import'});
|
|
208
|
-
|
|
247
|
+
forceExit();
|
|
209
248
|
}
|
|
210
249
|
} catch (error) {
|
|
211
|
-
channel.send({type: 'uncaught-exception', err: serializeError(
|
|
212
|
-
|
|
250
|
+
channel.send({type: 'uncaught-exception', err: serializeError(error, {testFile: options.file})});
|
|
251
|
+
forceExit();
|
|
213
252
|
}
|
|
214
253
|
};
|
|
215
254
|
|
package/lib/worker/channel.cjs
CHANGED
|
@@ -7,42 +7,14 @@ const timers = require('../now-and-timers.cjs');
|
|
|
7
7
|
|
|
8
8
|
const {isRunningInChildProcess, isRunningInThread} = require('./utils.cjs');
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
emitter.on(event, addToBuffer);
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
({pEvent} = await import('p-event'));
|
|
19
|
-
} finally {
|
|
20
|
-
emitter.off(event, addToBuffer);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (buffer.length === 0) {
|
|
24
|
-
return pEvent(emitter, event, options);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Now replay buffered events.
|
|
28
|
-
const replayEmitter = new events.EventEmitter();
|
|
29
|
-
const promise = pEvent(replayEmitter, event, options);
|
|
30
|
-
for (const args of buffer) {
|
|
31
|
-
replayEmitter.emit(event, ...args);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const replay = (...args) => replayEmitter.emit(event, ...args);
|
|
35
|
-
emitter.on(event, replay);
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
return await promise;
|
|
39
|
-
} finally {
|
|
40
|
-
emitter.off(event, replay);
|
|
10
|
+
const selectAvaMessage = async (channel, type) => {
|
|
11
|
+
for await (const [message] of events.on(channel, 'message')) {
|
|
12
|
+
if (message.ava?.type === type) {
|
|
13
|
+
return message;
|
|
14
|
+
}
|
|
41
15
|
}
|
|
42
16
|
};
|
|
43
17
|
|
|
44
|
-
const selectAvaMessage = type => message => message.ava && message.ava.type === type;
|
|
45
|
-
|
|
46
18
|
class RefCounter {
|
|
47
19
|
constructor() {
|
|
48
20
|
this.count = 0;
|
|
@@ -133,27 +105,11 @@ if (isRunningInChildProcess) {
|
|
|
133
105
|
// Node.js. In order to keep track, explicitly reference before attaching.
|
|
134
106
|
handle.ref();
|
|
135
107
|
|
|
136
|
-
exports.options =
|
|
137
|
-
exports.peerFailed =
|
|
108
|
+
exports.options = selectAvaMessage(handle.channel, 'options').then(message => message.ava.options);
|
|
109
|
+
exports.peerFailed = selectAvaMessage(handle.channel, 'peer-failed');
|
|
138
110
|
exports.send = handle.send.bind(handle);
|
|
139
111
|
exports.unref = handle.unref.bind(handle);
|
|
140
112
|
|
|
141
|
-
let pendingPings = Promise.resolve();
|
|
142
|
-
async function flush() {
|
|
143
|
-
handle.ref();
|
|
144
|
-
const promise = pendingPings.then(async () => {
|
|
145
|
-
handle.send({type: 'ping'});
|
|
146
|
-
await pEvent(handle.channel, 'message', selectAvaMessage('pong'));
|
|
147
|
-
if (promise === pendingPings) {
|
|
148
|
-
handle.unref();
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
pendingPings = promise;
|
|
152
|
-
await promise;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
exports.flush = flush;
|
|
156
|
-
|
|
157
113
|
let channelCounter = 0;
|
|
158
114
|
let messageCounter = 0;
|
|
159
115
|
|
|
@@ -202,7 +158,7 @@ function registerSharedWorker(filename, initialData) {
|
|
|
202
158
|
// The attaching of message listeners will cause the port to be referenced by
|
|
203
159
|
// Node.js. In order to keep track, explicitly reference before attaching.
|
|
204
160
|
sharedWorkerHandle.ref();
|
|
205
|
-
const ready =
|
|
161
|
+
const ready = selectAvaMessage(ourPort, 'ready').then(() => {
|
|
206
162
|
currentlyAvailable = error === null;
|
|
207
163
|
}).finally(() => {
|
|
208
164
|
// Once ready, it's up to user code to subscribe to messages, which (see
|
|
@@ -214,7 +170,7 @@ function registerSharedWorker(filename, initialData) {
|
|
|
214
170
|
|
|
215
171
|
// Errors are received over the test worker channel, not the message port
|
|
216
172
|
// dedicated to the shared worker.
|
|
217
|
-
|
|
173
|
+
events.once(channelEmitter, 'shared-worker-error').then(() => {
|
|
218
174
|
unsubscribe();
|
|
219
175
|
sharedWorkerHandle.forceUnref();
|
|
220
176
|
error = new Error('The shared worker is no longer available');
|
package/license
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
|
3
|
+
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ava",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Node.js test runner that lets you develop with confidence.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "avajs/ava",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
13
|
"import": {
|
|
14
|
-
"types": "./entrypoints/main.d.
|
|
14
|
+
"types": "./entrypoints/main.d.mts",
|
|
15
15
|
"default": "./entrypoints/main.mjs"
|
|
16
16
|
},
|
|
17
17
|
"require": {
|
|
@@ -22,22 +22,24 @@
|
|
|
22
22
|
"./eslint-plugin-helper": "./entrypoints/eslint-plugin-helper.cjs",
|
|
23
23
|
"./plugin": {
|
|
24
24
|
"import": {
|
|
25
|
-
"types": "./entrypoints/plugin.d.
|
|
25
|
+
"types": "./entrypoints/plugin.d.mts",
|
|
26
26
|
"default": "./entrypoints/plugin.mjs"
|
|
27
27
|
},
|
|
28
28
|
"require": {
|
|
29
29
|
"types": "./entrypoints/plugin.d.cts",
|
|
30
30
|
"default": "./entrypoints/plugin.cjs"
|
|
31
31
|
}
|
|
32
|
+
},
|
|
33
|
+
"./internal": {
|
|
34
|
+
"types": "./entrypoints/internal.d.mts"
|
|
32
35
|
}
|
|
33
36
|
},
|
|
34
37
|
"type": "module",
|
|
35
38
|
"engines": {
|
|
36
|
-
"node": "
|
|
39
|
+
"node": "^18.18 || ^20.8 || ^21"
|
|
37
40
|
},
|
|
38
41
|
"scripts": {
|
|
39
|
-
"
|
|
40
|
-
"test": "xo && tsc --noEmit && npm run -s cover"
|
|
42
|
+
"test": "./scripts/test.sh"
|
|
41
43
|
},
|
|
42
44
|
"files": [
|
|
43
45
|
"entrypoints",
|
|
@@ -81,45 +83,42 @@
|
|
|
81
83
|
"typescript"
|
|
82
84
|
],
|
|
83
85
|
"dependencies": {
|
|
84
|
-
"
|
|
85
|
-
"acorn
|
|
86
|
+
"@vercel/nft": "^0.24.4",
|
|
87
|
+
"acorn": "^8.11.2",
|
|
88
|
+
"acorn-walk": "^8.3.0",
|
|
86
89
|
"ansi-styles": "^6.2.1",
|
|
87
90
|
"arrgv": "^1.0.2",
|
|
88
91
|
"arrify": "^3.0.0",
|
|
89
|
-
"callsites": "^4.
|
|
90
|
-
"cbor": "^
|
|
91
|
-
"chalk": "^5.
|
|
92
|
-
"chokidar": "^3.5.3",
|
|
92
|
+
"callsites": "^4.1.0",
|
|
93
|
+
"cbor": "^9.0.1",
|
|
94
|
+
"chalk": "^5.3.0",
|
|
93
95
|
"chunkd": "^2.0.1",
|
|
94
|
-
"ci-info": "^
|
|
96
|
+
"ci-info": "^4.0.0",
|
|
95
97
|
"ci-parallel-vars": "^1.0.1",
|
|
96
|
-
"
|
|
97
|
-
"cli-truncate": "^3.1.0",
|
|
98
|
+
"cli-truncate": "^4.0.0",
|
|
98
99
|
"code-excerpt": "^4.0.0",
|
|
99
100
|
"common-path-prefix": "^3.0.0",
|
|
100
101
|
"concordance": "^5.0.4",
|
|
101
102
|
"currently-unhandled": "^0.4.1",
|
|
102
103
|
"debug": "^4.3.4",
|
|
103
104
|
"emittery": "^1.0.1",
|
|
104
|
-
"figures": "^
|
|
105
|
-
"globby": "^
|
|
105
|
+
"figures": "^6.0.1",
|
|
106
|
+
"globby": "^14.0.0",
|
|
106
107
|
"ignore-by-default": "^2.1.0",
|
|
107
108
|
"indent-string": "^5.0.0",
|
|
108
|
-
"is-error": "^2.2.2",
|
|
109
109
|
"is-plain-object": "^5.0.0",
|
|
110
110
|
"is-promise": "^4.0.0",
|
|
111
111
|
"matcher": "^5.0.0",
|
|
112
|
-
"
|
|
112
|
+
"memoize": "^10.0.0",
|
|
113
113
|
"ms": "^2.1.3",
|
|
114
|
-
"p-
|
|
115
|
-
"
|
|
116
|
-
"picomatch": "^
|
|
117
|
-
"pkg-conf": "^4.0.0",
|
|
114
|
+
"p-map": "^6.0.0",
|
|
115
|
+
"package-config": "^5.0.0",
|
|
116
|
+
"picomatch": "^3.0.1",
|
|
118
117
|
"plur": "^5.1.0",
|
|
119
118
|
"pretty-ms": "^8.0.0",
|
|
120
119
|
"resolve-cwd": "^3.0.0",
|
|
121
120
|
"stack-utils": "^2.0.6",
|
|
122
|
-
"strip-ansi": "^7.0
|
|
121
|
+
"strip-ansi": "^7.1.0",
|
|
123
122
|
"supertap": "^3.0.1",
|
|
124
123
|
"temp-dir": "^3.0.0",
|
|
125
124
|
"write-file-atomic": "^5.0.1",
|
|
@@ -127,24 +126,19 @@
|
|
|
127
126
|
},
|
|
128
127
|
"devDependencies": {
|
|
129
128
|
"@ava/test": "github:avajs/test",
|
|
130
|
-
"@ava/typescript": "^4.
|
|
131
|
-
"@sindresorhus/tsconfig": "^
|
|
129
|
+
"@ava/typescript": "^4.1.0",
|
|
130
|
+
"@sindresorhus/tsconfig": "^5.0.0",
|
|
131
|
+
"@types/node": "^20.10.3",
|
|
132
132
|
"ansi-escapes": "^6.2.0",
|
|
133
|
-
"c8": "^
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"temp-write": "^5.0.0",
|
|
143
|
-
"tempy": "^3.0.0",
|
|
144
|
-
"touch": "^3.1.0",
|
|
145
|
-
"tsd": "^0.28.1",
|
|
146
|
-
"typescript": "^4.9.5",
|
|
147
|
-
"xo": "^0.54.2",
|
|
133
|
+
"c8": "^8.0.1",
|
|
134
|
+
"execa": "^8.0.1",
|
|
135
|
+
"expect": "^29.7.0",
|
|
136
|
+
"sinon": "^17.0.1",
|
|
137
|
+
"tap": "^18.6.1",
|
|
138
|
+
"tempy": "^3.1.0",
|
|
139
|
+
"tsd": "^0.29.0",
|
|
140
|
+
"typescript": "~5.3.2",
|
|
141
|
+
"xo": "^0.56.0",
|
|
148
142
|
"zen-observable": "^0.10.0"
|
|
149
143
|
},
|
|
150
144
|
"peerDependencies": {
|
|
@@ -156,6 +150,6 @@
|
|
|
156
150
|
}
|
|
157
151
|
},
|
|
158
152
|
"volta": {
|
|
159
|
-
"node": "20.
|
|
153
|
+
"node": "20.10.0"
|
|
160
154
|
}
|
|
161
155
|
}
|
package/readme.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
[
|
|
1
|
+
*[Please support our friend Vadim Demedes and the people in Ukraine.](https://stand-with-ukraine.pp.ua/)*
|
|
2
|
+
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
# <img src="media/header.png" title="AVA" alt="AVA logo" width="530">
|
|
4
6
|
|
|
5
|
-
AVA is a test runner for Node.js with a concise API, detailed error output, embrace of new language features and
|
|
7
|
+
AVA is a test runner for Node.js with a concise API, detailed error output, embrace of new language features and htread isolation that lets you develop with confidence 🚀
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Watch this repository and follow the [Discussions](https://github.com/avajs/ava/discussions) for updates.
|
|
8
10
|
|
|
9
11
|
Read our [contributing guide](.github/CONTRIBUTING.md) if you're looking to contribute (issues / PRs / etc).
|
|
10
12
|
|
|
@@ -23,7 +25,7 @@ Translations: [Español](https://github.com/avajs/ava-docs/blob/main/es_ES/readm
|
|
|
23
25
|
- No implicit globals
|
|
24
26
|
- Includes TypeScript definitions
|
|
25
27
|
- [Magic assert](#magic-assert)
|
|
26
|
-
- [Isolated environment for each test file](./docs/01-writing-tests.md#
|
|
28
|
+
- [Isolated environment for each test file](./docs/01-writing-tests.md#test-isolation)
|
|
27
29
|
- [Promise support](./docs/01-writing-tests.md#promise-support)
|
|
28
30
|
- [Async function support](./docs/01-writing-tests.md#async-function-support)
|
|
29
31
|
- [Observable support](./docs/01-writing-tests.md#observable-support)
|
|
@@ -166,14 +168,6 @@ We have a growing list of [common pitfalls](docs/08-common-pitfalls.md) you may
|
|
|
166
168
|
|
|
167
169
|
## FAQ
|
|
168
170
|
|
|
169
|
-
### Why not `mocha`, `tape`, `tap`?
|
|
170
|
-
|
|
171
|
-
Mocha requires you to use implicit globals like `describe` and `it` with the default interface (which most people use). It's not very opinionated and executes tests serially without process isolation, making it slow.
|
|
172
|
-
|
|
173
|
-
Tape and tap are pretty good. AVA is highly inspired by their syntax. They too execute tests serially. Their default [TAP](https://testanything.org) output isn't very user-friendly though so you always end up using an external tap reporter.
|
|
174
|
-
|
|
175
|
-
In contrast AVA is highly opinionated and runs tests concurrently, with a separate process for each test file. Its default reporter is easy on the eyes and yet AVA still supports TAP output through a CLI flag.
|
|
176
|
-
|
|
177
171
|
### How is the name written and pronounced?
|
|
178
172
|
|
|
179
173
|
AVA, not Ava or ava. Pronounced [`/ˈeɪvə/`](media/pronunciation.m4a?raw=true): Ay (f**a**ce, m**a**de) V (**v**ie, ha**v**e) A (comm**a**, **a**go)
|