Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync with behavior changes in Node13 #4

Merged
merged 7 commits into from Apr 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
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
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
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
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