Skip to content

Commit a5ee31b

Browse files
BridgeARtargos
authored andcommitted
assert: accept regular expressions to validate
This makes sure regular expressions on validation objects validate against strings when used with `assert.throws` and `assert.rejects`. PR-URL: #20485 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent 08097cc commit a5ee31b

File tree

3 files changed

+88
-11
lines changed

3 files changed

+88
-11
lines changed

doc/api/assert.md

+44-6
Original file line numberDiff line numberDiff line change
@@ -1070,27 +1070,65 @@ changes:
10701070
Expects the function `block` to throw an error.
10711071

10721072
If specified, `error` can be a [`Class`][], [`RegExp`][], a validation function,
1073-
an object where each property will be tested for, or an instance of error where
1074-
each property will be tested for including the non-enumerable `message` and
1075-
`name` properties.
1073+
a validation object where each property will be tested for strict deep equality,
1074+
or an instance of error where each property will be tested for strict deep
1075+
equality including the non-enumerable `message` and `name` properties. When
1076+
using an object, it is also possible to use a regular expression, when
1077+
validating against a string property. See below for examples.
10761078

10771079
If specified, `message` will be the message provided by the `AssertionError` if
10781080
the block fails to throw.
10791081

1080-
Custom error object / error instance:
1082+
Custom validation object / error instance:
10811083

10821084
```js
10831085
const err = new TypeError('Wrong value');
10841086
err.code = 404;
1087+
err.foo = 'bar';
1088+
err.info = {
1089+
nested: true,
1090+
baz: 'text'
1091+
};
1092+
err.reg = /abc/i;
10851093

10861094
assert.throws(
10871095
() => {
10881096
throw err;
10891097
},
10901098
{
10911099
name: 'TypeError',
1092-
message: 'Wrong value'
1093-
// Note that only properties on the error object will be tested!
1100+
message: 'Wrong value',
1101+
info: {
1102+
nested: true,
1103+
baz: 'text'
1104+
}
1105+
// Note that only properties on the validation object will be tested for.
1106+
// Using nested objects requires all properties to be present. Otherwise
1107+
// the validation is going to fail.
1108+
}
1109+
);
1110+
1111+
// Using regular expressions to validate error properties:
1112+
assert.throws(
1113+
() => {
1114+
throw err;
1115+
},
1116+
{
1117+
// The `name` and `message` properties are strings and using regular
1118+
// expressions on those will match against the string. If they fail, an
1119+
// error is thrown.
1120+
name: /^TypeError$/,
1121+
message: /Wrong/,
1122+
foo: 'bar',
1123+
info: {
1124+
nested: true,
1125+
// It is not possible to use regular expressions for nested properties!
1126+
baz: 'text'
1127+
},
1128+
// The `reg` property contains a regular expression and only if the
1129+
// validation object contains an identical regular expression, it is going
1130+
// to pass.
1131+
reg: /abc/i
10941132
}
10951133
);
10961134

lib/assert.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const {
3535
}
3636
} = require('internal/errors');
3737
const { openSync, closeSync, readSync } = require('fs');
38-
const { inspect, types: { isPromise } } = require('util');
38+
const { inspect, types: { isPromise, isRegExp } } = require('util');
3939
const { EOL } = require('os');
4040
const { NativeModule } = require('internal/bootstrap/loaders');
4141

@@ -362,10 +362,18 @@ assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
362362
};
363363

364364
class Comparison {
365-
constructor(obj, keys) {
365+
constructor(obj, keys, actual) {
366366
for (const key of keys) {
367-
if (key in obj)
368-
this[key] = obj[key];
367+
if (key in obj) {
368+
if (actual !== undefined &&
369+
typeof actual[key] === 'string' &&
370+
isRegExp(obj[key]) &&
371+
obj[key].test(actual[key])) {
372+
this[key] = actual[key];
373+
} else {
374+
this[key] = obj[key];
375+
}
376+
}
369377
}
370378
}
371379
}
@@ -375,7 +383,7 @@ function compareExceptionKey(actual, expected, key, message, keys) {
375383
if (!message) {
376384
// Create placeholder objects to create a nice output.
377385
const a = new Comparison(actual, keys);
378-
const b = new Comparison(expected, keys);
386+
const b = new Comparison(expected, keys, actual);
379387

380388
const tmpLimit = Error.stackTraceLimit;
381389
Error.stackTraceLimit = 0;
@@ -415,6 +423,11 @@ function expectedException(actual, expected, msg) {
415423
keys.push('name', 'message');
416424
}
417425
for (const key of keys) {
426+
if (typeof actual[key] === 'string' &&
427+
isRegExp(expected[key]) &&
428+
expected[key].test(actual[key])) {
429+
continue;
430+
}
418431
compareExceptionKey(actual, expected, key, msg, keys);
419432
}
420433
return true;

test/parallel/test-assert.js

+26
Original file line numberDiff line numberDiff line change
@@ -914,3 +914,29 @@ assert.throws(
914914
}
915915
);
916916
}
917+
918+
assert.throws(
919+
() => { throw new TypeError('foobar'); },
920+
{
921+
message: /foo/,
922+
name: /^TypeError$/
923+
}
924+
);
925+
926+
assert.throws(
927+
() => assert.throws(
928+
() => { throw new TypeError('foobar'); },
929+
{
930+
message: /fooa/,
931+
name: /^TypeError$/
932+
}
933+
),
934+
{
935+
message: `${start}\n${actExp}\n\n` +
936+
' Comparison {\n' +
937+
"- message: 'foobar',\n" +
938+
'+ message: /fooa/,\n' +
939+
" name: 'TypeError'\n" +
940+
' }'
941+
}
942+
);

0 commit comments

Comments
 (0)