ava 7.0.0 → 8.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.
Files changed (61) hide show
  1. package/entrypoints/{eslint-plugin-helper.cjs → eslint-plugin-helper.js} +10 -13
  2. package/entrypoints/{internal.d.mts → internal.d.ts} +1 -1
  3. package/entrypoints/{main.d.mts → main.d.ts} +5 -5
  4. package/entrypoints/{main.mjs → main.js} +1 -1
  5. package/entrypoints/{plugin.d.cts → plugin.d.ts} +2 -2
  6. package/entrypoints/plugin.js +1 -0
  7. package/index.d.ts +2 -2
  8. package/lib/api-event-iterator.js +2 -2
  9. package/lib/api.js +6 -6
  10. package/lib/assert.js +6 -5
  11. package/lib/cli.js +7 -27
  12. package/lib/create-chain.js +68 -25
  13. package/lib/extensions.js +5 -7
  14. package/lib/fork.js +3 -3
  15. package/lib/{glob-helpers.cjs → glob-helpers.js} +16 -30
  16. package/lib/globs.js +3 -3
  17. package/lib/{ipc-flow-control.cjs → ipc-flow-control.js} +1 -4
  18. package/lib/load-config.js +2 -3
  19. package/lib/{now-and-timers.cjs → now-and-timers.js} +11 -8
  20. package/lib/pkg.js +1 -0
  21. package/lib/plugin-support/shared-worker-loader.js +2 -2
  22. package/lib/plugin-support/shared-workers.js +3 -3
  23. package/lib/provider-manager.js +6 -5
  24. package/lib/reporters/default.js +1 -1
  25. package/lib/reporters/improper-usage-messages.js +1 -1
  26. package/lib/reporters/tap.js +10 -4
  27. package/lib/runner.js +5 -5
  28. package/lib/scheduler.js +1 -1
  29. package/lib/snapshot-manager.js +43 -12
  30. package/lib/test.js +15 -8
  31. package/lib/watcher.js +10 -18
  32. package/lib/worker/base.js +17 -41
  33. package/lib/worker/{channel.cjs → channel.js} +21 -25
  34. package/lib/worker/completion-handlers.js +3 -3
  35. package/lib/worker/{guard-environment.cjs → guard-environment.js} +4 -5
  36. package/lib/worker/line-numbers.js +3 -7
  37. package/lib/worker/main.js +11 -0
  38. package/lib/worker/{options.cjs → options.js} +4 -5
  39. package/lib/worker/{plugin.cjs → plugin.js} +8 -10
  40. package/lib/worker/state.js +5 -0
  41. package/lib/worker/utils.js +5 -0
  42. package/package.json +30 -38
  43. package/plugin.d.ts +1 -1
  44. package/types/{test-fn.d.cts → test-fn.d.ts} +24 -3
  45. package/types/{try-fn.d.cts → try-fn.d.ts} +1 -2
  46. package/entrypoints/main.cjs +0 -2
  47. package/entrypoints/main.d.cts +0 -12
  48. package/entrypoints/plugin.cjs +0 -2
  49. package/entrypoints/plugin.d.mts +0 -6
  50. package/entrypoints/plugin.mjs +0 -4
  51. package/lib/module-types.js +0 -85
  52. package/lib/pkg.cjs +0 -2
  53. package/lib/slash.cjs +0 -36
  54. package/lib/worker/main.cjs +0 -12
  55. package/lib/worker/state.cjs +0 -6
  56. package/lib/worker/utils.cjs +0 -6
  57. /package/entrypoints/{cli.mjs → cli.js} +0 -0
  58. /package/types/{assertions.d.cts → assertions.d.ts} +0 -0
  59. /package/types/{shared-worker.d.cts → shared-worker.d.ts} +0 -0
  60. /package/types/{state-change-events.d.cts → state-change-events.d.ts} +0 -0
  61. /package/types/{subscribable.d.cts → subscribable.d.ts} +0 -0
@@ -2,7 +2,7 @@ import {EventEmitter, on} from 'node:events';
2
2
  import process from 'node:process';
3
3
  import {workerData, parentPort, threadId} from 'node:worker_threads';
4
4
 
