Skip to content

Commit

Permalink
Merge pull request #4 from twada/node-v13-error-handler
Browse files Browse the repository at this point in the history
Sync with behavior changes in Node13
  • Loading branch information
twada authored Apr 18, 2020
2 parents 45c217d + 1b3da41 commit 05aeace
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 30 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_js:
- "8" # to be removed on "December 2019"
- "10" # to be removed on "April 2021"
- "12" # to be removed on "April 2022"
- "13" # to be removed on "June 2020"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ SPEC
- when messages does not match, rejects with the actual error.
- if `error` is a `<Class>` (constructor function), validate instanceof using constructor (works well with ES2015 classes that extends Error).
- when actual error is an instanceof `<Class>`, resolves with undefined.
- when actual error is NOT an instanceof `<Class>`, rejects with the actual error.
- when actual error is NOT an instanceof `<Class>`, rejects with AssertionError.
- appends `error.name` as expected error class name to the message if the `promiseFn` is not rejected.
- if `error` is a `<Function>`, run custom validation against actual rejection result.
- when validation function returns `true`, resolves with undefined.
- when returned value of validation function is NOT `true`, rejects with the actual error.
- when returned value of validation function is NOT `true`, rejects with AssertionError.
- if Error is thrown from validation function, rejects with the error.
- if `error` is an `<Object>`, that is an object where each property will be tested for.
- when all key-value pairs in `error` are the same as key-value pairs from actual rejected result, resolves with undefined. Note that only properties on the error object will be tested.
Expand Down
20 changes: 17 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,27 @@ function wantReject (stackStartFn, thennable, errorHandler, message) {
// Dealing with ES2015 class that extends Error
// see: https://github.com/nodejs/node/issues/3188
// see: https://github.com/nodejs/node/pull/4166
return reject(actualRejectionResult);
return reject(new AssertionError({
actual: actualRejectionResult,
expected: errorHandler,
message: message || 'The error is expected to be an instance of "' + errorHandler.name + '". Received "' + actualRejectionResult.constructor.name + '"\n\nError message:\n\n' + actualRejectionResult.message,
operator: stackStartFn.name,
stackStartFn: stackStartFn
}));
}
}
if (errorHandler.call({}, actualRejectionResult) === true) {
var handlerFuncResult = errorHandler.call({}, actualRejectionResult);
if (handlerFuncResult === true) {
return resolve();
} else {
return reject(actualRejectionResult);
var validationFunctionName = errorHandler.name ? 'The "' + errorHandler.name + '" validation function' : 'The validation function';
return reject(new AssertionError({
actual: actualRejectionResult,
expected: errorHandler,
message: message || validationFunctionName + ' is expected to return "true". Received ' + handlerFuncResult + '\n\nCaught error:\n\n' + actualRejectionResult,
operator: stackStartFn.name,
stackStartFn: stackStartFn
}));
}
}
if (typeof errorHandler === 'object') {
Expand Down
105 changes: 80 additions & 25 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,32 @@ implementations.forEach(function (impl) {
assert(nothing === undefined);
}, shouldNotBeRejected);
});
it('when actual error is NOT an instanceof `<Class>`, rejects with the actual error.', function () {
return rejects(
willReject(new TypeError('the original error message')),
RangeError
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof TypeError);
assert.equal(err.message, 'the original error message');
// < Node13
if (impl.name === 'official implementation' && semver.satisfies(process.version, '< 13.0.0')) {
it('when actual error is NOT an instanceof `<Class>`, rejects with the actual error.', function () {
return rejects(
willReject(new TypeError('the original error message')),
RangeError
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof TypeError);
assert.equal(err.message, 'the original error message');
});
});
});
} else {
it('when actual error is NOT an instanceof `<Class>`, rejects with AssertionError.', function () {
var te = new TypeError('the original error message');
return rejects(
willReject(te),
RangeError
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof assert.AssertionError);
assert.equal(err.actual, te);
assert.equal(err.expected, RangeError);
assert(/The error is expected to be an instance of "RangeError". Received "TypeError"/.test(err.message));
assert(/the original error message/.test(err.message));
});
});
}
describe('works well with ES2015 classes that extends Error', function () {
class ES2015Error extends Error {
}
Expand All @@ -201,15 +218,32 @@ implementations.forEach(function (impl) {
assert(nothing === undefined);
}, shouldNotBeRejected);
});
it('unmatch case, rejects with the original error.', function () {
return rejects(
willReject(new AnotherES2015Error('bar')),
ES2015Error
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof AnotherES2015Error);
assert.equal(err.message, 'bar');
// < Node13
if (impl.name === 'official implementation' && semver.satisfies(process.version, '< 13.0.0')) {
it('unmatch case, rejects with the original error.', function () {
return rejects(
willReject(new AnotherES2015Error('bar')),
ES2015Error
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof AnotherES2015Error);
assert.equal(err.message, 'bar');
});
});
});
} else {
it('unmatch case, rejects with AssertionError.', function () {
var another = new AnotherES2015Error('bar');
return rejects(
willReject(another),
ES2015Error
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof assert.AssertionError);
assert.equal(err.actual, another);
assert.equal(err.expected, ES2015Error);
assert(/The error is expected to be an instance of "ES2015Error". Received "AnotherES2015Error"/.test(err.message));
assert(/bar/.test(err.message));
});
});
}
});
it('appends `error.name` as expected error class name to the message if the `promiseFn` is not rejected.', function () {
return rejects(
Expand All @@ -232,17 +266,38 @@ implementations.forEach(function (impl) {
assert(nothing === undefined);
}, shouldNotBeRejected);
});
it('when returned value of validation function is NOT `true`, rejects with the actual error.', function () {
return rejects(
willReject(new RangeError('Wrong range')),
function (err) {
// < Node13
if (impl.name === 'official implementation' && semver.satisfies(process.version, '< 13.0.0')) {
it('when returned value of validation function is NOT `true`, rejects with the actual error.', function () {
return rejects(
willReject(new RangeError('Wrong range')),
function (err) {
return ((err instanceof TypeError) && /type/.test(err));
}
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof RangeError);
assert.equal(err.message, 'Wrong range');
});
});
} else {
it('when returned value of validation function is NOT `true`, rejects with AssertionError.', function () {
var e = new RangeError('Wrong range');
const handlerFn = (err) => {
return ((err instanceof TypeError) && /type/.test(err));
}
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof RangeError);
assert.equal(err.message, 'Wrong range');
};
return rejects(
willReject(e),
handlerFn
).then(shouldNotBeFulfilled, function (err) {
assert(err instanceof assert.AssertionError);
assert.equal(err.actual, e);
assert.equal(err.expected, handlerFn);

assert(/The "handlerFn" validation function is expected to return "true". Received false/.test(err.message), `actual [${err.message}]`);
assert(/RangeError: Wrong range/.test(err.message), `actual [${err.message}]`);
});
});
});
}
it('if Error is thrown from validation function, rejects with the error.', function () {
var e = new RangeError('the original error message');
var te = new TypeError('some programming error');
Expand Down

0 comments on commit 05aeace

Please sign in to comment.