ava 5.1.0 → 5.1.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.
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
- const path = require('path');
3
- const url = require('url');
4
- const v8 = require('v8');
5
- const {Worker} = require('worker_threads');
2
+ const path = require('node:path');
3
+ const url = require('node:url');
4
+ const v8 = require('node:v8');
5
+ const {Worker} = require('node:worker_threads');
6
6
 
7
7
  const {
8
8
  classify,
package/lib/assert.js CHANGED
@@ -50,7 +50,7 @@ export class AssertionError extends Error {
50
50
  // use the values for custom diff views
51
51
  this.raw = options.raw;
52
52
 
53
- this.savedError = options.savedError ? options.savedError : getErrorWithLongStackTrace();
53
+ this.savedError = options.savedError || getErrorWithLongStackTrace();
54
54
  }
55
55
  }
56
56
 
@@ -143,14 +143,17 @@ function validateExpectations(assertion, expectations, numberArgs) { // eslint-d
143
143
  case 'is':
144
144
  case 'message':
145
145
  case 'name':
146
- case 'code':
146
+ case 'code': {
147
147
  continue;
148
- default:
148
+ }
149
+
150
+ default: {
149
151
  throw new AssertionError({
150
152
  assertion,
151
153
  message: `The second argument to \`t.${assertion}()\` contains unexpected properties`,
152
154
  values: [formatWithLabel('Called with:', expectations)],
153
155
  });
156
+ }
154
157
  }
155
158
  }
156
159
  }
@@ -33,7 +33,7 @@ const buildGlobs = ({conf, providers, projectDir, overrideExtensions, overrideFi
33
33
  cwd: projectDir,
34
34
  ...normalizeGlobs({
35
35
  extensions,
36
- files: overrideFiles ? overrideFiles : conf.files,
36
+ files: overrideFiles || conf.files,
37
37
  providers,
38
38
  }),
39
39
  };
@@ -69,5 +69,5 @@ const handleMessage = async ({projectDir, overrideExtensions, overrideFiles}) =>
69
69
  };
70
70
 
71
71
  parentPort.on('message', handleMessage);
72
- handleMessage(workerData.firstMessage);
72
+ handleMessage(workerData.firstMessage); // eslint-disable-line unicorn/prefer-top-level-await
73
73
  delete workerData.firstMessage;
package/lib/fork.js CHANGED
@@ -109,9 +109,11 @@ export default function loadFork(file, options, execArgv = process.execArgv) {
109
109
  }
110
110
 
