mirror of https://github.com/facebook/jest.git
154 lines
4.3 KiB
TypeScript
154 lines
4.3 KiB
TypeScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import chalk from 'chalk';
|
|
import {
|
|
type DiffOptions,
|
|
diff,
|
|
printExpected,
|
|
printReceived,
|
|
} from 'jest-matcher-utils';
|
|
import type {AssertionErrorWithStack} from './types';
|
|
|
|
const assertOperatorsMap: Record<string, string> = {
|
|
'!=': 'notEqual',
|
|
'!==': 'notStrictEqual',
|
|
'==': 'equal',
|
|
'===': 'strictEqual',
|
|
};
|
|
|
|
const humanReadableOperators: Record<string, string> = {
|
|
deepEqual: 'to deeply equal',
|
|
deepStrictEqual: 'to deeply and strictly equal',
|
|
equal: 'to be equal',
|
|
notDeepEqual: 'not to deeply equal',
|
|
notDeepStrictEqual: 'not to deeply and strictly equal',
|
|
notEqual: 'to not be equal',
|
|
notStrictEqual: 'not be strictly equal',
|
|
strictEqual: 'to strictly be equal',
|
|
};
|
|
|
|
const getOperatorName = (operator: string | null, stack: string) => {
|
|
if (typeof operator === 'string') {
|
|
return assertOperatorsMap[operator] || operator;
|
|
}
|
|
if (stack.match('.doesNotThrow')) {
|
|
return 'doesNotThrow';
|
|
}
|
|
if (stack.match('.throws')) {
|
|
return 'throws';
|
|
}
|
|
return '';
|
|
};
|
|
|
|
const operatorMessage = (operator: string | null) => {
|
|
const niceOperatorName = getOperatorName(operator, '');
|
|
const humanReadableOperator = humanReadableOperators[niceOperatorName];
|
|
|
|
return typeof operator === 'string'
|
|
? `${humanReadableOperator || niceOperatorName} to:\n`
|
|
: '';
|
|
};
|
|
|
|
const assertThrowingMatcherHint = (operatorName: string) =>
|
|
operatorName
|
|
? chalk.dim('assert') +
|
|
chalk.dim(`.${operatorName}(`) +
|
|
chalk.red('function') +
|
|
chalk.dim(')')
|
|
: '';
|
|
|
|
const assertMatcherHint = (
|
|
operator: string | null,
|
|
operatorName: string,
|
|
expected: unknown,
|
|
) => {
|
|
let message = '';
|
|
|
|
if (operator === '==' && expected === true) {
|
|
message =
|
|
chalk.dim('assert') +
|
|
chalk.dim('(') +
|
|
chalk.red('received') +
|
|
chalk.dim(')');
|
|
} else if (operatorName) {
|
|
message =
|
|
chalk.dim('assert') +
|
|
chalk.dim(`.${operatorName}(`) +
|
|
chalk.red('received') +
|
|
chalk.dim(', ') +
|
|
chalk.green('expected') +
|
|
chalk.dim(')');
|
|
}
|
|
|
|
return message;
|
|
};
|
|
|
|
function assertionErrorMessage(
|
|
error: AssertionErrorWithStack,
|
|
options: DiffOptions,
|
|
): string {
|
|
const {expected, actual, generatedMessage, message, operator, stack} = error;
|
|
const diffString = diff(expected, actual, options);
|
|
const hasCustomMessage = !generatedMessage;
|
|
const operatorName = getOperatorName(operator, stack);
|
|
const trimmedStack = stack
|
|
.replace(message, '')
|
|
.replaceAll(/AssertionError(.*)/g, '');
|
|
|
|
if (operatorName === 'doesNotThrow') {
|
|
return `${
|
|
buildHintString(assertThrowingMatcherHint(operatorName)) +
|
|
chalk.reset('Expected the function not to throw an error.\n') +
|
|
chalk.reset('Instead, it threw:\n')
|
|
} ${printReceived(actual)}${chalk.reset(
|
|
hasCustomMessage ? `\n\nMessage:\n ${message}` : '',
|
|
)}${trimmedStack}`;
|
|
}
|
|
|
|
if (operatorName === 'throws') {
|
|
if (error.generatedMessage) {
|
|
return (
|
|
buildHintString(assertThrowingMatcherHint(operatorName)) +
|
|
chalk.reset(error.message) +
|
|
chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') +
|
|
trimmedStack
|
|
);
|
|
}
|
|
return (
|
|
buildHintString(assertThrowingMatcherHint(operatorName)) +
|
|
chalk.reset('Expected the function to throw an error.\n') +
|
|
chalk.reset("But it didn't throw anything.") +
|
|
chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') +
|
|
trimmedStack
|
|
);
|
|
}
|
|
|
|
if (operatorName === 'fail') {
|
|
return (
|
|
buildHintString(assertMatcherHint(operator, operatorName, expected)) +
|
|
chalk.reset(hasCustomMessage ? `Message:\n ${message}` : '') +
|
|
trimmedStack
|
|
);
|
|
}
|
|
|
|
return `${
|
|
buildHintString(assertMatcherHint(operator, operatorName, expected)) +
|
|
chalk.reset(`Expected value ${operatorMessage(operator)}`)
|
|
} ${printExpected(expected)}\n${chalk.reset('Received:\n')} ${printReceived(
|
|
actual,
|
|
)}${chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '')}${
|
|
diffString ? `\n\nDifference:\n\n${diffString}` : ''
|
|
}${trimmedStack}`;
|
|
}
|
|
|
|
function buildHintString(hint: string) {
|
|
return hint ? `${hint}\n\n` : '';
|
|
}
|
|
|
|
export default assertionErrorMessage;
|