4

The question:

I'm using Chai to do the tests and I seem to be stuck on testing an expected error:

Chai expected [Function] to throw an (error)

Current code:

Here's the code of the test:

describe('Do something', function () {

    it('should remove a record from the table', function (done) {

        storage.delete(ID, done);

    });

    it('should throw an error when the lookup fails', function () {

         expect(storage.delete.bind(storage, ID)).to.throw('Record not found');
    });
});

Here's the code of the function:

delete: function (id, callback) {
    //  Generate a Visitor object
    visitor = new Visitor(id);

    /*  Delete the visitor that matches the queue an
        cookie provided. */
    tableService.deleteEntity(function (error, response) {

        //  If successful, go on.
        if (!error) {
            // Do something on success.
        }
        //  If unsuccessful, log error.
        else {
            if (error.code === 'ResourceNotFound') {
                throw new Error('Record not found');
            }

            //  For unexpected errros.
            else {

                throw new Error('Table service error (delete): ' + error);

            }
        }
        if (callback) callback();
    });

},

Attempted solutions:

I've tried multiple variations of calling expect function (including calling anonymous function:

expect(function() {storage.delete(ID);}).to.throw('Record not found');

Bind, as provided in the example,

and the basic one of

expect(storage.delete(ID)).to.throw('Record not found');

I've also tried substituting the throw parameter from 'Record not found' to multiple things including directing the input to an already created error (Error), and creating a new error in the parameter (new Error('Record not found'));

Possible causes:

I have a suspicion that the error is not being thrown because it takes a while for the test to communicate with the database to delete the record, however I am not sure of how I could remedy that.

Additionally, it seems that the test that runs right after this one actually returns the error that was supposed to be returned on THIS test.

Grandas
  • 519
  • 1
  • 5
  • 13
  • Is `tableService.deleteEntity` synchronous? – zerkms Mar 09 '15 at 00:26
  • 1
    Then `tableService.deleteEntity` never throws an exception. It's a nested handler that does which runs asynchronously. – zerkms Mar 09 '15 at 00:48
  • Thanks! In that case perhaps you could recommend a method for testing this error throw? Or a way of rewriting the function that would make it possible to test? – Grandas Mar 09 '15 at 00:52
  • Return promises instead. – zerkms Mar 09 '15 at 00:54
  • What's a promise in this context? – Grandas Mar 09 '15 at 00:55
  • 1
    https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise and any implementation, like `Q` or `Bluebird` – zerkms Mar 09 '15 at 00:59
  • Examine [chai-as-promises](http://chaijs.com/plugins/chai-as-promised) and [this SO question](http://stackoverflow.com/questions/20931737/chai-as-promised-is-eating-assertion-errors) – Kirill Slatin Mar 09 '15 at 04:04
  • Thanks a lot for the replies guys! Wrestling with Promises now, never used them before. – Grandas Mar 09 '15 at 08:07

1 Answers1

1

Given (from comments) that tableService.deleteEntity is asynchronous, it is impossible to test that throw. And the code itself is invalid. Because the thrown exception won't be caught, it will be unhandled as it was thrown in a different tick. Read more about Asynchronous error handling in JavaScript and unhandled exceptions in Node.js

In other words such a function cannot be tested for throwing errors:

function behaveBad(){
    setTimeout(function(){
        throw new Error('Bad. Don\'t do this');
    }, 50);
}
Kirill Slatin
  • 6,085
  • 3
  • 18
  • 38