wallet-core/node_modules/ava/lib/test-worker.js
2017-12-27 19:34:16 +01:00

142 lines
3.5 KiB
JavaScript

'use strict';
// Check if the test is being run without AVA cli
{
const path = require('path');
const chalk = require('chalk');
const isForked = typeof process.send === 'function';
if (!isForked) {
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
}
}
const currentlyUnhandled = require('currently-unhandled')();
const isObj = require('is-obj');
const adapter = require('./process-adapter');
const globals = require('./globals');
const opts = adapter.opts;
globals.options = opts;
const serializeError = require('./serialize-error');
(opts.require || []).forEach(x => require(x));
adapter.installSourceMapSupport();
adapter.installPrecompilerHook();
const testPath = opts.file;
const dependencies = new Set();
adapter.installDependencyTracking(dependencies, testPath);
const touchedFiles = new Set();
// Set when main.js is required (since test files should have `require('ava')`).
let runner = null;
exports.setRunner = newRunner => {
runner = newRunner;
runner.on('dependency', file => {
dependencies.add(file);
});
runner.on('touched', files => {
for (const file of files) {
touchedFiles.add(file);
}
});
};
require(testPath);
// If AVA was not required, show an error
if (!runner) {
adapter.send('no-tests', {avaRequired: false});
}
function attributeLeakedError(err) {
if (!runner) {
return false;
}
return runner.attributeLeakedError(err);
}
const attributedRejections = new Set();
process.on('unhandledRejection', (reason, promise) => {
if (attributeLeakedError(reason)) {
attributedRejections.add(promise);
}
});
process.on('uncaughtException', exception => {
if (attributeLeakedError(exception)) {
return;
}
let serialized;
try {
serialized = serializeError(exception);
} catch (ignore) { // eslint-disable-line unicorn/catch-error-name
// Avoid using serializeError
const err = new Error('Failed to serialize uncaught exception');
serialized = {
avaAssertionError: false,
name: err.name,
message: err.message,
stack: err.stack
};
}
// Ensure the IPC channel is refereced. The uncaught exception will kick off
// the teardown sequence, for which the messages must be received.
adapter.ipcChannel.ref();
adapter.send('uncaughtException', {exception: serialized});
});
let tearingDown = false;
process.on('ava-teardown', () => {
// AVA-teardown can be sent more than once
if (tearingDown) {
return;
}
tearingDown = true;
let rejections = currentlyUnhandled()
.filter(rejection => !attributedRejections.has(rejection.promise));
if (rejections.length > 0) {
rejections = rejections.map(rejection => {
let reason = rejection.reason;
if (!isObj(reason) || typeof reason.message !== 'string') {
reason = {
message: String(reason)
};
}
return serializeError(reason);
});
adapter.send('unhandledRejections', {rejections});
}
// Include dependencies in the final teardown message. This ensures the full
// set of dependencies is included no matter how the process exits, unless
// it flat out crashes. Also include any files that AVA touched during the
// test run. This allows the watcher to ignore modifications to those files.
adapter.send('teardown', {
dependencies: Array.from(dependencies),
touchedFiles: Array.from(touchedFiles)
});
});
process.on('ava-exit', () => {
process.exit(0); // eslint-disable-line xo/no-process-exit
});