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

rejectedWith / check-error doesn't compare the real prototype #226

Open
janis91 opened this issue Oct 17, 2017 · 6 comments
Open

rejectedWith / check-error doesn't compare the real prototype #226

janis91 opened this issue Oct 17, 2017 · 6 comments

Comments

@janis91
Copy link

janis91 commented Oct 17, 2017

Hi,

I have an issue with rejectedWith and I guess it is caused by the check-error dependency under the hood:
I am using Error to extend it and define an own Error (here HttpError) like so:

class HttpError extends Error {
    constructor(statusCode, message) {
        super(message);
        this.statusCode = statusCode;
        Object.setPrototypeOf(this, new.target.prototype);
        this.name = new.target.name;
    }
    toString() {
        return `${this.name}(${this.statusCode}): ${this.message}`;
    }
}

Now I have an async function that is throwing an instance of HttpError (that is created inside the function, therefore I create two new HttpErrors in the example below) and test it with rejectedWith():

it('', async () => {
   const httpError = new HttpError(404, 'Not found.');
   await expect(Promise.reject(new HttpError(404, 'Not found.'))).to.be.rejectedWith(httpError);
});

I would have expected this works, but it does not and gives back the following error:

AssertionError: expected promise to be rejected with 'HttpError(404): Not found.' but it was rejected with 'HttpError(404): Not found.'

My expectation would be that it compares if the thrown error deepEquals an object given, but it doesn't. It uses the check-error compatibleInstance check and this doesn't include a differentiation between different errors (and custom properties inside of it). The problem is obviously the instanceof Error as the HttpError extends Error it is still a instanceof Error.

Do you have a suggestion how to deal with this?

@domenic
Copy link
Collaborator

domenic commented Oct 17, 2017

In general Chai as Promised's rejectWith() emulates Chai's throws(). So if you'd like it fixed in Chai, open an error there.

Otherwise you can just check the rejection value:

const rejectionErr = await promise.catch(err => err);
expect(rejectionError).to.equal(httpError);

@janis91
Copy link
Author

janis91 commented Oct 17, 2017

Your suggested solution unfortunately doesn't work for me. It still says:

AssertionError: expected [HttpError: Not found.] to equal [HttpError: Not found.]

But if I see it right, the check for this is done here:
https://github.com/domenic/chai-as-promised/blob/master/lib/chai-as-promised.js#L187
And this line causes the custom Error to be treated like an Error instance.

@domenic
Copy link
Collaborator

domenic commented Oct 17, 2017

Sorry, I had an extra .prototype. Let me remove that and then it should work.

@janis91
Copy link
Author

janis91 commented Oct 18, 2017

Still doesn't work. Mhm, seems like I do something wrong.

@meeber
Copy link
Contributor

meeber commented Oct 19, 2017

@janis91 As Domenic mentioned, .rejectedWith mimics Chai's .throw assertion, so the best place to look for clues is http://chaijs.com/api/bdd/#method_throw.

Your original example is failing because, when passed an Error instance, the assertion checks to see if that Error instance is strictly (===) equal to the value of the rejected promise, which it's not.

This should work:

await expect(Promise.reject(new HttpError(404, 'Not found.')))
  .to.be.rejectedWith(HttpError, 'Not found.')
  .and.eventually.have.property('statusCode', 404);

(I personally think it'd be more useful for .throw and .rejectedWith to perform a deep equality comparison instead of strict, but that'd be a pretty big breaking change at this point. Also, it'd have to be a "special" deep equality algo that ignored the stack trace. Although the semantics are a bit awkward, maybe this could be implemented by introducing .deep.throw and .deep.rejectedWith. That way it wouldn't be a breaking change, and it'd be consistent with Chai's other assertions. May be worth raising an issue on Chai's issue tracker if you feel strongly about it.)

@janis91
Copy link
Author

janis91 commented Oct 19, 2017

@meeber thanks for your response. Your approach works fine. I will raise this issue on chai as well and let you know the issue number here. I think for now I will stick to your suggestion, but in the future it would be quite useful to be able to check for a deep equality of errors. Especially because the world is moving forward and more and more projects are written with es6 and use classes and extend the Error class in order to have a nicer error handling available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants