tj / should.js

BDD style assertions for node.js -- test framework agnostic
MIT License
2.75k stars 194 forks source link

testing should.throw() on asynchronous code #147

Closed jmarca closed 10 years ago

jmarca commented 10 years ago

I am trying to test that an async bit of code should throw an error, but should.throw() doesn't seem set up for async code.

For example

 (function(){ 
    fs.readFile('fake.file', function (err, data) {
      if (err) throw err;
    });
  ).should.throwError();

That doesn't work.

Should one instead attach a listener on the process' uncaught exception handler?

it('should throw',function(done){
  process.on('uncaughtException', function(err) {
    console.log('Caught exception: ' + err);
    return done();
  });
  fs.readFile('fake.file', function (err, data) {
    if (err) throw err;
  });
  return null; 
})

Of course, that doesn't work either (I get Caught exception: Error: ENOENT, open 'fake.file'), but somehow the done() is skipped and the test fails with

 1) verify config checker should throw:
     Uncaught Error: ENOENT, open 'fake.file'

and anyway, the node.js docs deprecate uncaughtException in favor of domains, which I haven't learned yet.

Guidance or a new feature would be appreciated.

btd commented 10 years ago

Maybe something like this?

fs.readFile('fake.file', function (err, data) {
     err.should.be.Error; //it is in case you are sure it will be, it will fail on null with standard message that null it is not an object or similar
should(err).be.Error; // in case you are not sure it will fail if no error with more descriptive message
    });

.throw created only for sync functions, for async flow usually you need to make test inside callback.

jmarca commented 10 years ago

Well, the "readFile" was a toy example, just trying to get something that throws an error, not reports an error in the err argument. The function I am testing does a stat on a file and (originally) would throw if the file was not mode '0600'.

When the function calls throw(), the callback is not triggered. I was hoping to hack something based on should.throw(), but you confirmed it isn't possible.

I'll dig into domains and try to solve this properly

btd commented 10 years ago

If you need to be sure that callback called then you better to add sinon, spy will check if function was called.