replace jest with ava
This commit is contained in:
parent
27cc8b23fe
commit
0347b72305
11775 changed files with 84546 additions and 1440575 deletions
47
node_modules/ava/lib/worker/dependency-tracker.js
generated
vendored
Normal file
47
node_modules/ava/lib/worker/dependency-tracker.js
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* eslint-disable node/no-deprecated-api */
|
||||
'use strict';
|
||||
const ipc = require('./ipc');
|
||||
|
||||
const seenDependencies = new Set();
|
||||
let newDependencies = [];
|
||||
function flush() {
|
||||
if (newDependencies.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipc.send({type: 'dependencies', dependencies: newDependencies});
|
||||
newDependencies = [];
|
||||
}
|
||||
|
||||
exports.flush = flush;
|
||||
|
||||
function track(filename) {
|
||||
if (seenDependencies.has(filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newDependencies.length === 0) {
|
||||
process.nextTick(flush);
|
||||
}
|
||||
|
||||
seenDependencies.add(filename);
|
||||
newDependencies.push(filename);
|
||||
}
|
||||
|
||||
exports.track = track;
|
||||
|
||||
function install(testPath) {
|
||||
for (const ext of Object.keys(require.extensions)) {
|
||||
const wrappedHandler = require.extensions[ext];
|
||||
|
||||
require.extensions[ext] = (module, filename) => {
|
||||
if (filename !== testPath) {
|
||||
track(filename);
|
||||
}
|
||||
|
||||
wrappedHandler(module, filename);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
exports.install = install;
|
||||
18
node_modules/ava/lib/worker/ensure-forked.js
generated
vendored
Normal file
18
node_modules/ava/lib/worker/ensure-forked.js
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
'use strict';
|
||||
const path = require('path');
|
||||
const chalk = require('chalk'); // Use default Chalk instance.
|
||||
|
||||
// Check if the test is being run without AVA cli
|
||||
const isForked = typeof process.send === 'function';
|
||||
if (!isForked) {
|
||||
if (process.argv[1]) {
|
||||
const fp = path.relative('.', process.argv[1]);
|
||||
|
||||
console.log();
|
||||
console.error(`Test files must be run with the AVA CLI:\n\n ${chalk.grey.dim('$')} ${chalk.cyan('ava ' + fp)}\n`);
|
||||
|
||||
process.exit(1); // eslint-disable-line unicorn/no-process-exit
|
||||
} else {
|
||||
throw new Error('The ’ava’ module can only be imported in test files');
|
||||
}
|
||||
}
|
||||
56
node_modules/ava/lib/worker/ipc.js
generated
vendored
Normal file
56
node_modules/ava/lib/worker/ipc.js
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
const Emittery = require('emittery');
|
||||
|
||||
const emitter = new Emittery();
|
||||
process.on('message', message => {
|
||||
if (!message.ava) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.ava.type) {
|
||||
case 'options':
|
||||
emitter.emit('options', message.ava.options);
|
||||
break;
|
||||
case 'peer-failed':
|
||||
emitter.emit('peerFailed');
|
||||
break;
|
||||
case 'pong':
|
||||
emitter.emit('pong');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
exports.options = emitter.once('options');
|
||||
exports.peerFailed = emitter.once('peerFailed');
|
||||
|
||||
function send(evt) {
|
||||
if (process.connected) {
|
||||
process.send({ava: evt});
|
||||
}
|
||||
}
|
||||
|
||||
exports.send = send;
|
||||
|
||||
function unref() {
|
||||
process.channel.unref();
|
||||
}
|
||||
|
||||
exports.unref = unref;
|
||||
|
||||
let pendingPings = Promise.resolve();
|
||||
async function flush() {
|
||||
process.channel.ref();
|
||||
const promise = pendingPings.then(async () => { // eslint-disable-line promise/prefer-await-to-then
|
||||
send({type: 'ping'});
|
||||
await emitter.once('pong');
|
||||
if (promise === pendingPings) {
|
||||
unref();
|
||||
}
|
||||
});
|
||||
pendingPings = promise;
|
||||
await promise;
|
||||
}
|
||||
|
||||
exports.flush = flush;
|
||||
90
node_modules/ava/lib/worker/line-numbers.js
generated
vendored
Normal file
90
node_modules/ava/lib/worker/line-numbers.js
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
function parse(file) {
|
||||
const fs = require('fs');
|
||||
const acorn = require('acorn');
|
||||
const walk = require('acorn-walk');
|
||||
|
||||
const ast = acorn.parse(fs.readFileSync(file, 'utf8'), {
|
||||
ecmaVersion: 11,
|
||||
locations: true
|
||||
});
|
||||
|
||||
const locations = [];
|
||||
walk.simple(ast, {
|
||||
CallExpression(node) {
|
||||
locations.push(node.loc);
|
||||
}
|
||||
});
|
||||
|
||||
// Walking is depth-first, but we want to sort these breadth-first.
|
||||
locations.sort((a, b) => {
|
||||
if (a.start.line === b.start.line) {
|
||||
return a.start.column - b.start.column;
|
||||
}
|
||||
|
||||
return a.start.line - b.start.line;
|
||||
});
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
function findTest(locations, declaration) {
|
||||
// Find all calls that span the test declaration.
|
||||
const spans = locations.filter(loc => {
|
||||
if (loc.start.line > declaration.line || loc.end.line < declaration.line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loc.start.line === declaration.line && loc.start.column > declaration.column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loc.end.line === declaration.line && loc.end.column < declaration.column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Locations should be sorted by source order, so the last span must be the test.
|
||||
return spans.pop();
|
||||
}
|
||||
|
||||
const range = (start, end) => new Array(end - start + 1).fill(start).map((element, index) => element + index);
|
||||
|
||||
module.exports = ({file, lineNumbers = []}) => {
|
||||
if (lineNumbers.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Avoid loading these until we actually need to select tests by line number.
|
||||
const callsites = require('callsites');
|
||||
const sourceMapSupport = require('source-map-support');
|
||||
|
||||
const locations = parse(file);
|
||||
const selected = new Set(lineNumbers);
|
||||
|
||||
return () => {
|
||||
// Assume this is called from a test declaration, which is located in the file.
|
||||
// If not… don't select the test!
|
||||
const callSite = callsites().find(callSite => callSite.getFileName() === file);
|
||||
if (!callSite) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: This assumes the callSite hasn't already been adjusted. It's likely
|
||||
// that if `source-map-support/register` has been loaded, this would result
|
||||
// in the wrong location.
|
||||
const sourceCallSite = sourceMapSupport.wrapCallSite(callSite);
|
||||
const start = {
|
||||
line: sourceCallSite.getLineNumber(),
|
||||
column: sourceCallSite.getColumnNumber() - 1 // Use 0-indexed columns.
|
||||
};
|
||||
|
||||
const test = findTest(locations, start);
|
||||
if (!test) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return range(test.start.line, test.end.line).some(line => selected.has(line));
|
||||
};
|
||||
};
|
||||
21
node_modules/ava/lib/worker/main.js
generated
vendored
Normal file
21
node_modules/ava/lib/worker/main.js
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
const runner = require('./subprocess').getRunner();
|
||||
|
||||
const makeCjsExport = () => {
|
||||
function test(...args) {
|
||||
return runner.chain(...args);
|
||||
}
|
||||
|
||||
return Object.assign(test, runner.chain);
|
||||
};
|
||||
|
||||
// Support CommonJS modules by exporting a test function that can be fully
|
||||
// chained. Also support ES module loaders by exporting __esModule and a
|
||||
// default. Support `import * as ava from 'ava'` use cases by exporting a
|
||||
// `test` member. Do all this whilst preventing `test.test.test() or
|
||||
// `test.default.test()` chains, though in CommonJS `test.test()` is
|
||||
// unavoidable.
|
||||
module.exports = Object.assign(makeCjsExport(), {
|
||||
__esModule: true,
|
||||
default: runner.chain
|
||||
});
|
||||
17
node_modules/ava/lib/worker/options.js
generated
vendored
Normal file
17
node_modules/ava/lib/worker/options.js
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
let options = null;
|
||||
exports.get = () => {
|
||||
if (!options) {
|
||||
throw new Error('Options have not yet been set');
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
exports.set = newOptions => {
|
||||
if (options) {
|
||||
throw new Error('Options have already been set');
|
||||
}
|
||||
|
||||
options = newOptions;
|
||||
};
|
||||
235
node_modules/ava/lib/worker/subprocess.js
generated
vendored
Normal file
235
node_modules/ava/lib/worker/subprocess.js
generated
vendored
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
'use strict';
|
||||
const {pathToFileURL} = require('url');
|
||||
const currentlyUnhandled = require('currently-unhandled')();
|
||||
|
||||
require('./ensure-forked'); // eslint-disable-line import/no-unassigned-import
|
||||
|
||||
const ipc = require('./ipc');
|
||||
|
||||
const supportsESM = async () => {
|
||||
try {
|
||||
await import('data:text/javascript,'); // eslint-disable-line node/no-unsupported-features/es-syntax
|
||||
return true;
|
||||
} catch {}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
ipc.send({type: 'ready-for-options'});
|
||||
ipc.options.then(async options => {
|
||||
require('./options').set(options);
|
||||
require('../chalk').set(options.chalkOptions);
|
||||
|
||||
if (options.chalkOptions.level > 0) {
|
||||
const {stdout, stderr} = process;
|
||||
global.console = Object.assign(global.console, new console.Console({stdout, stderr, colorMode: true}));
|
||||
}
|
||||
|
||||
const nowAndTimers = require('../now-and-timers');
|
||||
const providerManager = require('../provider-manager');
|
||||
const Runner = require('../runner');
|
||||
const serializeError = require('../serialize-error');
|
||||
const dependencyTracking = require('./dependency-tracker');
|
||||
const lineNumberSelection = require('./line-numbers');
|
||||
|
||||
async function exit(code) {
|
||||
if (!process.exitCode) {
|
||||
process.exitCode = code;
|
||||
}
|
||||
|
||||
dependencyTracking.flush();
|
||||
await ipc.flush();
|
||||
process.exit(); // eslint-disable-line unicorn/no-process-exit
|
||||
}
|
||||
|
||||
// TODO: Initialize providers here, then pass to lineNumberSelection() so they
|
||||
// can be used to parse the test file.
|
||||
let checkSelectedByLineNumbers;
|
||||
try {
|
||||
checkSelectedByLineNumbers = lineNumberSelection({
|
||||
file: options.file,
|
||||
lineNumbers: options.lineNumbers
|
||||
});
|
||||
} catch (error) {
|
||||
ipc.send({type: 'line-number-selection-error', err: serializeError('Line number selection error', false, error, options.file)});
|
||||
checkSelectedByLineNumbers = () => false;
|
||||
}
|
||||
|
||||
const runner = new Runner({
|
||||
checkSelectedByLineNumbers,
|
||||
experiments: options.experiments,
|
||||
failFast: options.failFast,
|
||||
failWithoutAssertions: options.failWithoutAssertions,
|
||||
file: options.file,
|
||||
match: options.match,
|
||||
projectDir: options.projectDir,
|
||||
recordNewSnapshots: options.recordNewSnapshots,
|
||||
runOnlyExclusive: options.runOnlyExclusive,
|
||||
serial: options.serial,
|
||||
snapshotDir: options.snapshotDir,
|
||||
updateSnapshots: options.updateSnapshots
|
||||
});
|
||||
|
||||
ipc.peerFailed.then(() => { // eslint-disable-line promise/prefer-await-to-then
|
||||
runner.interrupt();
|
||||
});
|
||||
|
||||
const attributedRejections = new Set();
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
if (runner.attributeLeakedError(reason)) {
|
||||
attributedRejections.add(promise);
|
||||
}
|
||||
});
|
||||
|
||||
runner.on('dependency', dependencyTracking.track);
|
||||
runner.on('stateChange', state => ipc.send(state));
|
||||
|
||||
runner.on('error', error => {
|
||||
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, error, runner.file)});
|
||||
exit(1);
|
||||
});
|
||||
|
||||
runner.on('finish', () => {
|
||||
try {
|
||||
const touchedFiles = runner.saveSnapshotState();
|
||||
if (touchedFiles) {
|
||||
ipc.send({type: 'touched-files', files: touchedFiles});
|
||||
}
|
||||
} catch (error) {
|
||||
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, error, runner.file)});
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
nowAndTimers.setImmediate(() => {
|
||||
currentlyUnhandled()
|
||||
.filter(rejection => !attributedRejections.has(rejection.promise))
|
||||
.forEach(rejection => {
|
||||
ipc.send({type: 'unhandled-rejection', err: serializeError('Unhandled rejection', true, rejection.reason, runner.file)});
|
||||
});
|
||||
|
||||
exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
process.on('uncaughtException', error => {
|
||||
if (runner.attributeLeakedError(error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipc.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, error, runner.file)});
|
||||
exit(1);
|
||||
});
|
||||
|
||||
let accessedRunner = false;
|
||||
exports.getRunner = () => {
|
||||
accessedRunner = true;
|
||||
return runner;
|
||||
};
|
||||
|
||||
// Store value to prevent required modules from modifying it.
|
||||
const testPath = options.file;
|
||||
|
||||
// Install basic source map support.
|
||||
const sourceMapSupport = require('source-map-support');
|
||||
sourceMapSupport.install({
|
||||
environment: 'node',
|
||||
handleUncaughtExceptions: false
|
||||
});
|
||||
|
||||
const extensionsToLoadAsModules = Object.entries(options.moduleTypes)
|
||||
.filter(([, type]) => type === 'module')
|
||||
.map(([extension]) => extension);
|
||||
|
||||
// Install before processing options.require, so if helpers are added to the
|
||||
// require configuration the *compiled* helper will be loaded.
|
||||
const {projectDir, providerStates = []} = options;
|
||||
const providers = providerStates.map(({type, state}) => {
|
||||
if (type === 'babel') {
|
||||
const provider = providerManager.babel(projectDir).worker({extensionsToLoadAsModules, state});
|
||||
runner.powerAssert = provider.powerAssert;
|
||||
return provider;
|
||||
}
|
||||
|
||||
if (type === 'typescript') {
|
||||
return providerManager.typescript(projectDir).worker({extensionsToLoadAsModules, state});
|
||||
}
|
||||
|
||||
return null;
|
||||
}).filter(provider => provider !== null);
|
||||
|
||||
let requireFn = require;
|
||||
let isESMSupported;
|
||||
const load = async ref => {
|
||||
for (const extension of extensionsToLoadAsModules) {
|
||||
if (ref.endsWith(`.${extension}`)) {
|
||||
if (typeof isESMSupported !== 'boolean') {
|
||||
// Lazily determine support since this prints an experimental warning.
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
isESMSupported = await supportsESM();
|
||||
}
|
||||
|
||||
if (isESMSupported) {
|
||||
return import(pathToFileURL(ref)); // eslint-disable-line node/no-unsupported-features/es-syntax
|
||||
}
|
||||
|
||||
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, new Error('ECMAScript Modules are not supported in this Node.js version.'))});
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const provider of providers) {
|
||||
if (provider.canLoad(ref)) {
|
||||
return provider.load(ref, {requireFn});
|
||||
}
|
||||
}
|
||||
|
||||
return requireFn(ref);
|
||||
};
|
||||
|
||||
try {
|
||||
for await (const ref of (options.require || [])) {
|
||||
const mod = await load(ref);
|
||||
|
||||
try {
|
||||
if (Reflect.has(mod, Symbol.for('esm:package'))) {
|
||||
requireFn = mod(module);
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// Install dependency tracker after the require configuration has been evaluated
|
||||
// to make sure we also track dependencies with custom require hooks
|
||||
dependencyTracking.install(testPath);
|
||||
|
||||
if (options.debug) {
|
||||
require('inspector').open(options.debug.port, options.debug.host, true); // eslint-disable-line node/no-unsupported-features/node-builtins
|
||||
if (options.debug.break) {
|
||||
debugger; // eslint-disable-line no-debugger
|
||||
}
|
||||
}
|
||||
|
||||
await load(testPath);
|
||||
|
||||
if (accessedRunner) {
|
||||
// Unreference the IPC channel if the test file required AVA. This stops it
|
||||
// from keeping the event loop busy, which means the `beforeExit` event can be
|
||||
// used to detect when tests stall.
|
||||
ipc.unref();
|
||||
} else {
|
||||
ipc.send({type: 'missing-ava-import'});
|
||||
exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
ipc.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, error, runner.file)});
|
||||
exit(1);
|
||||
}
|
||||
}).catch(error => {
|
||||
// There shouldn't be any errors, but if there are we may not have managed
|
||||
// to bootstrap enough code to serialize them. Re-throw and let the process
|
||||
// crash.
|
||||
setImmediate(() => {
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue