assert: make sure throws is able to handle primitives
This fixes some possible issues with `assert.throws` and `assert.rejects` in combination with an validation object. It will now properly handle primitive values being thrown as error. It also makes sure the `generatedMessage` property is properly set if `assert.throws` or `assert.rejects` is used in combination with an validation object and improves the error performance in such cases by only creating the error once. In addition it will fix detecting regular expressions from a different context such as n-api that are passed through as validator for `assert.throws` or `assert.rejects`. Until now those were not tested. PR-URL: https://github.com/nodejs/node/pull/20482 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
parent
5e6ca894cf
commit
560925fe22
@ -382,16 +382,16 @@ function compareExceptionKey(actual, expected, key, message, keys) {
|
|||||||
const a = new Comparison(actual, keys);
|
const a = new Comparison(actual, keys);
|
||||||
const b = new Comparison(expected, keys, actual);
|
const b = new Comparison(expected, keys, actual);
|
||||||
|
|
||||||
const tmpLimit = Error.stackTraceLimit;
|
|
||||||
Error.stackTraceLimit = 0;
|
|
||||||
const err = new AssertionError({
|
const err = new AssertionError({
|
||||||
actual: a,
|
actual: a,
|
||||||
expected: b,
|
expected: b,
|
||||||
operator: 'deepStrictEqual',
|
operator: 'deepStrictEqual',
|
||||||
stackStartFn: assert.throws
|
stackStartFn: assert.throws
|
||||||
});
|
});
|
||||||
Error.stackTraceLimit = tmpLimit;
|
err.actual = actual;
|
||||||
message = err.message;
|
err.expected = expected;
|
||||||
|
err.operator = 'throws';
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
innerFail({
|
innerFail({
|
||||||
actual,
|
actual,
|
||||||
@ -405,7 +405,7 @@ function compareExceptionKey(actual, expected, key, message, keys) {
|
|||||||
|
|
||||||
function expectedException(actual, expected, msg) {
|
function expectedException(actual, expected, msg) {
|
||||||
if (typeof expected !== 'function') {
|
if (typeof expected !== 'function') {
|
||||||
if (expected instanceof RegExp)
|
if (isRegExp(expected))
|
||||||
return expected.test(actual);
|
return expected.test(actual);
|
||||||
// assert.doesNotThrow does not accept objects.
|
// assert.doesNotThrow does not accept objects.
|
||||||
if (arguments.length === 2) {
|
if (arguments.length === 2) {
|
||||||
@ -413,6 +413,26 @@ function expectedException(actual, expected, msg) {
|
|||||||
'expected', ['Function', 'RegExp'], expected
|
'expected', ['Function', 'RegExp'], expected
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Disallow primitives as error argument.
|
||||||
|
// This is here to prevent a breaking change.
|
||||||
|
if (typeof expected !== 'object') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle primitives properly.
|
||||||
|
if (typeof actual !== 'object' || actual === null) {
|
||||||
|
const err = new AssertionError({
|
||||||
|
actual,
|
||||||
|
expected,
|
||||||
|
message: msg,
|
||||||
|
operator: 'deepStrictEqual',
|
||||||
|
stackStartFn: assert.throws
|
||||||
|
});
|
||||||
|
err.operator = 'throws';
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
const keys = Object.keys(expected);
|
const keys = Object.keys(expected);
|
||||||
// Special handle errors to make sure the name and the message are compared
|
// Special handle errors to make sure the name and the message are compared
|
||||||
// as well.
|
// as well.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
assert.js:*
|
assert.js:*
|
||||||
throw new AssertionError(obj);
|
throw err;
|
||||||
^
|
^
|
||||||
|
|
||||||
AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B:
|
AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B:
|
||||||
|
@ -740,7 +740,9 @@ common.expectsError(
|
|||||||
const frames = err.stack.split('\n');
|
const frames = err.stack.split('\n');
|
||||||
const [, filename, line, column] = frames[1].match(/\((.+):(\d+):(\d+)\)/);
|
const [, filename, line, column] = frames[1].match(/\((.+):(\d+):(\d+)\)/);
|
||||||
// Reset the cache to check again
|
// Reset the cache to check again
|
||||||
|
const size = errorCache.size;
|
||||||
errorCache.delete(`${filename}${line - 1}${column - 1}`);
|
errorCache.delete(`${filename}${line - 1}${column - 1}`);
|
||||||
|
assert.strictEqual(errorCache.size, size - 1);
|
||||||
const data = `${'\n'.repeat(line - 1)}${' '.repeat(column - 1)}` +
|
const data = `${'\n'.repeat(line - 1)}${' '.repeat(column - 1)}` +
|
||||||
'ok(failed(badly));';
|
'ok(failed(badly));';
|
||||||
try {
|
try {
|
||||||
@ -849,6 +851,7 @@ common.expectsError(
|
|||||||
{
|
{
|
||||||
name: 'AssertionError [ERR_ASSERTION]',
|
name: 'AssertionError [ERR_ASSERTION]',
|
||||||
code: 'ERR_ASSERTION',
|
code: 'ERR_ASSERTION',
|
||||||
|
generatedMessage: true,
|
||||||
message: `${start}\n${actExp}\n\n` +
|
message: `${start}\n${actExp}\n\n` +
|
||||||
" Comparison {\n name: 'Error',\n- message: 'foo'" +
|
" Comparison {\n name: 'Error',\n- message: 'foo'" +
|
||||||
"\n+ message: ''\n }"
|
"\n+ message: ''\n }"
|
||||||
@ -940,3 +943,45 @@ assert.throws(
|
|||||||
' }'
|
' }'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let actual = null;
|
||||||
|
const expected = { message: 'foo' };
|
||||||
|
assert.throws(
|
||||||
|
() => assert.throws(
|
||||||
|
() => { throw actual; },
|
||||||
|
expected
|
||||||
|
),
|
||||||
|
{
|
||||||
|
operator: 'throws',
|
||||||
|
actual,
|
||||||
|
expected,
|
||||||
|
generatedMessage: true,
|
||||||
|
message: `${start}\n${actExp}\n\n` +
|
||||||
|
'- null\n' +
|
||||||
|
'+ {\n' +
|
||||||
|
"+ message: 'foo'\n" +
|
||||||
|
'+ }'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
actual = 'foobar';
|
||||||
|
const message = 'message';
|
||||||
|
assert.throws(
|
||||||
|
() => assert.throws(
|
||||||
|
() => { throw actual; },
|
||||||
|
{ message: 'foobar' },
|
||||||
|
message
|
||||||
|
),
|
||||||
|
{
|
||||||
|
actual,
|
||||||
|
message,
|
||||||
|
operator: 'throws',
|
||||||
|
generatedMessage: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This case is only there to make sure there is no breaking change.
|
||||||
|
// eslint-disable-next-line no-restricted-syntax, no-throw-literal
|
||||||
|
assert.throws(() => { throw 4; }, 4);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user