Skip to content

Commit

Permalink
test: improve common.expectsError
Browse files Browse the repository at this point in the history
The output is now improved by showing most properties all at once.
Besides that this adds a warning to use `assert.throws` instead
due to a better output.

PR-URL: nodejs#19797
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
  • Loading branch information
BridgeAR committed Apr 23, 2018
1 parent c1078c4 commit f85d599
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 30 deletions.
73 changes: 50 additions & 23 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,52 +690,79 @@ Object.defineProperty(exports, 'hasSmallICU', {
}
});

class Comparison {
constructor(obj, keys) {
for (const key of keys) {
if (key in obj)
this[key] = obj[key];
}
}
}

// Useful for testing expected internal/error objects
exports.expectsError = function expectsError(fn, settings, exact) {
if (typeof fn !== 'function') {
exact = settings;
settings = fn;
fn = undefined;
}

function innerFn(error) {
const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
assert.strictEqual(descriptor.enumerable,
false, 'The error message should be non-enumerable');

let innerSettings = settings;
if ('type' in settings) {
const type = settings.type;
if (type !== Error && !Error.isPrototypeOf(type)) {
throw new TypeError('`settings.type` must inherit from `Error`');
}
assert(error instanceof type,
`${error.name} is not instance of ${type.name}`);
let typeName = error.constructor.name;
if (typeName === 'NodeError' && type.name !== 'NodeError') {
typeName = Object.getPrototypeOf(error.constructor).name;
let constructor = error.constructor;
if (constructor.name === 'NodeError' && type.name !== 'NodeError') {
constructor = Object.getPrototypeOf(error.constructor);
}
assert.strictEqual(typeName, type.name);
// Add the `type` to the error to properly compare and visualize it.
if (!('type' in error))
error.type = constructor;
}
if ('info' in settings) {
assert.deepStrictEqual(error.info, settings.info);
}
if ('message' in settings) {
const message = settings.message;
if (typeof message === 'string') {
assert.strictEqual(error.message, message);
} else {
assert(message.test(error.message),
`${error.message} does not match ${message}`);
}

if ('message' in settings &&
typeof settings.message === 'object' &&
settings.message.test(error.message)) {
// Make a copy so we are able to modify the settings.
innerSettings = Object.create(
settings, Object.getOwnPropertyDescriptors(settings));
// Visualize the message as identical in case of other errors.
innerSettings.message = error.message;
}

// Check all error properties.
const keys = Object.keys(settings);
for (const key of keys) {
if (key === 'message' || key === 'type' || key === 'info')
continue;
const actual = error[key];
const expected = settings[key];
assert.strictEqual(actual, expected,
`${key}: expected ${expected}, not ${actual}`);
if (!util.isDeepStrictEqual(error[key], innerSettings[key])) {
// Create placeholder objects to create a nice output.
const a = new Comparison(error, keys);
const b = new Comparison(innerSettings, keys);

const tmpLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
const err = new assert.AssertionError({
actual: a,
expected: b,
operator: 'strictEqual',
stackStartFn: assert.throws
});
Error.stackTraceLimit = tmpLimit;

throw new assert.AssertionError({
actual: error,
expected: settings,
operator: 'common.expectsError',
message: err.message
});
}

}
return true;
}
Expand Down
8 changes: 3 additions & 5 deletions test/parallel/test-console-assign-undefined.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@
const tmp = global.console;
global.console = 42;

const common = require('../common');
require('../common');
const assert = require('assert');

// Originally the console had a getter. Test twice to verify it had no side
// effect.
assert.strictEqual(global.console, 42);
assert.strictEqual(global.console, 42);

common.expectsError(
assert.throws(
() => console.log('foo'),
{
type: TypeError
}
{ name: 'TypeError' }
);

global.console = 1;
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-internal-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ common.expectsError(() => {
}, { code: 'TEST_ERROR_1', type: RangeError });
}, {
code: 'ERR_ASSERTION',
message: /^.+ is not instance of \S/
message: /- type: \[Function: TypeError]\n\+ type: \[Function: RangeError]/
});

common.expectsError(() => {
Expand All @@ -89,7 +89,7 @@ common.expectsError(() => {
}, {
code: 'ERR_ASSERTION',
type: assert.AssertionError,
message: /.+ does not match \S/
message: /- message: 'Error for testing purposes: a'\n\+ message: \/\^Error/
});

// Test ERR_INVALID_FD_TYPE
Expand Down

0 comments on commit f85d599

Please sign in to comment.