Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chai: expecting an error or not depending on a parameter [duplicate]

I've been trying to do a text of a function that handles errors in a way that, if it is a valid error, it is thrown, but if it is not, then nothing is thrown. The problem is that i cant seem to set the parameter while using:

expect(handleError).to.throw(Error);

The ideal would be to use:

expect(handleError(validError)).to.throw(Error);

Is there any way to achieve this functionality?

code of the function:

function handleError (err) {
    if (err !== true) {
        switch (err) {
            case xxx:
            ...
        }
        throw "stop js execution";
    else {}
}

And the code of the test (not working as intended):

it("should stop Javascript execution if the parameter isnt \"true\"", function() {
    expect(handleError).to.be.a("function");
    expect(handleError(true)).to.not.throw(Error);
    expect(handleError("anything else")).to.throw(Error);
});
like image 616
Apzx Avatar asked Sep 30 '13 14:09

Apzx


3 Answers

The problem is that you are calling handleError, then passing the result to expect. If handleError throws, then expect never even gets called.

You need to defer calling handleError until expect is called, so that expect can see what happens when the function is called. Fortunately, this is what expect wants:

expect(function () { handleError(true); }).to.not.throw();
expect(function () { handleError("anything else") }).to.throw("stop js execution");

If you read the documentation for throw, you'll see that the associated expect should be passed a function.

like image 112
David Norman Avatar answered Nov 16 '22 17:11

David Norman


I ran into this same problem today and opted for another solution not mentioned here: partial function application using bind():

expect(handleError.bind(null, true)).to.not.throw();
expect(handleError.bind(null, "anything else")).to.throw("stop js execution");

This has the benefit of being concise, using plain old JavaScript, requiring no extra functions and you can even provide the value of this should your function depend on it.

like image 35
Sven Schoenung Avatar answered Nov 16 '22 16:11

Sven Schoenung


Wrapping the function call in a Lambda, as recommended by David Norman, is certainly one good way to solve this problem.

You might add this to your testing utilities, though, if you're looking for a more readable solution. This function wraps your function in an object with a method withArgs, which allows you to write the same statement in a more readable way. Ideally this would be built into Chai.

var calling = function(func) {
  return {
    withArgs: function(/* arg1, arg2, ... */) {
      var args = Array.prototype.slice.call(arguments);
      return function() {
        func.apply(null, args);
      };
    }
  };
};

Then use it like:

expect(calling(handleError).withArgs(true)).to.not.throw();        
expect(calling(handleError).withArgs("anything else")).to.throw("stop js execution");

It reads like english!

like image 1
morsecoder Avatar answered Nov 16 '22 16:11

morsecoder