5
- import pkg from '../pkg.cjs';
5
+ import pkg from '../pkg.js';
6
6
 
7
7
  // Used to forward messages received over the `parentPort` and any direct ports
8
8
  // to test workers. Every subscription adds a listener, so do not enforce any
@@ -199,7 +199,7 @@ try {
199
199
 
200
200
  // Run possibly asynchronous release functions serially, in reverse
201
201
  // order. Any error will crash the worker.
202
- for await (const fn of [...teardownFns].reverse()) {
202
+ for await (const fn of [...teardownFns].toReversed()) {
203
203
  await fn();
204
204
  }
205
205
 
@@ -84,7 +84,7 @@ export async function observeWorkerProcess(fork, runStatus) {
84
84
  }
85
85
  };
86
86
 
87
- fork.promise.finally(() => { // eslint-disable-line promise/prefer-await-to-then
87
+ fork.promise.finally(() => {
88
88
  removeAllInstances();
89
89
  });
90
90
 
@@ -99,7 +99,7 @@ export async function observeWorkerProcess(fork, runStatus) {
99
99
  }
100
100
  };
101
101
 
102
- launched.statePromises.error.then(error => { // eslint-disable-line promise/prefer-await-to-then
102
+ launched.statePromises.error.then(error => {
103
103
  launched.worker.off('message', handleWorkerMessage);
104
104
  removeAllInstances();
105
105
  runStatus.emitStateChange({type: 'shared-worker-error', err: serializeError(error)});
@@ -118,7 +118,7 @@ export async function observeWorkerProcess(fork, runStatus) {
118
118
  port,
119
119
  }, [port]);
120
120
 
121
- fork.promise.finally(() => { // eslint-disable-line promise/prefer-await-to-then
121
+ fork.promise.finally(() => {
122
122
  launched.worker.postMessage({
123
123
  type: 'deregister-test-worker',
124
124
  id: fork.threadId,
@@ -1,14 +1,15 @@
1
1
  import * as globs from './globs.js';
2
- import pkg from './pkg.cjs';
2
+ import pkg from './pkg.js';
3
3
 
4
+ // Provides an integer representation of the protocol level. This is internal to a particular AVA installation, and
5
+ // allows other parts of AVA to assert minimum protocol levels for certain features without having to hardcode
6
+ // identifier strings. Integer values can be reused across protocols when older identifiers are removed.
4
7
  export const levels = {
5
- // As the protocol changes, comparing levels by integer allows AVA to be
6
- // compatible with different versions.
7
- ava6: 1,
8
+ ava8: 1,
8
9
  };
9
10
 
10
11
  const levelsByProtocol = Object.assign(Object.create(null), {
11
- 'ava-6': levels.ava6,
12
+ 'ava-8': levels.ava8,
12
13
  });
13
14
 
14
15
  async function load(providerModule, projectDir, selectProtocol = () => true) {
@@ -148,7 +148,7 @@ export default class Reporter {
148
148
  this.prefixTitle = (testFile, title) => prefixTitle(this.extensions, plan.filePathPrefix, testFile, title);
149
149
  }
150
150
 
151
- this.removePreviousListener = plan.status.on('stateChange', evt => {
151
+ this.removePreviousListener = plan.status.on('stateChange', ({data: evt}) => {
152
152
  this.consumeStateChange(evt);
153
153
  });
154
154
 
@@ -1,5 +1,5 @@
1
1
  import {chalk} from '../chalk.js';
2
- import pkg from '../pkg.cjs';
2
+ import pkg from '../pkg.js';
3
3
 
4
4
  export default function buildMessage(improperUsage) {
5
5
  if (!improperUsage) {
@@ -24,7 +24,13 @@ function dumpError({
24
24
  };
25
25
  }
26
26
 
27
- originalError.name = name; // Restore the original name.
27
+ if (originalError && Object.getOwnPropertyDescriptor(originalError, 'name')?.writable !== false) {
28
+ try {
29
+ originalError.name = name; // Restore the original name.
30
+ } catch {
31
+ // Ignore
32
+ }
33
+ }
28
34
 
29
35
  if (type === 'ava') {
30
36
  if (assertion) {
@@ -46,8 +52,6 @@ function dumpError({
46
52
 
47
53
  export default class TapReporter {
48
54
  constructor(options) {
49
- this.i = 0;
50
-
51
55
  this.extensions = options.extensions;
52
56
  this.stdStream = options.stdStream;
53
57
  this.reportStream = options.reportStream;
@@ -65,7 +69,7 @@ export default class TapReporter {
65
69
  this.prefixTitle = (testFile, title) => prefixTitle(this.extensions, plan.filePathPrefix, testFile, title);
66
70
  }
67
71
 
68
- plan.status.on('stateChange', evt => this.consumeStateChange(evt));
72
+ plan.status.on('stateChange', ({data: evt}) => this.consumeStateChange(evt));
69
73
 
70
74
  this.reportStream.write(supertap.start() + os.EOL);
71
75
  }
@@ -259,4 +263,6 @@ export default class TapReporter {
259
263
  }
260
264
  }
261
265
  }
266
+
267
+ i = 0;
262
268
  }
package/lib/runner.js CHANGED
@@ -10,7 +10,7 @@ import parseTestArgs from './parse-test-args.js';
10
10
  import serializeError from './serialize-error.js';
11
11
  import {load as loadSnapshots, determineSnapshotDir} from './snapshot-manager.js';
12
12
  import Runnable from './test.js';
13
- import {waitForReady} from './worker/state.cjs';
13
+ import {waitForReady} from './worker/state.js';
14
14
 
15
15
  const makeFileURL = file => file.startsWith('file://') ? file : pathToFileURL(file).toString();
16
16
 
@@ -254,7 +254,7 @@ export default class Runner extends Emittery {
254
254
  let waitForSerial = Promise.resolve();
255
255
  await runnables.reduce((previous, runnable) => { // eslint-disable-line unicorn/no-array-reduce
256
256
  if (runnable.metadata.serial || this.serial) {
257
- waitForSerial = previous.then(() => // eslint-disable-line promise/prefer-await-to-then
257
+ waitForSerial = previous.then(() =>
258
258
  // Serial runnables run as long as there was no previous failure, unless
259
259
  // the runnable should always be run.
260
260
  (allPassed || runnable.metadata.always) && runAndStoreResult(runnable));
@@ -263,7 +263,7 @@ export default class Runner extends Emittery {
263
263
 
264
264
  return Promise.all([
265
265
  previous,
266
- waitForSerial.then(() => // eslint-disable-line promise/prefer-await-to-then
266
+ waitForSerial.then(() =>
267
267
  // Concurrent runnables are kicked off after the previous serial
268
268
  // runnables have completed, as long as there was no previous failure
269
269
  // (or if the runnable should always be run). One concurrent runnable's
@@ -476,7 +476,7 @@ export default class Runner extends Emittery {
476
476
 
477
477
  // Note that the hooks and tests always begin running asynchronously.
478
478
  const beforePromise = this.runHooks(this.tasks.before, contextRef);
479
- const serialPromise = beforePromise.then(beforeHooksOk => { // eslint-disable-line promise/prefer-await-to-then
479
+ const serialPromise = beforePromise.then(beforeHooksOk => {
480
480
  // Don't run tests if a `before` hook failed.
481
481
  if (!beforeHooksOk) {
482
482
  return false;
@@ -498,7 +498,7 @@ export default class Runner extends Emittery {
498
498
  return this.runTest(task, contextRef.copy());
499
499
  }, true);
500
500
  });
501
- const concurrentPromise = Promise.all([beforePromise, serialPromise]).then(async ([beforeHooksOk, serialOk]) => { // eslint-disable-line promise/prefer-await-to-then
501
+ const concurrentPromise = Promise.all([beforePromise, serialPromise]).then(async ([beforeHooksOk, serialOk]) => {
502
502
  // Don't run tests if a `before` hook failed, or if `failFast` is enabled
503
503
  // and a previous serial test failed.
504
504
  if (!beforeHooksOk || (!serialOk && this.failFast)) {
package/lib/scheduler.js CHANGED
@@ -45,7 +45,7 @@ const scheduler = {
45
45
  return selectedFiles;
46
46
  }
47
47
 
48
- return [...selectedFiles].sort((f, s) => {
48
+ return selectedFiles.toSorted((f, s) => {
49
49
  if (failedTestFiles.includes(f) && failedTestFiles.includes(s)) {
50
50
  return 0;
51
51
  }
@@ -6,14 +6,16 @@ import path from 'node:path';
6
6
  import {fileURLToPath} from 'node:url';
7
7
  import zlib from 'node:zlib';
8
8
 
9
- import cbor from 'cbor';
9
+ import {decode as decodeCbor, encode as encodeCbor, TypeEncoderMap} from 'cbor2';
10
+ import {writeArray, writeUint8Array} from 'cbor2/encoder';
11
+ import {sortLengthFirstDeterministic} from 'cbor2/sorts';
10
12
  import concordance from 'concordance';
11
13
  import indentString from 'indent-string';
12
14
  import memoize from 'memoize';
15
+ import slash from 'slash';
13
16
  import writeFileAtomic from 'write-file-atomic';
14
17
 
15
18
  import {snapshotManager as concordanceOptions} from './concordance-options.js';
16
- import slash from './slash.cjs';
17
19
 
18
20
  // Increment if encoding layout or Concordance serialization versions change. Previous AVA versions will not be able to
19
21
  // decode buffers generated by a newer version, so changing this value will require a major version bump of AVA itself.
@@ -92,7 +94,7 @@ function formatEntry(snapshot, index) {
92
94
  } = snapshot;
93
95
 
94
96
  const description = data
95
- ? concordance.formatDescriptor(concordance.deserialize(data), concordanceOptions)
97
+ ? concordance.formatDescriptor(concordance.deserialize(Buffer.from(data.buffer, data.byteOffset, data.byteLength)), concordanceOptions)
96
98
  : '<No Data>';
97
99
 
98
100
  const blockquote = label.split(/\n/).map(line => '> ' + line).join('\n');
@@ -160,7 +162,7 @@ class BufferBuilder {
160
162
  }
161
163
 
162
164
  function sortBlocks(blocksByTitle, blockIndices) {
163
- return [...blocksByTitle].sort(([aTitle], [bTitle]) => {
165
+ return [...blocksByTitle].toSorted(([aTitle], [bTitle]) => {
164
166
  const a = blockIndices.get(aTitle);
165
167
  const b = blockIndices.get(bTitle);
166
168
 
@@ -180,10 +182,36 @@ function sortBlocks(blocksByTitle, blockIndices) {
180
182
  });
181
183
  }
182
184
 
183
- async function encodeSnapshots(snapshotData) {
184
- const encoded = await cbor.encodeAsync(snapshotData, {
185
- omitUndefinedProperties: true,
186
- canonical: true,
185
+ function normalizeBeforeEncoding(value) {
186
+ if (Array.isArray(value)) {
187
+ return value.map(v => normalizeBeforeEncoding(v));
188
+ }
189
+
190
+ // FIXME: The decode code path unexpectedly returns Buffers not Uint8Arrays.
191
+ if (Buffer.isBuffer(value)) {
192
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
193
+ }
194
+
195
+ if (value !== null && typeof value === 'object' && !(value instanceof Uint8Array)) {
196
+ return Object.fromEntries(Object.entries(value)
197
+ .filter(([, v]) => v !== undefined)
198
+ .map(([k, v]) => [k, normalizeBeforeEncoding(v)]));
199
+ }
200
+
201
+ return value;
202
+ }
203
+
204
+ // FIXME: This seems to be a bug in cbor2, ignoreGlobalTags shouldn't break (Uint8)Array encoding.
205
+ const types = new TypeEncoderMap();
206
+ types.registerEncoder(Array, writeArray);
207
+ types.registerEncoder(Uint8Array, writeUint8Array);
208
+
209
+ function encodeSnapshots(snapshotData) {
210
+ const encoded = encodeCbor(normalizeBeforeEncoding(snapshotData), {
211
+ ignoreGlobalTags: true,
212
+ rejectUndefined: true,
213
+ sortKeys: sortLengthFirstDeterministic,
214
+ types,
187
215
  });
188
216
  const compressed = zlib.gzipSync(encoded);
189
217
  compressed[9] = 0x03; // Override the GZip header containing the OS to always be Linux
@@ -233,7 +261,9 @@ function decodeSnapshots(buffer, snapPath) {
233
261
  }
234
262
 
235
263
  const decompressed = zlib.gunzipSync(compressed);
236
- return cbor.decode(decompressed);
264
+ return decodeCbor(decompressed, {
265
+ ignoreGlobalTags: true,
266
+ });
237
267
  }
238
268
 
239
269
  class Manager {
@@ -282,7 +312,7 @@ class Manager {
282
312
  return {pass: true};
283
313
  }
284
314
 
285
- const actual = concordance.deserialize(data, concordanceOptions);
315
+ const actual = concordance.deserialize(Buffer.from(data.buffer, data.byteOffset, data.byteLength), concordanceOptions);
286
316
  const expected = concordance.describe(options.expected, concordanceOptions);
287
317
  const pass = concordance.compareDescriptors(actual, expected);
288
318
 
@@ -311,7 +341,8 @@ class Manager {
311
341
  deferRecord(options) {
312
342
  const {expected, belongsTo, label, index} = options;
313
343
  const descriptor = concordance.describe(expected, concordanceOptions);
314
- const data = concordance.serialize(descriptor);
344
+ const buffer = concordance.serialize(descriptor);
345
+ const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
315
346
 
316
347
  return () => { // Must be called in order!
317
348
  this.hasChanges = true;
@@ -369,7 +400,7 @@ class Manager {
369
400
  blocks: sortBlocks(this.newBlocksByTitle, this.blockIndices).map(([title, block]) => ({title, ...block})),
370
401
  };
371
402
 
372
- const buffer = await encodeSnapshots(snapshots);
403
+ const buffer = encodeSnapshots(snapshots);
373
404
  const reportBuffer = generateReport(relFile, snapFile, snapshots);
374
405
 
375
406
  await fs.promises.mkdir(dir, {recursive: true});
package/lib/test.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  AssertionError, Assertions, checkAssertionMessage, getAssertionStack,
7
7
  } from './assert.js';
8
8
  import concordanceOptions from './concordance-options.js';
9
- import nowAndTimers from './now-and-timers.cjs';
9
+ import * as nowAndTimers from './now-and-timers.js';
10
10
  import parseTestArgs from './parse-test-args.js';
11
11
 
12
12
  function isExternalAssertError(error) {
@@ -43,8 +43,8 @@ class ExecutionContext extends Assertions {
43
43
  test.countPassedAssertion();
44
44
  return true;
45
45
  },
46
- pending(promise) {
47
- test.addPendingAssertion(promise);
46
+ pending(promise, assertionStack) {
47
+ test.addPendingAssertion(promise, assertionStack);
48
48
  },
49
49
  fail(error) {
50
50
  return test.addFailedAssertion(error);
@@ -293,6 +293,7 @@ export default class Test {
293
293
  this.finishDueToTimeout = null;
294
294
  this.finishing = false;
295
295
  this.pendingAssertionCount = 0;
296
+ this.pendingAssertionMetadata = new Set();
296
297
  this.pendingAttemptCount = 0;
297
298
  this.planCount = null;
298
299
  this.startedAt = 0;
@@ -321,7 +322,7 @@ export default class Test {
321
322
  this.logs.push(text);
322
323
  }
323
324
 
324
- async addPendingAssertion(promise) {
325
+ async addPendingAssertion(promise, assertionStack) {
325
326
  if (this.finishing) {
326
327
  this.saveFirstError(new Error('Assertion started, but test has already finished'));
327
328
  }
@@ -332,6 +333,8 @@ export default class Test {
332
333
 
333
334
  this.assertCount++;
334
335
  this.pendingAssertionCount++;
336
+ const metadata = {assertionStack};
337
+ this.pendingAssertionMetadata.add(metadata);
335
338
  this.refreshTimeout();
336
339
 
337
340
  try {
@@ -340,6 +343,7 @@ export default class Test {
340
343
  // Ignore errors.
341
344
  } finally {
342
345
  this.pendingAssertionCount--;
346
+ this.pendingAssertionMetadata.delete(metadata);
343
347
  this.refreshTimeout();
344
348
  }
345
349
  }
@@ -474,7 +478,7 @@ export default class Test {
474
478
  }
475
479
 
476
480
  async runTeardowns() {
477
- const teardowns = [...this.teardowns].reverse();
481
+ const teardowns = this.teardowns.toReversed();
478
482
 
479
483
  for (const teardown of teardowns) {
480
484
  try {
@@ -505,7 +509,10 @@ export default class Test {
505
509
  }
506
510
 
507
511
  if (this.pendingAssertionCount > 0) {
508
- this.saveFirstError(new Error('Test finished, but an assertion is still pending'));
512
+ const [first] = this.pendingAssertionMetadata;
513
+ this.saveFirstError(new AssertionError('Test finished, but an assertion was not awaited', {
514
+ assertionStack: first?.assertionStack ?? '',
515
+ }));
509
516
  return;
510
517
  }
511
518
 
@@ -590,7 +597,7 @@ export default class Test {
590
597
  };
591
598
 
592
599
  promise
593
- .catch(error => { // eslint-disable-line promise/prefer-await-to-then
600
+ .catch(error => {
594
601
  if (this.testFailure !== null && error === this.testFailure) {
595
602
  return;
596
603
  }
@@ -607,7 +614,7 @@ export default class Test {
607
614
  }));
608
615
  }
609
616
  })
610
- .then(() => resolve(this.finish())); // eslint-disable-line promise/prefer-await-to-then
617
+ .then(() => resolve(this.finish()));
611
618
  });
612
619
  }
613
620
 
package/lib/watcher.js CHANGED
@@ -12,7 +12,6 @@ import {
12
12
  applyTestFileFilter, classify, buildIgnoreMatcher, findTests,
13
13
  normalizePattern,
14
14
  } from './globs.js';
15
- import {levels as providerLevels} from './provider-manager.js';
16
15
 
17
16
  const debug = createDebug('ava:watcher');
18
17
 
@@ -158,7 +157,6 @@ const promptForMatchPattern = async (reporter, lineReader, currentPattern) => {
158
157
  };
159
158
 
160
159
  export async function start({api, filter, globs, projectDir, providers, reporter, stdin, signal}) {
161
- providers = providers.filter(({level}) => level >= providerLevels.ava6);
162
160
  for await (const {files, testFileSelector, ...runtimeOptions} of plan({
163
161
  api,
164
162
  filter,
@@ -210,7 +208,7 @@ async function * plan({
210
208
  };
211
209
 
212
210
  // Begin a file trace in the background.
213
- fileTracer.update(findTests(cwdAndGlobs).then(testFiles => testFiles.map(path => ({ // eslint-disable-line promise/prefer-await-to-then
211
+ fileTracer.update(findTests(cwdAndGlobs).then(testFiles => testFiles.map(path => ({
214
212
  path: nodePath.relative(projectDir, path),
215
213
  isTest: true,
216
214
  exists: true,
@@ -231,8 +229,8 @@ async function * plan({
231
229
  };
232
230
 
233
231
  // Observe all test runs.
234
- api.on('run', ({status}) => {
235
- status.on('stateChange', evt => {
232
+ api.on('run', ({data: {status}}) => {
233
+ status.on('stateChange', ({data: evt}) => {
236
234
  switch (evt.type) {
237
235
  case 'accessed-snapshots': {
238
236
  fileTracer.addDependency(nodePath.relative(projectDir, evt.testFile), nodePath.relative(projectDir, evt.filename));
@@ -258,8 +256,11 @@ async function * plan({
258
256
  case 'uncaught-exception':
259
257
  case 'unhandled-rejection':
260
258
  case 'worker-failed': {
261
- const path = nodePath.relative(projectDir, evt.testFile);
262
- failureCounts.set(path, 1 + (failureCounts.get(path) ?? 0));
259
+ if (evt.testFile) {
260
+ const path = nodePath.relative(projectDir, evt.testFile);
261
+ failureCounts.set(path, 1 + (failureCounts.get(path) ?? 0));
262
+ }
263
+
263
264
  break;
264
265
  }
265
266
 
@@ -425,7 +426,7 @@ async function * plan({
425
426
  // If the file tracer is still analyzing dependencies, wait for that to
426
427
  // complete.
427
428
  if (fileTracer.busy !== null) {
428
- fileTracer.busy.then(() => debounce.refresh()); // eslint-disable-line promise/prefer-await-to-then
429
+ fileTracer.busy.then(() => debounce.refresh());
429
430
  takeCoverageForSelfTests?.();
430
431
  return;
431
432
  }
@@ -707,15 +708,10 @@ class FileTracer {
707
708
  #base;
708
709
  #cache = Object.create(null);
709
710
  #pendingTrace = null;
710
- #updateRunning;
711
- #signalUpdateRunning;
712
711
  #tree = new Tree();
713
712
 
714
713
  constructor({base}) {
715
714
  this.#base = base;
716
- this.#updateRunning = new Promise(resolve => {
717
- this.#signalUpdateRunning = resolve;
718
- });
719
715
  }
720
716
 
721
717
  get busy() {
@@ -761,12 +757,9 @@ class FileTracer {
761
757
  }
762
758
 
763
759
  update(changes) {
764
- const current = this.#update(changes).finally(() => { // eslint-disable-line promise/prefer-await-to-then
760
+ const current = this.#update(changes).finally(() => {
765
761
  if (this.#pendingTrace === current) {
766
762
  this.#pendingTrace = null;
767
- this.#updateRunning = new Promise(resolve => {
768
- this.#signalUpdateRunning = resolve;
769
- });
770
763
  }
771
764
  });
772
765
 
@@ -775,7 +768,6 @@ class FileTracer {
775
768
 
776
769
  async #update(changes) {
777
770
  await this.#pendingTrace; // Guard against race conditions.
778
- this.#signalUpdateRunning();
779
771
 
780
772
  let reuseCache = true;
781
773
  const knownTestFiles = new Set();
@@ -1,5 +1,4 @@
1
1
  import {mkdir} from 'node:fs/promises';
2
- import {createRequire} from 'node:module';
3
2
  import path from 'node:path';
4
3
  import process from 'node:process';
5
4
  import {pathToFileURL} from 'node:url';
@@ -9,17 +8,17 @@ import setUpCurrentlyUnhandled from 'currently-unhandled';
9
8
  import writeFileAtomic from 'write-file-atomic';
10
9
 
11
10
  import {set as setChalk} from '../chalk.js';
12
- import nowAndTimers from '../now-and-timers.cjs';
11
+ import {setImmediate} from '../now-and-timers.js';
13
12
  import providerManager from '../provider-manager.js';
14
13
  import Runner from '../runner.js';
15
14
  import serializeError from '../serialize-error.js';
16
15
 
17
- import channel from './channel.cjs';
16
+ import * as channel from './channel.js';
18
17
  import {runCompletionHandlers} from './completion-handlers.js';
19
18
  import lineNumberSelection from './line-numbers.js';
20
- import {set as setOptions} from './options.cjs';
21
- import {flags, refs, sharedWorkerTeardowns} from './state.cjs';
22
- import {isRunningInThread, isRunningInChildProcess} from './utils.cjs';
19
+ import {set as setOptions} from './options.js';
20
+ import {flags, refs, sharedWorkerTeardowns} from './state.js';
21
+ import {isRunningInThread, isRunningInChildProcess} from './utils.js';
23
22
 
24
23
  const currentlyUnhandled = setUpCurrentlyUnhandled();
25
24
  let runner;
@@ -88,14 +87,14 @@ const run = async options => {
88
87
 
89
88
  refs.runnerChain = runner.chain;
90
89
 
91
- channel.peerFailed.then(() => { // eslint-disable-line promise/prefer-await-to-then
90
+ channel.peerFailed.then(() => {
92
91
  runner.interrupt();
93
92
  });
94
93
 
95
- runner.on('accessed-snapshots', filename => channel.send({type: 'accessed-snapshots', filename}));
96
- runner.on('stateChange', state => channel.send(state));
94
+ runner.on('accessed-snapshots', ({data: filename}) => channel.send({type: 'accessed-snapshots', filename}));
95
+ runner.on('stateChange', ({data: state}) => channel.send(state));
97
96
 
98
- runner.on('error', error => {
97
+ runner.on('error', ({data: error}) => {
99
98
  channel.send({type: 'internal-error', err: serializeError(error)});
100
99
  forceExit();
101
100
  });
@@ -129,7 +128,7 @@ const run = async options => {
129
128
  await channel.workerFreed;
130
129
  channel.unref();
131
130
 
132
- nowAndTimers.setImmediate(() => {
131
+ setImmediate(() => {
133
132
  const unhandled = currentlyUnhandled();
134
133
  if (unhandled.length === 0) {
135
134
  return avaIsDone();
@@ -151,10 +150,6 @@ const run = async options => {
151
150
  // Store value to prevent required modules from modifying it.
152
151
  const testPath = options.file;
153
152
 
154
- const extensionsToLoadAsModules = Object.entries(options.moduleTypes)
155
- .filter(([, type]) => type === 'module')
156
- .map(([extension]) => extension);
157
-
158
153
  // Install before processing options.require, so if helpers are added to the
159
154
  // require configuration the *compiled* helper will be loaded.
160
155
  const {projectDir, providerStates = []} = options;
@@ -162,26 +157,18 @@ const run = async options => {
162
157
  await Promise.all(providerStates.map(async ({type, state, protocol}) => {
163
158
  if (type === 'typescript') {
164
159
  const provider = await providerManager.typescript(projectDir, {protocol});
165
- providers.push(provider.worker({extensionsToLoadAsModules, state}));
160
+ providers.push(provider.worker({state}));
166
161
  }
167
162
  }));
168
163
 
169
- const require = createRequire(import.meta.url);
170
164
  const load = async ref => {
171
165
  for (const provider of providers) {
172
166
  if (provider.canLoad(ref)) {
173
- return provider.load(ref, {requireFn: require});
174
- }
175
- }
176
-
177
- for (const extension of extensionsToLoadAsModules) {
178
- if (ref.endsWith(`.${extension}`)) {
179
- return import(pathToFileURL(ref));
167
+ return provider.load(ref);
180
168
  }
181
169
  }
182
170
 
183
- // We still support require() since it's more easily monkey-patched.
184
- return require(ref);
171
+ return import(pathToFileURL(ref));
185
172
  };
186
173
 
187
174
  const loadRequiredModule = async ref => {
@@ -189,21 +176,14 @@ const run = async options => {
189
176
  // dependency.
190
177
  for (const provider of providers) {
191
178
  if (provider.canLoad(ref)) {
192
- return provider.load(ref, {requireFn: require});
179
+ return provider.load(ref, {});
193
180
  }
194
181
  }
195
182
 
196
183
  // Try to load the module as a file, relative to the project directory.
197
- // Match load() behavior.
198
184
  const fullPath = path.resolve(projectDir, ref);
199
185
  try {
200
- for (const extension of extensionsToLoadAsModules) {
201
- if (fullPath.endsWith(`.${extension}`)) {
202
- return await import(pathToFileURL(fullPath)); // eslint-disable-line no-await-in-loop
203
- }
204
- }
205
-
206
- return require(fullPath);
186
+ return await import(pathToFileURL(fullPath));
207
187
  } catch (error) {
208
188
  // If the module could not be found, assume it's not a file but a dependency.
209
189
  if (error.code === 'ERR_MODULE_NOT_FOUND' || error.code === 'MODULE_NOT_FOUND') {
@@ -226,12 +206,8 @@ const run = async options => {
226
206
 
227
207
  try {
228
208
  for await (const [ref, ...args] of (options.require ?? [])) {
229
- const loadedModule = await loadRequiredModule(ref);
230
-
231
- if (typeof loadedModule === 'function') { // CJS module
232
- await loadedModule(...args);
233
- } else if (typeof loadedModule.default === 'function') { // ES module, or exports.default from CJS
234
- const {default: fn} = loadedModule;
209
+ const {default: fn} = await loadRequiredModule(ref);
210
+ if (typeof fn === 'function') {
235
211
  await fn(...args);
236
212
  }
237
213
  }