in packages/expect/src/index.ts [268:373]
function throwingMatcher(...args): any {
let throws = true;
const utils = {...matcherUtils, iterableEquality, subsetEquality};
const matcherContext: MatcherState = {
// When throws is disabled, the matcher will not throw errors during test
// execution but instead add them to the global matcher state. If a
// matcher throws, test execution is normally stopped immediately. The
// snapshot matcher uses it because we want to log all snapshot
// failures in a test.
dontThrow: () => (throws = false),
...getState(),
equals,
error: err,
isNot,
promise,
utils,
};
const processResult = (
result: SyncExpectationResult,
asyncError?: JestAssertionError,
) => {
_validateResult(result);
getState().assertionCalls++;
if ((result.pass && isNot) || (!result.pass && !isNot)) {
// XOR
const message = getMessage(result.message);
let error;
if (err) {
error = err;
error.message = message;
} else if (asyncError) {
error = asyncError;
error.message = message;
} else {
error = new JestAssertionError(message);
// Try to remove this function from the stack trace frame.
// Guard for some environments (browsers) that do not support this feature.
if (Error.captureStackTrace) {
Error.captureStackTrace(error, throwingMatcher);
}
}
// Passing the result of the matcher with the error so that a custom
// reporter could access the actual and expected objects of the result
// for example in order to display a custom visual diff
error.matcherResult = {...result, message};
if (throws) {
throw error;
} else {
getState().suppressedErrors.push(error);
}
}
};
const handleError = (error: Error) => {
if (
matcher[INTERNAL_MATCHER_FLAG] === true &&
!(error instanceof JestAssertionError) &&
error.name !== 'PrettyFormatPluginError' &&
// Guard for some environments (browsers) that do not support this feature.
Error.captureStackTrace
) {
// Try to remove this and deeper functions from the stack trace frame.
Error.captureStackTrace(error, throwingMatcher);
}
throw error;
};
let potentialResult: ExpectationResult;
try {
potentialResult =
matcher[INTERNAL_MATCHER_FLAG] === true
? matcher.call(matcherContext, actual, ...args)
: // It's a trap specifically for inline snapshot to capture this name
// in the stack trace, so that it can correctly get the custom matcher
// function call.
(function __EXTERNAL_MATCHER_TRAP__() {
return matcher.call(matcherContext, actual, ...args);
})();
if (isPromise(potentialResult)) {
const asyncResult = potentialResult as AsyncExpectationResult;
const asyncError = new JestAssertionError();
if (Error.captureStackTrace) {
Error.captureStackTrace(asyncError, throwingMatcher);
}
return asyncResult
.then(aResult => processResult(aResult, asyncError))
.catch(handleError);
} else {
const syncResult = potentialResult as SyncExpectationResult;
return processResult(syncResult);
}
} catch (error: any) {
return handleError(error);
}
};