111
111
  switch (message.ava.type) {
112
- case 'ready-for-options':
112
+ case 'ready-for-options': {
113
113
  send({type: 'options', options});
114
114
  break;
115
+ }
116
+
115
117
  case 'shared-worker-connect': {
116
118
  const {channelId, filename, initialData, port} = message.ava;
117
119
  emitter.emit('connectSharedWorker', {
@@ -125,11 +127,14 @@ export default function loadFork(file, options, execArgv = process.execArgv) {
125
127
  break;
126
128
  }
127
129
 
128
- case 'ping':
130
+ case 'ping': {
129
131
  send({type: 'pong'});
130
132
  break;
131
- default:
133
+ }
134
+
135
+ default: {
132
136
  emitStateChange(message.ava);
137
+ }
133
138
  }
134
139
  });
135
140
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
- const path = require('path');
3
- const process = require('process');
2
+ const path = require('node:path');
3
+ const process = require('node:process');
4
4
 
5
5
  const ignoreByDefault = require('ignore-by-default');
6
6
  const picomatch = require('picomatch');
@@ -6,21 +6,28 @@ const requireTrueValue = value => {
6
6
 
7
7
  const normalize = (extension, type, defaultModuleType) => {
8
8
  switch (extension) {
9
- case 'cjs':
9
+ case 'cjs': {
10
10
  requireTrueValue(type);
11
11
  return 'commonjs';
12
- case 'mjs':
12
+ }
13
+
14
+ case 'mjs': {
13
15
  requireTrueValue(type);
14
16
  return 'module';
15
- case 'js':
17
+ }
18
+
19
+ case 'js': {
16
20
  requireTrueValue(type);
17
21
  return defaultModuleType;
18
- default:
22
+ }
23
+
24
+ default: {
19
25
  if (type !== 'commonjs' && type !== 'module') {
20
26
  throw new TypeError(`Module type for ’${extension}’ must be ’commonjs’ or ’module’`);
21
27
  }
22
28
 
23
29
  return type;
30
+ }
24
31
  }
25
32
  };
26
33
 
@@ -37,17 +44,24 @@ const deriveFromArray = (extensions, defaultModuleType) => {
37
44
  const moduleTypes = {};
38
45
  for (const extension of extensions) {
39
46
  switch (extension) {
40
- case 'cjs':
47
+ case 'cjs': {
41
48
  moduleTypes.cjs = 'commonjs';
42
49
  break;
43
- case 'mjs':
50
+ }
51
+
52
+ case 'mjs': {
44
53
  moduleTypes.mjs = 'module';
45
54
  break;
46
- case 'js':
55
+ }
56
+
57
+ case 'js': {
47
58
  moduleTypes.js = defaultModuleType;
48
59
  break;
49
- default:
60
+ }
61
+
62
+ default: {
50
63
  moduleTypes[extension] = 'commonjs';
64
+ }
51
65
  }
52
66
  }
53
67
 
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
- const timers = require('timers');
2
+ const timers = require('node:timers');
3
3
 
4
4
  Object.assign(exports, timers);
5
5
  exports.now = Date.now;
@@ -166,7 +166,8 @@ let signalAvailable = () => {
166
166
  };
167
167
 
168
168
  let fatal;
169
- loadFactory(workerData.filename).then(factory => {
169
+ try {
170
+ const factory = await loadFactory(workerData.filename);
170
171
  if (typeof factory !== 'function') {
171
172
  throw new TypeError(`Missing default factory function export for shared worker plugin at ${workerData.filename}`);
172
173
  }
@@ -236,14 +237,12 @@ loadFactory(workerData.filename).then(factory => {
236
237
  };
237
238
  },
238
239
  });
239
- }).catch(error => {
240
- if (fatal === undefined) {
241
- fatal = error;
242
- }
243
- }).finally(() => {
240
+ } catch (error) {
241
+ fatal = fatal ?? error;
242
+ } finally {
244
243
  if (fatal !== undefined) {
245
244
  process.nextTick(() => {
246
245
  throw fatal;
247
246
  });
248
247
  }
249
- });
248
+ }
@@ -49,35 +49,54 @@ function launchWorker(filename, initialData) {
49
49
  }
50
50
 
51
51
  export async function observeWorkerProcess(fork, runStatus) {
52
- let registrationCount = 0;
53
- let signalDeregistered;
54
- const deregistered = new Promise(resolve => {
55
- signalDeregistered = resolve;
52
+ let signalDone;
53
+
54
+ const done = new Promise(resolve => {
55
+ signalDone = () => {
56
+ resolve();
57
+ };
56
58
  });
57
59
 
58
- fork.promise.finally(() => {
59
- if (registrationCount === 0) {
60
- signalDeregistered();
60
+ const activeInstances = new Set();
61
+
62
+ const removeInstance = instance => {
63
+ instance.worker.unref();
64
+ activeInstances.delete(instance);
65
+
66
+ if (activeInstances.size === 0) {
67
+ signalDone();
68
+ }
69
+ };
70
+
71
+ const removeAllInstances = () => {
72
+ if (activeInstances.size === 0) {
73
+ signalDone();
74
+ return;
61
75
  }
76
+
77
+ for (const instance of activeInstances) {
78
+ removeInstance(instance);
79
+ }
80
+ };
81
+
82
+ fork.promise.finally(() => {
83
+ removeAllInstances();
62
84
  });
63
85
 
64
86
  fork.onConnectSharedWorker(async ({filename, initialData, port, signalError}) => {
65
87
  const launched = launchWorker(filename, initialData);
88
+ activeInstances.add(launched);
66
89
 
67
90
  const handleWorkerMessage = async message => {
68
91
  if (message.type === 'deregistered-test-worker' && message.id === fork.threadId) {
69
92
  launched.worker.off('message', handleWorkerMessage);
70
-
71
- registrationCount--;
72
- if (registrationCount === 0) {
73
- signalDeregistered();
74
- }
93
+ removeInstance(launched);
75
94
  }
76
95
  };
77
96
 
78
97
  launched.statePromises.error.then(error => {
79
- signalDeregistered();
80
98
  launched.worker.off('message', handleWorkerMessage);
99
+ removeAllInstances();
81
100
  runStatus.emitStateChange({type: 'shared-worker-error', err: serializeError('Shared worker error', true, error)});
82
101
  signalError();
83
102
  });
@@ -85,8 +104,6 @@ export async function observeWorkerProcess(fork, runStatus) {
85
104
  try {
86
105
  await launched.statePromises.available;
87
106
 
88
- registrationCount++;
89
-
90
107
  port.postMessage({type: 'ready'});
91
108
 
92
109
  launched.worker.postMessage({
@@ -104,15 +121,8 @@ export async function observeWorkerProcess(fork, runStatus) {
104
121
  });
105
122
 
106
123
  launched.worker.on('message', handleWorkerMessage);
107
- } catch {
108
- return;
109
- } finally {
110
- // Attaching listeners has the side-effect of referencing the worker.
111
- // Explicitly unreference it now so it does not prevent the main process
112
- // from exiting.
113
- launched.worker.unref();
114
- }
124
+ } catch {}
115
125
  });
116
126
 
117
- return deregistered;
127
+ return done;
118
128
  }
@@ -153,26 +153,38 @@ export default class TapReporter {
153
153
  const fileStats = this.stats && evt.testFile ? this.stats.byFile.get(evt.testFile) : null;
154
154
 
155
155
  switch (evt.type) {
156
- case 'declared-test':
156
+ case 'declared-test': {
157
157
  // Ignore
158
158
  break;
159
- case 'hook-failed':
159
+ }
160
+
161
+ case 'hook-failed': {
160
162
  this.writeTest(evt, {passed: false, todo: false, skip: false});
161
163
  break;
162
- case 'hook-finished':
164
+ }
165
+
166
+ case 'hook-finished': {
163
167
  this.writeComment(evt, {});
164
168
  break;
165
- case 'internal-error':
169
+ }
170
+
171
+ case 'internal-error': {
166
172
  this.writeCrash(evt);
167
173
  break;
168
- case 'missing-ava-import':
174
+ }
175
+
176
+ case 'missing-ava-import': {
169
177
  this.filesWithMissingAvaImports.add(evt.testFile);
170
178
  this.writeCrash(evt, `No tests found in ${this.relativeFile(evt.testFile)}, make sure to import "ava" at the top of your test file`);
171
179
  break;
172
- case 'process-exit':
180
+ }
181
+
182
+ case 'process-exit': {
173
183
  this.writeProcessExit(evt);
174
184
  break;
175
- case 'selected-test':
185
+ }
186
+
187
+ case 'selected-test': {
176
188
  if (evt.skip) {
177
189
  this.writeTest(evt, {passed: true, todo: false, skip: true});
178
190
  } else if (evt.todo) {
@@ -180,25 +192,39 @@ export default class TapReporter {
180
192
  }
181
193
 
182
194
  break;
183
- case 'stats':
195
+ }
196
+
197
+ case 'stats': {
184
198
  this.stats = evt.stats;
185
199
  break;
186
- case 'test-failed':
200
+ }
201
+
202
+ case 'test-failed': {
187
203
  this.writeTest(evt, {passed: false, todo: false, skip: false});
188
204
  break;
189
- case 'test-passed':
205
+ }
206
+
207
+ case 'test-passed': {
190
208
  this.writeTest(evt, {passed: true, todo: false, skip: false});
191
209
  break;
192
- case 'timeout':
210
+ }
211
+
212
+ case 'timeout': {
193
213
  this.writeTimeout(evt);
194
214
  break;
195
- case 'uncaught-exception':
215
+ }
216
+
217
+ case 'uncaught-exception': {
196
218
  this.writeCrash(evt);
197
219
  break;
198
- case 'unhandled-rejection':
220
+ }
221
+
222
+ case 'unhandled-rejection': {
199
223
  this.writeCrash(evt);
200
224
  break;
201
- case 'worker-failed':
225
+ }
226
+
227
+ case 'worker-failed': {
202
228
  if (!this.filesWithMissingAvaImports.has(evt.testFile)) {
203
229
  if (evt.nonZeroExitCode) {
204
230
  this.writeCrash(evt, `${this.relativeFile(evt.testFile)} exited with a non-zero exit code: ${evt.nonZeroExitCode}`);
@@ -208,7 +234,9 @@ export default class TapReporter {
208
234
  }
209
235
 
210
236
  break;
211
- case 'worker-finished':
237
+ }
238
+
239
+ case 'worker-finished': {
212
240
  if (!evt.forcedExit && !this.filesWithMissingAvaImports.has(evt.testFile)) {
213
241
  if (fileStats.declaredTests === 0) {
214
242
  this.writeCrash(evt, `No tests found in ${this.relativeFile(evt.testFile)}`);
@@ -218,12 +246,17 @@ export default class TapReporter {
218
246
  }
219
247
 
220
248
  break;
249
+ }
250
+
221
251
  case 'worker-stderr':
222
- case 'worker-stdout':
252
+ case 'worker-stdout': {
223
253
  this.stdStream.write(evt.chunk);
224
254
  break;
225
- default:
255
+ }
256
+
257
+ default: {
226
258
  break;
259
+ }
227
260
  }
228
261
  }
229
262
  }
package/lib/run-status.js CHANGED
@@ -72,22 +72,28 @@ export default class RunStatus extends Emittery {
72
72
 
73
73
  let changedStats = true;
74
74
  switch (event.type) {
75
- case 'declared-test':
75
+ case 'declared-test': {
76
76
  stats.declaredTests++;
77
77
  fileStats.declaredTests++;
78
78
  break;
79
- case 'hook-failed':
79
+ }
80
+
81
+ case 'hook-failed': {
80
82
  stats.failedHooks++;
81
83
  fileStats.failedHooks++;
82
84
  break;
83
- case 'internal-error':
85
+ }
86
+
87
+ case 'internal-error': {
84
88
  stats.internalErrors++;
85
89
  if (event.testFile) {
86
90
  fileStats.internalErrors++;
87
91
  }
88
92
 
89
93
  break;
90
- case 'selected-test':
94
+ }
95
+
96
+ case 'selected-test': {
91
97
  stats.selectedTests++;
92
98
  fileStats.selectedTests++;
93
99
  if (event.skip) {
@@ -103,17 +109,23 @@ export default class RunStatus extends Emittery {
103
109
  }
104
110
 
105
111
  break;
106
- case 'shared-worker-error':
112
+ }
113
+
114
+ case 'shared-worker-error': {
107
115
  stats.sharedWorkerErrors++;
108
116
  break;
109
- case 'test-failed':
117
+ }
118
+
119
+ case 'test-failed': {
110
120
  stats.failedTests++;
111
121
  fileStats.failedTests++;
112
122
  stats.remainingTests--;
113
123
  fileStats.remainingTests--;
114
124
  this.removePendingTest(event);
115
125
  break;
116
- case 'test-passed':
126
+ }
127
+
128
+ case 'test-passed': {
117
129
  if (event.knownFailing) {
118
130
  stats.passedKnownFailingTests++;
119
131
  fileStats.passedKnownFailingTests++;
@@ -126,10 +138,14 @@ export default class RunStatus extends Emittery {
126
138
  fileStats.remainingTests--;
127
139
  this.removePendingTest(event);
128
140
  break;
129
- case 'test-register-log-reference':
141
+ }
142
+
143
+ case 'test-register-log-reference': {
130
144
  this.addPendingTestLogs(event);
131
145
  break;
132
- case 'timeout':
146
+ }
147
+
148
+ case 'timeout': {
133
149
  stats.timeouts++;
134
150
  event.pendingTests = this.pendingTests;
135
151
  event.pendingTestsLogs = this.pendingTestsLogs;
@@ -140,35 +156,50 @@ export default class RunStatus extends Emittery {
140
156
  }
141
157
 
142
158
  break;
143
- case 'interrupt':
159
+ }
160
+
161
+ case 'interrupt': {
144
162
  event.pendingTests = this.pendingTests;
145
163
  event.pendingTestsLogs = this.pendingTestsLogs;
146
164
  this.pendingTests = new Map();
147
165
  this.pendingTestsLogs = new Map();
148
166
  break;
149
- case 'process-exit':
167
+ }
168
+
169
+ case 'process-exit': {
150
170
  event.pendingTests = this.pendingTests;
151
171
  event.pendingTestsLogs = this.pendingTestsLogs;
152
172
  this.pendingTests = new Map();
153
173
  this.pendingTestsLogs = new Map();
154
174
  break;
155
- case 'uncaught-exception':
175
+ }
176
+
177
+ case 'uncaught-exception': {
156
178
  stats.uncaughtExceptions++;
157
179
  fileStats.uncaughtExceptions++;
158
180
  break;
159
- case 'unhandled-rejection':
181
+ }
182
+
183
+ case 'unhandled-rejection': {
160
184
  stats.unhandledRejections++;
161
185
  fileStats.unhandledRejections++;
162
186
  break;
163
- case 'worker-failed':
187
+ }
188
+
189
+ case 'worker-failed': {
164
190
  stats.failedWorkers++;
165
191
  break;
166
- case 'worker-finished':
192
+ }
193
+
194
+ case 'worker-finished': {
167
195
  stats.finishedWorkers++;
168
196
  break;
169
- default:
197
+ }
198
+
199
+ default: {
170
200
  changedStats = false;
171
201
  break;
202
+ }
172
203
  }
173
204
 
174
205
  if (changedStats) {
package/lib/watcher.js CHANGED
@@ -298,11 +298,14 @@ export default class Watcher {
298
298
  case 'test-failed':
299
299
  case 'uncaught-exception':
300
300
  case 'unhandled-rejection':
301
- case 'worker-failed':
301
+ case 'worker-failed': {
302
302
  this.countFailure(evt.testFile, currentVector);
303
303
  break;
304
- default:
304
+ }
305
+
306
+ default: {
305
307
  break;
308
+ }
306
309
  }
307
310
  });
308
311
  });
@@ -222,12 +222,18 @@ const onError = error => {
222
222
  });
223
223
  };
224
224
 
225
+ let options;
225
226
  if (isRunningInThread) {
226
227
  channel.send({type: 'starting'}); // AVA won't terminate the worker thread until it's seen this message.
227
- const {options} = workerData;
228
+ ({options} = workerData);
228
229
  delete workerData.options; // Don't allow user code access.
229
- run(options).catch(onError);
230
230
  } else if (isRunningInChildProcess) {
231
231
  channel.send({type: 'ready-for-options'});
232
- channel.options.then(run).catch(onError);
232
+ options = await channel.options;
233
+ }
234
+
235
+ try {
236
+ await run(options);
237
+ } catch (error) {
238
+ onError(error);
233
239
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
- const events = require('events');
3
- const process = require('process');
4
- const {MessageChannel, threadId} = require('worker_threads');
2
+ const events = require('node:events');
3
+ const process = require('node:process');
4
+ const {MessageChannel, threadId} = require('node:worker_threads');
5
5
 
6
6
  const timers = require('../now-and-timers.cjs');
7
7
 
@@ -125,7 +125,7 @@ if (isRunningInChildProcess) {
125
125
  const {controlFlow} = require('../ipc-flow-control.cjs');
126
126
  handle = new IpcHandle(controlFlow(process));
127
127
  } else if (isRunningInThread) {
128
- const {parentPort} = require('worker_threads');
128
+ const {parentPort} = require('node:worker_threads');
129
129
  handle = new MessagePortHandle(parentPort);
130
130
  }
131
131
 
@@ -133,7 +133,7 @@ if (isRunningInChildProcess) {
133
133
  // Node.js. In order to keep track, explicitly reference before attaching.
134
134
  handle.ref();
135
135
 
136
- exports.options = pEvent(handle.channel, 'message', selectAvaMessage('options')).then(message => message.ava.options);
136
+ exports.options = pEvent(handle.channel, 'message', selectAvaMessage('options')).then(message => message.ava.options); // eslint-disable-line unicorn/prefer-top-level-await
137
137
  exports.peerFailed = pEvent(handle.channel, 'message', selectAvaMessage('peer-failed'));
138
138
  exports.send = handle.send.bind(handle);
139
139
  exports.unref = handle.unref.bind(handle);
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
- const path = require('path');
3
- const process = require('process');
2
+ const path = require('node:path');
3
+ const process = require('node:process');
4
4
 
5
5
  const {isRunningInThread, isRunningInChildProcess} = require('./utils.cjs');
6
6
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  require('./guard-environment.cjs'); // eslint-disable-line import/no-unassigned-import
3
3
 
4
- const assert = require('assert');
4
+ const assert = require('node:assert');
5
5
 
6
6
  const {flags, refs} = require('./state.cjs');
7
7
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
- const process = require('process');
3
- const {isMainThread} = require('worker_threads');
2
+ const process = require('node:process');
3
+ const {isMainThread} = require('node:worker_threads');
4
4
 
5
5
  exports.isRunningInThread = isMainThread === false;
6
6
  exports.isRunningInChildProcess = typeof process.send === 'function';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ava",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "description": "Node.js test runner that lets you develop with confidence.",
5
5
  "license": "MIT",
6
6
  "repository": "avajs/ava",
@@ -88,10 +88,10 @@
88
88
  "arrify": "^3.0.0",
89
89
  "callsites": "^4.0.0",
90
90
  "cbor": "^8.1.0",
91
- "chalk": "^5.1.2",
91
+ "chalk": "^5.2.0",
92
92
  "chokidar": "^3.5.3",
93
93
  "chunkd": "^2.0.1",
94
- "ci-info": "^3.6.1",
94
+ "ci-info": "^3.7.1",
95
95
  "ci-parallel-vars": "^1.0.1",
96
96
  "clean-yaml-object": "^0.1.0",
97
97
  "cli-truncate": "^3.1.0",
@@ -103,7 +103,7 @@
103
103
  "del": "^7.0.0",
104
104
  "emittery": "^1.0.1",
105
105
  "figures": "^5.0.0",
106
- "globby": "^13.1.2",
106
+ "globby": "^13.1.3",
107
107
  "ignore-by-default": "^2.1.0",
108
108
  "indent-string": "^5.0.0",
109
109
  "is-error": "^2.2.2",
@@ -131,23 +131,22 @@
131
131
  "@ava/test": "github:avajs/test",
132
132
  "@ava/typescript": "^3.0.1",
133
133
  "@sindresorhus/tsconfig": "^3.0.1",
134
- "@sinonjs/fake-timers": "^10.0.0",
135
134
  "ansi-escapes": "^6.0.0",
136
135
  "c8": "^7.12.0",
137
136
  "delay": "^5.0.0",
138
137
  "execa": "^6.1.0",
139
- "fs-extra": "^10.1.0",
138
+ "fs-extra": "^11.1.0",
140
139
  "get-stream": "^6.0.1",
141
140
  "replace-string": "^4.0.0",
142
- "sinon": "^14.0.2",
143
- "tap": "^16.3.0",
141
+ "sinon": "^15.0.1",
142
+ "tap": "^16.3.3",
144
143
  "temp-write": "^5.0.0",
145
144
  "tempy": "^3.0.0",
146
145
  "touch": "^3.1.0",
147
- "tsd": "^0.24.1",
148
- "typescript": "^4.8.4",
149
- "xo": "^0.52.4",
150
- "zen-observable": "^0.9.0"
146
+ "tsd": "^0.25.0",
147
+ "typescript": "^4.9.4",
148
+ "xo": "^0.53.1",
149
+ "zen-observable": "^0.10.0"
151
150
  },
152
151
  "peerDependencies": {
153
152
  "@ava/typescript": "*"
@@ -158,7 +157,7 @@
158
157
  }
159
158
  },
160
159
  "volta": {
161
- "node": "18.8.0",
162
- "npm": "8.18.0"
160
+ "node": "18.13.0",
161
+ "npm": "9.3.0"
163
162
  }
164
163
  }