github-pages-deploy-action/node_modules/jest-circus/build/utils.js
2020-01-27 23:58:23 -05:00

370 lines
9.5 KiB
JavaScript

'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.invariant = invariant;
exports.addErrorToEachTestUnderDescribe = exports.getTestID = exports.makeRunResult = exports.getTestDuration = exports.callAsyncCircusFn = exports.describeBlockHasTests = exports.getEachHooksForTest = exports.getAllHooksForDescribe = exports.makeTest = exports.makeDescribe = void 0;
var _jestUtil = require('jest-util');
var _isGeneratorFn = _interopRequireDefault(require('is-generator-fn'));
var _co = _interopRequireDefault(require('co'));
var _stackUtils = _interopRequireDefault(require('stack-utils'));
var _prettyFormat = _interopRequireDefault(require('pretty-format'));
var _state = require('./state');
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
var jestNow = global[Symbol.for('jest-native-now')] || global.Date.now;
var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
var Promise = global[Symbol.for('jest-native-promise')] || global.Promise;
const stackUtils = new _stackUtils.default({
cwd: 'A path that does not exist'
});
const makeDescribe = (name, parent, mode) => {
let _mode = mode;
if (parent && !mode) {
// If not set explicitly, inherit from the parent describe.
_mode = parent.mode;
}
return {
children: [],
hooks: [],
mode: _mode,
name: (0, _jestUtil.convertDescriptorToString)(name),
parent,
tests: []
};
};
exports.makeDescribe = makeDescribe;
const makeTest = (fn, mode, name, parent, timeout, asyncError) => ({
asyncError,
duration: null,
errors: [],
fn,
invocations: 0,
mode,
name: (0, _jestUtil.convertDescriptorToString)(name),
parent,
startedAt: null,
status: null,
timeout
}); // Traverse the tree of describe blocks and return true if at least one describe
// block has an enabled test.
exports.makeTest = makeTest;
const hasEnabledTest = describeBlock => {
const {hasFocusedTests, testNamePattern} = (0, _state.getState)();
const hasOwnEnabledTests = describeBlock.tests.some(
test =>
!(
test.mode === 'skip' ||
(hasFocusedTests && test.mode !== 'only') ||
(testNamePattern && !testNamePattern.test(getTestID(test)))
)
);
return hasOwnEnabledTests || describeBlock.children.some(hasEnabledTest);
};
const getAllHooksForDescribe = describe => {
const result = {
afterAll: [],
beforeAll: []
};
if (hasEnabledTest(describe)) {
for (const hook of describe.hooks) {
switch (hook.type) {
case 'beforeAll':
result.beforeAll.push(hook);
break;
case 'afterAll':
result.afterAll.push(hook);
break;
}
}
}
return result;
};
exports.getAllHooksForDescribe = getAllHooksForDescribe;
const getEachHooksForTest = test => {
const result = {
afterEach: [],
beforeEach: []
};
let block = test.parent;
do {
const beforeEachForCurrentBlock = []; // TODO: inline after https://github.com/microsoft/TypeScript/pull/34840 is released
let hook;
for (hook of block.hooks) {
switch (hook.type) {
case 'beforeEach':
beforeEachForCurrentBlock.push(hook);
break;
case 'afterEach':
result.afterEach.push(hook);
break;
}
} // 'beforeEach' hooks are executed from top to bottom, the opposite of the
// way we traversed it.
result.beforeEach = [...beforeEachForCurrentBlock, ...result.beforeEach];
} while ((block = block.parent));
return result;
};
exports.getEachHooksForTest = getEachHooksForTest;
const describeBlockHasTests = describe =>
describe.tests.length > 0 || describe.children.some(describeBlockHasTests);
exports.describeBlockHasTests = describeBlockHasTests;
const _makeTimeoutMessage = (timeout, isHook) =>
`Exceeded timeout of ${timeout}ms for a ${
isHook ? 'hook' : 'test'
}.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.`; // Global values can be overwritten by mocks or tests. We'll capture
// the original values in the variables before we require any files.
const {setTimeout, clearTimeout} = global;
function checkIsError(error) {
return !!(error && error.message && error.stack);
}
const callAsyncCircusFn = (fn, testContext, {isHook, timeout}) => {
let timeoutID;
let completed = false;
return new Promise((resolve, reject) => {
timeoutID = setTimeout(
() => reject(_makeTimeoutMessage(timeout, !!isHook)),
timeout
); // If this fn accepts `done` callback we return a promise that fulfills as
// soon as `done` called.
if (fn.length) {
const done = reason => {
const errorAsErrorObject = checkIsError(reason)
? reason
: new Error(
`Failed: ${(0, _prettyFormat.default)(reason, {
maxDepth: 3
})}`
); // Consider always throwing, regardless if `reason` is set or not
if (completed && reason) {
errorAsErrorObject.message =
'Caught error after test environment was torn down\n\n' +
errorAsErrorObject.message;
throw errorAsErrorObject;
}
return reason ? reject(errorAsErrorObject) : resolve();
};
return fn.call(testContext, done);
}
let returnedValue;
if ((0, _isGeneratorFn.default)(fn)) {
returnedValue = _co.default.wrap(fn).call({});
} else {
try {
returnedValue = fn.call(testContext);
} catch (error) {
return reject(error);
}
} // If it's a Promise, return it. Test for an object with a `then` function
// to support custom Promise implementations.
if (
typeof returnedValue === 'object' &&
returnedValue !== null &&
typeof returnedValue.then === 'function'
) {
return returnedValue.then(resolve, reject);
}
if (!isHook && returnedValue !== void 0) {
return reject(
new Error(`
test functions can only return Promise or undefined.
Returned value: ${String(returnedValue)}
`)
);
} // Otherwise this test is synchronous, and if it didn't throw it means
// it passed.
return resolve();
})
.then(() => {
completed = true; // If timeout is not cleared/unrefed the node process won't exit until
// it's resolved.
timeoutID.unref && timeoutID.unref();
clearTimeout(timeoutID);
})
.catch(error => {
completed = true;
timeoutID.unref && timeoutID.unref();
clearTimeout(timeoutID);
throw error;
});
};
exports.callAsyncCircusFn = callAsyncCircusFn;
const getTestDuration = test => {
const {startedAt} = test;
return typeof startedAt === 'number' ? jestNow() - startedAt : null;
};
exports.getTestDuration = getTestDuration;
const makeRunResult = (describeBlock, unhandledErrors) => ({
testResults: makeTestResults(describeBlock),
unhandledErrors: unhandledErrors.map(_formatError)
});
exports.makeRunResult = makeRunResult;
const makeTestResults = describeBlock => {
const {includeTestLocationInResult} = (0, _state.getState)();
let testResults = [];
for (const test of describeBlock.tests) {
const testPath = [];
let parent = test;
do {
testPath.unshift(parent.name);
} while ((parent = parent.parent));
const {status} = test;
if (!status) {
throw new Error('Status should be present after tests are run.');
}
let location = null;
if (includeTestLocationInResult) {
const stackLine = test.asyncError.stack.split('\n')[1];
const parsedLine = stackUtils.parseLine(stackLine);
if (
parsedLine &&
typeof parsedLine.column === 'number' &&
typeof parsedLine.line === 'number'
) {
location = {
column: parsedLine.column,
line: parsedLine.line
};
}
}
testResults.push({
duration: test.duration,
errors: test.errors.map(_formatError),
invocations: test.invocations,
location,
status,
testPath
});
}
for (const child of describeBlock.children) {
testResults = testResults.concat(makeTestResults(child));
}
return testResults;
}; // Return a string that identifies the test (concat of parent describe block
// names + test title)
const getTestID = test => {
const titles = [];
let parent = test;
do {
titles.unshift(parent.name);
} while ((parent = parent.parent));
titles.shift(); // remove TOP_DESCRIBE_BLOCK_NAME
return titles.join(' ');
};
exports.getTestID = getTestID;
const _formatError = errors => {
let error;
let asyncError;
if (Array.isArray(errors)) {
error = errors[0];
asyncError = errors[1];
} else {
error = errors;
asyncError = new Error();
}
if (error) {
if (error.stack) {
return error.stack;
}
if (error.message) {
return error.message;
}
}
asyncError.message = `thrown: ${(0, _prettyFormat.default)(error, {
maxDepth: 3
})}`;
return asyncError.stack;
};
const addErrorToEachTestUnderDescribe = (describeBlock, error, asyncError) => {
for (const test of describeBlock.tests) {
test.errors.push([error, asyncError]);
}
for (const child of describeBlock.children) {
addErrorToEachTestUnderDescribe(child, error, asyncError);
}
};
exports.addErrorToEachTestUnderDescribe = addErrorToEachTestUnderDescribe;
function invariant(condition, message) {
if (!condition) {
throw new Error(message);
}
}