482 lines
15 KiB
JavaScript
482 lines
15 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', {
|
|
value: true
|
|
});
|
|
exports.default = exports.createMatcher = void 0;
|
|
var _expectUtils = require('@jest/expect-utils');
|
|
var _jestMatcherUtils = require('jest-matcher-utils');
|
|
var _jestMessageUtil = require('jest-message-util');
|
|
var _print = require('./print');
|
|
/**
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/* eslint-disable local/ban-types-eventually */
|
|
|
|
const DID_NOT_THROW = 'Received function did not throw';
|
|
const getThrown = e => {
|
|
const hasMessage =
|
|
e !== null && e !== undefined && typeof e.message === 'string';
|
|
if (hasMessage && typeof e.name === 'string' && typeof e.stack === 'string') {
|
|
return {
|
|
hasMessage,
|
|
isError: true,
|
|
message: e.message,
|
|
value: e
|
|
};
|
|
}
|
|
return {
|
|
hasMessage,
|
|
isError: false,
|
|
message: hasMessage ? e.message : String(e),
|
|
value: e
|
|
};
|
|
};
|
|
const createMatcher = (matcherName, fromPromise) =>
|
|
function (received, expected) {
|
|
const options = {
|
|
isNot: this.isNot,
|
|
promise: this.promise
|
|
};
|
|
let thrown = null;
|
|
if (fromPromise && (0, _expectUtils.isError)(received)) {
|
|
thrown = getThrown(received);
|
|
} else {
|
|
if (typeof received !== 'function') {
|
|
if (!fromPromise) {
|
|
const placeholder = expected === undefined ? '' : 'expected';
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
placeholder,
|
|
options
|
|
),
|
|
`${(0, _jestMatcherUtils.RECEIVED_COLOR)(
|
|
'received'
|
|
)} value must be a function`,
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Received',
|
|
received,
|
|
_jestMatcherUtils.printReceived
|
|
)
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
try {
|
|
received();
|
|
} catch (e) {
|
|
thrown = getThrown(e);
|
|
}
|
|
}
|
|
}
|
|
if (expected === undefined) {
|
|
return toThrow(matcherName, options, thrown);
|
|
} else if (typeof expected === 'function') {
|
|
return toThrowExpectedClass(matcherName, options, thrown, expected);
|
|
} else if (typeof expected === 'string') {
|
|
return toThrowExpectedString(matcherName, options, thrown, expected);
|
|
} else if (expected !== null && typeof expected.test === 'function') {
|
|
return toThrowExpectedRegExp(matcherName, options, thrown, expected);
|
|
} else if (
|
|
expected !== null &&
|
|
typeof expected.asymmetricMatch === 'function'
|
|
) {
|
|
return toThrowExpectedAsymmetric(matcherName, options, thrown, expected);
|
|
} else if (expected !== null && typeof expected === 'object') {
|
|
return toThrowExpectedObject(matcherName, options, thrown, expected);
|
|
} else {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
),
|
|
`${(0, _jestMatcherUtils.EXPECTED_COLOR)(
|
|
'expected'
|
|
)} value must be a string or regular expression or class or error`,
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Expected',
|
|
expected,
|
|
_jestMatcherUtils.printExpected
|
|
)
|
|
)
|
|
);
|
|
}
|
|
};
|
|
exports.createMatcher = createMatcher;
|
|
const matchers = {
|
|
toThrow: createMatcher('toThrow'),
|
|
toThrowError: createMatcher('toThrowError')
|
|
};
|
|
const toThrowExpectedRegExp = (matcherName, options, thrown, expected) => {
|
|
const pass = thrown !== null && expected.test(thrown.message);
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected pattern: not ', expected) +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatReceived(
|
|
'Received message: ',
|
|
thrown,
|
|
'message',
|
|
expected
|
|
) + formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected pattern: ', expected) +
|
|
(thrown === null
|
|
? `\n${DID_NOT_THROW}`
|
|
: thrown.hasMessage
|
|
? formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'));
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const toThrowExpectedAsymmetric = (matcherName, options, thrown, expected) => {
|
|
const pass = thrown !== null && expected.asymmetricMatch(thrown.value);
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected asymmetric matcher: not ', expected) +
|
|
'\n' +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatReceived('Received name: ', thrown, 'name') +
|
|
formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Thrown value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected asymmetric matcher: ', expected) +
|
|
'\n' +
|
|
(thrown === null
|
|
? DID_NOT_THROW
|
|
: thrown.hasMessage
|
|
? formatReceived('Received name: ', thrown, 'name') +
|
|
formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Thrown value: ', thrown, 'value'));
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const toThrowExpectedObject = (matcherName, options, thrown, expected) => {
|
|
const expectedMessageAndCause = createMessageAndCause(expected);
|
|
const thrownMessageAndCause =
|
|
thrown !== null ? createMessageAndCause(thrown.value) : null;
|
|
const pass =
|
|
thrown !== null &&
|
|
thrown.message === expected.message &&
|
|
thrownMessageAndCause === expectedMessageAndCause;
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected(
|
|
`Expected ${messageAndCause(expected)}: not `,
|
|
expectedMessageAndCause
|
|
) +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
(thrown === null
|
|
? // eslint-disable-next-line prefer-template
|
|
formatExpected(
|
|
`Expected ${messageAndCause(expected)}: `,
|
|
expectedMessageAndCause
|
|
) +
|
|
'\n' +
|
|
DID_NOT_THROW
|
|
: thrown.hasMessage
|
|
? // eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.printDiffOrStringify)(
|
|
expectedMessageAndCause,
|
|
thrownMessageAndCause,
|
|
`Expected ${messageAndCause(expected)}`,
|
|
`Received ${messageAndCause(thrown.value)}`,
|
|
true
|
|
) +
|
|
'\n' +
|
|
formatStack(thrown)
|
|
: formatExpected(
|
|
`Expected ${messageAndCause(expected)}: `,
|
|
expectedMessageAndCause
|
|
) + formatReceived('Received value: ', thrown, 'value'));
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const toThrowExpectedClass = (matcherName, options, thrown, expected) => {
|
|
const pass = thrown !== null && thrown.value instanceof expected;
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
(0, _print.printExpectedConstructorNameNot)(
|
|
'Expected constructor',
|
|
expected
|
|
) +
|
|
(thrown !== null &&
|
|
thrown.value != null &&
|
|
typeof thrown.value.constructor === 'function' &&
|
|
thrown.value.constructor !== expected
|
|
? (0, _print.printReceivedConstructorNameNot)(
|
|
'Received constructor',
|
|
thrown.value.constructor,
|
|
expected
|
|
)
|
|
: '') +
|
|
'\n' +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
(0, _print.printExpectedConstructorName)(
|
|
'Expected constructor',
|
|
expected
|
|
) +
|
|
(thrown === null
|
|
? `\n${DID_NOT_THROW}`
|
|
: `${
|
|
thrown.value != null &&
|
|
typeof thrown.value.constructor === 'function'
|
|
? (0, _print.printReceivedConstructorName)(
|
|
'Received constructor',
|
|
thrown.value.constructor
|
|
)
|
|
: ''
|
|
}\n${
|
|
thrown.hasMessage
|
|
? formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value')
|
|
}`);
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const toThrowExpectedString = (matcherName, options, thrown, expected) => {
|
|
const pass = thrown !== null && thrown.message.includes(expected);
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected substring: not ', expected) +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatReceived(
|
|
'Received message: ',
|
|
thrown,
|
|
'message',
|
|
expected
|
|
) + formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
undefined,
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
formatExpected('Expected substring: ', expected) +
|
|
(thrown === null
|
|
? `\n${DID_NOT_THROW}`
|
|
: thrown.hasMessage
|
|
? formatReceived('Received message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Received value: ', thrown, 'value'));
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const toThrow = (matcherName, options, thrown) => {
|
|
const pass = thrown !== null;
|
|
const message = pass
|
|
? () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
'',
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
(thrown !== null && thrown.hasMessage
|
|
? formatReceived('Error name: ', thrown, 'name') +
|
|
formatReceived('Error message: ', thrown, 'message') +
|
|
formatStack(thrown)
|
|
: formatReceived('Thrown value: ', thrown, 'value'))
|
|
: () =>
|
|
// eslint-disable-next-line prefer-template
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
'',
|
|
options
|
|
) +
|
|
'\n\n' +
|
|
DID_NOT_THROW;
|
|
return {
|
|
message,
|
|
pass
|
|
};
|
|
};
|
|
const formatExpected = (label, expected) =>
|
|
`${label + (0, _jestMatcherUtils.printExpected)(expected)}\n`;
|
|
const formatReceived = (label, thrown, key, expected) => {
|
|
if (thrown === null) {
|
|
return '';
|
|
}
|
|
if (key === 'message') {
|
|
const message = thrown.message;
|
|
if (typeof expected === 'string') {
|
|
const index = message.indexOf(expected);
|
|
if (index !== -1) {
|
|
return `${
|
|
label +
|
|
(0, _print.printReceivedStringContainExpectedSubstring)(
|
|
message,
|
|
index,
|
|
expected.length
|
|
)
|
|
}\n`;
|
|
}
|
|
} else if (expected instanceof RegExp) {
|
|
return `${
|
|
label +
|
|
(0, _print.printReceivedStringContainExpectedResult)(
|
|
message,
|
|
typeof expected.exec === 'function' ? expected.exec(message) : null
|
|
)
|
|
}\n`;
|
|
}
|
|
return `${label + (0, _jestMatcherUtils.printReceived)(message)}\n`;
|
|
}
|
|
if (key === 'name') {
|
|
return thrown.isError
|
|
? `${label + (0, _jestMatcherUtils.printReceived)(thrown.value.name)}\n`
|
|
: '';
|
|
}
|
|
if (key === 'value') {
|
|
return thrown.isError
|
|
? ''
|
|
: `${label + (0, _jestMatcherUtils.printReceived)(thrown.value)}\n`;
|
|
}
|
|
return '';
|
|
};
|
|
const formatStack = thrown =>
|
|
thrown === null || !thrown.isError
|
|
? ''
|
|
: (0, _jestMessageUtil.formatStackTrace)(
|
|
(0, _jestMessageUtil.separateMessageFromStack)(thrown.value.stack)
|
|
.stack,
|
|
{
|
|
rootDir: process.cwd(),
|
|
testMatch: []
|
|
},
|
|
{
|
|
noStackTrace: false
|
|
}
|
|
);
|
|
function createMessageAndCauseMessage(error) {
|
|
if (error.cause instanceof Error) {
|
|
return `{ message: ${error.message}, cause: ${createMessageAndCauseMessage(
|
|
error.cause
|
|
)}}`;
|
|
}
|
|
return `{ message: ${error.message} }`;
|
|
}
|
|
function createMessageAndCause(error) {
|
|
if (error.cause instanceof Error) {
|
|
return createMessageAndCauseMessage(error);
|
|
}
|
|
return error.message;
|
|
}
|
|
function messageAndCause(error) {
|
|
return error.cause === undefined ? 'message' : 'message and cause';
|
|
}
|
|
var _default = matchers;
|
|
exports.default = _default;
|