uvu-jest
Version:
Run the existing jest code with uvu
375 lines (374 loc) • 15.7 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.exec = exports.test = exports.suite = exports.Test = void 0;
process.env.NODE_ENV = 'test';
const kleur_1 = __importDefault(require("kleur"));
const diff_1 = require("../diff");
let isCLI = false, isNode = false;
let hrtime = (now = Date.now()) => () => (Date.now() - now).toFixed(2) + 'ms';
let write = console.log;
class Test {
constructor(name, handler) {
this.name = name;
this.handler = handler;
}
}
exports.Test = Test;
const into = (ctx, key) => (name, handler) => { ctx[key].push(new Test(name, handler)); };
const intoSuite = (ctx, key) => (suite) => { ctx[key].push(suite); };
const context = (state) => ({
tests: [],
before: [],
after: [],
bEach: [],
aEach: [],
only: [],
skips: 0,
state,
filename: 'not set'
});
const milli = (arr) => (arr[0] * 1e3 + arr[1] / 1e6).toFixed(2) + 'ms';
const hook = (ctx, key) => (handler) => { ctx[key].push(handler); };
if (isNode = typeof process < 'u' && typeof process.stdout < 'u') {
// globalThis polyfill; Node < 12
if (typeof globalThis !== 'object') {
Object.defineProperty(global, 'globalThis', {
get: function () { return this; }
});
}
/**
* bin.js
* .bin/ts-uvu
* @type {RegExp}
*/
let rgx = /(ts-bin\.ts|bin\.js|\.bin[\\+\/]uj|uvu-jest[\\+\/]bin\.js)/i;
isCLI = process.argv.some(x => rgx.test(x));
// attach node-specific utils
write = x => process.stdout.write(x);
// @ts-ignore
hrtime = (now = process.hrtime()) => () => milli(process.hrtime(now));
}
else if (typeof performance < 'u') {
hrtime = (now = performance.now()) => () => (performance.now() - now).toFixed(2) + 'ms';
}
globalThis.UVU_QUEUE = globalThis.UVU_QUEUE || [];
isCLI || globalThis.UVU_QUEUE.push([null]);
const QUOTE = kleur_1.default.dim('"'), GUTTER = '\n ';
const IGNORE = /^\s*at.*(?:\(|\s)(?:node|(internal\/[\w/]*))/;
const FAILURE = kleur_1.default.bold().bgRed(' FAIL ');
const SUCCESS = kleur_1.default.bold().bgGreen(' SUCCESS ');
const FILE = kleur_1.default.bold().underline().white;
const SUITE = kleur_1.default.bgWhite().bold;
const TestResultIcon = (result) => result ? '✔' : '✘';
function stack(stack, idx) {
let i = 0, line, out = '';
let arr = stack.substring(idx).replace(/\\/g, '/').split('\n');
for (; i < arr.length; i++) {
line = arr[i].trim();
if (line.length && !IGNORE.test(line)) {
out += '\n ' + line;
}
}
return kleur_1.default.grey(out) + '\n';
}
const isAssertion = (err) => {
return err.name.startsWith('AssertionError');
};
function format(name, err, suite = '') {
let { details, operator = '' } = err;
let idx = err.stack && err.stack.indexOf('\n').toString();
if (isAssertion(err) && !operator.includes('not')) {
// @ts-ignore
details = (0, diff_1.compare)(err.actual, err.expected);
} // TODO?
let str = ' ' + FAILURE + (suite ? kleur_1.default.red(SUITE(` ${suite} `)) : '') + ' ' + QUOTE + kleur_1.default.red().bold(name) + QUOTE;
str += '\n ' + err.message + (operator ? kleur_1.default.italic().dim(` (${operator})`) : '') + '\n';
if (details)
str += GUTTER + details.split('\n').join(GUTTER);
// @ts-ignore
if (!!~idx)
str += stack(err.stack, idx);
return str + '\n';
}
const executeWithErrorReporting = (fn, where) => __awaiter(void 0, void 0, void 0, function* () {
try {
return yield fn();
}
catch (err) {
const { filename, nameStack } = where || { filename: '', nameStack: [] };
if (filename)
console.log(FILE(filename));
const whereString = nameStack ? FAILURE + SUITE(` ${nameStack.join(' > ')} `) : undefined;
console.error(...[whereString, err].filter(Boolean));
}
});
function runner(ctx, thisSuiteName, filename, suiteNameStack) {
return __awaiter(this, void 0, void 0, function* () {
let { only, tests, before, after, bEach, aEach, state } = ctx;
let arr = only.length ? only : tests;
const res = {
errorMessages: true,
count: {
test: {
passed: 0,
skipped: (only.length ? tests.length : 0) + ctx.skips,
errored: 0
},
suite: { passed: 0, errored: 0 }
},
};
// let passed=0, errors='', errorCounts=0,
let errorCountOfThis = 0;
const testResults = [];
const childSuiteResults = [];
try {
for (const hook of before) {
yield executeWithErrorReporting(hook.bind(0, state), {
filename,
nameStack: [thisSuiteName, ...suiteNameStack || [], 'before'],
});
}
for (const test of arr) {
if (!(test instanceof Test)) {
const suite = test;
// nested suite
const result = yield suite.runSync(filename, [...suiteNameStack || [], thisSuiteName]);
if (result.errorMessages !== true) {
if (res.errorMessages === true)
res.errorMessages = '';
res.errorMessages += result.errorMessages;
}
res.count.test.passed += result.count.test.passed;
res.count.test.skipped += result.count.test.skipped;
res.count.test.errored += result.count.test.errored;
res.count.suite.passed += result.count.suite.passed;
res.count.suite.errored += result.count.suite.errored;
childSuiteResults.push(result.result);
}
else {
// test
state.__test__ = test.name;
globalThis.CURRENT_TEST_NAME = test.name;
globalThis.CURRENT_SUITE_NAMES = [...suiteNameStack || [], thisSuiteName];
try {
for (const beHook of bEach) {
yield executeWithErrorReporting(beHook.bind(0, state), {
filename,
nameStack: [thisSuiteName, ...suiteNameStack || [], 'beforeEach'],
});
}
yield test.handler(state);
for (const aeHook of aEach) {
yield executeWithErrorReporting(aeHook.bind(0, state), {
filename,
nameStack: [thisSuiteName, ...suiteNameStack || [], 'afterEach'],
});
}
res.count.test.passed++;
testResults.push({
name: test.name,
result: true,
});
}
catch (err) {
for (const aeHook of aEach) {
yield executeWithErrorReporting(aeHook.bind(0, state), {
filename,
nameStack: [thisSuiteName, ...suiteNameStack || [], 'afterEach'],
});
}
if (typeof res.errorMessages === 'string' && res.errorMessages.length)
res.errorMessages += '\n';
const errorMessage = format(test.name, err, thisSuiteName);
res.errorMessages += errorMessage;
res.count.test.errored++;
errorCountOfThis++;
testResults.push({
name: test.name,
result: false,
errorMessage,
});
}
}
}
}
finally {
state.__test__ = '';
for (const afterHook of after) {
yield executeWithErrorReporting(afterHook.bind(0, state), {
filename,
nameStack: [thisSuiteName, ...suiteNameStack || [], 'after'],
});
}
if (errorCountOfThis) {
res.count.suite.errored++;
}
else {
res.count.suite.passed++;
}
return Object.assign(Object.assign({}, res), { result: {
filename,
suiteName: ctx.state.__suite__ || 'unknown',
testResults,
suiteResult: res.count.test.errored === 0,
thisSuiteResult: errorCountOfThis === 0,
childResults: childSuiteResults,
} });
}
});
}
let timer;
function defer() {
clearTimeout(timer);
timer = setTimeout(exec);
}
function suiteFactory(ctx, name = '') {
ctx.state.__test__ = '';
ctx.state.__suite__ = name;
const props = {
before: Object.assign(hook(ctx, 'before'), {
each: hook(ctx, 'bEach'),
}),
after: Object.assign(hook(ctx, 'after'), {
each: hook(ctx, 'aEach'),
}),
only: into(ctx, 'only'),
nest: intoSuite(ctx, 'tests'),
skip: () => { ctx.skips++; },
runSync: (filename, suiteNames) => {
const copy = Object.assign({}, ctx);
Object.assign(ctx, context(copy.state));
return runner.bind(0)(copy, name, filename, suiteNames);
},
run: () => {
const copy = Object.assign({}, ctx);
Object.assign(ctx, context(copy.state));
globalThis.UVU_QUEUE[globalThis.UVU_INDEX || 0].push(runner.bind(0, copy, name));
isCLI || defer();
}
};
return Object.assign(into(ctx, 'tests'), props);
}
const suite = (name = '', state = {}) => suiteFactory(context(state), name);
exports.suite = suite;
exports.test = (0, exports.suite)();
const reportResults = (result, depth = 1) => {
const { filename, suiteName, thisSuiteResult, testResults, childResults } = result;
if (depth === 1 && filename) {
console.group('👾 Each Suite Result: ');
console.log(FILE(filename));
}
console.group(SUITE(` ${suiteName} `));
testResults.forEach(({ name, result }) => {
console.log((result ? kleur_1.default.green : kleur_1.default.red)(`${TestResultIcon(result)} ${name}`));
});
if (childResults) {
childResults.forEach(cr => reportResults(cr, depth + 1));
}
console.groupEnd();
if (depth === 1) {
console.groupEnd();
}
};
const results = [];
const reportErrorSuites = (_result = results, resultStack = []) => {
if (Array.isArray(_result)) {
results.forEach(r => reportErrorSuites(r, resultStack));
return;
}
if (!_result.thisSuiteResult) {
if (_result.filename) {
console.group(FILE(_result.filename));
}
// report
const message = [
...resultStack
.map(r => (r.thisSuiteResult ? '' : FAILURE) + (SUITE(r.suiteName))),
FAILURE + SUITE(_result.suiteName)
].join(' > ');
console.group(message);
_result.testResults.forEach(({ name, result }) => {
console.log((result ? kleur_1.default.green : kleur_1.default.red)(`${TestResultIcon(result)} ${name}`));
});
console.groupEnd();
if (_result.filename) {
console.groupEnd();
}
}
if (_result.childResults) {
_result.childResults.forEach(r => reportErrorSuites(r, [...resultStack, _result]));
}
};
function exec(bail) {
return __awaiter(this, void 0, void 0, function* () {
let timer = hrtime();
let exitCode = 0;
const counts = {
tests: { total: 0, passed: 0, skipped: 0, errored: 0, },
suite: { passed: 0, errored: 0, }
};
const files = globalThis.UVU_QUEUE.length;
for (let group of globalThis.UVU_QUEUE) {
console.log();
const [name, ...testRunners] = group;
if (name === null || name === void 0 ? void 0 : name.file) {
globalThis.CURRENT_FILE_PATH = name.file;
}
for (let _runner of testRunners) {
let result = yield _runner((name === null || name === void 0 ? void 0 : name.name) || undefined);
counts.tests.skipped += result.count.test.skipped;
counts.suite.passed += result.count.suite.passed;
counts.suite.errored += result.count.suite.errored;
counts.tests.passed += result.count.test.passed;
counts.tests.errored += result.count.test.errored;
counts.tests.total += result.count.test.passed + result.count.test.errored;
results.push(result.result);
reportResults(result.result);
if (result.errorMessages.toString() !== 'true' && result.errorMessages) {
write('\n' + result.errorMessages + '\n');
exitCode = 1;
if (bail)
return isNode && process.exit(1);
}
}
}
console.log();
console.group(`💎 ${counts.tests.errored ? FAILURE : SUCCESS} Total results by here`);
console.group(kleur_1.default.bold().underline().blue('Total:'));
console.log(`Files: ${files}`);
console.log(`Suites: ${counts.suite.passed + counts.suite.errored}`);
console.log(`Tests: ${counts.tests.passed + counts.tests.errored}`);
console.groupEnd();
if (counts.tests.errored > 0) {
console.group(kleur_1.default.bold().underline().red('Errors:'));
console.log(kleur_1.default.red('Errored Suites: ' + counts.suite.errored));
console.log(kleur_1.default.red('Errored Tests: ' + counts.tests.errored));
console.groupEnd();
}
console.group(kleur_1.default.bold().underline().blue('Details:'));
console.log('Skipped: ' + (counts.tests.skipped ? kleur_1.default.yellow(counts.tests.skipped) : counts.tests.skipped));
console.log('Duration: ' + timer() + '\n\n');
console.groupEnd();
console.groupEnd();
if (counts.suite.errored > 0) {
console.group('💥 Errored Tests');
reportErrorSuites();
console.groupEnd();
}
if (isNode)
process.exitCode = exitCode;
});
}
exports.exec = exec;
;