Is there a way to get Chai working with asynchronous Mocha tests?
javascript, mocha.js, unit-testing
Solution
Your asynchronous test generates an exception, on failed `expect()`ations, that cannot be captured by `it()` because the exception is thrown outside of `it()`'s scope.
The captured exception that you see displayed is captured using `process.on('uncaughtException')` under node or using `window.onerror()` in the browser.
To fix this issue, you need to capture the exception within the asynchronous function called by `setTimeout()` in order to call `done()` with the exception as the first parameter. You also need to call `done()` with no parameter to indicate success, otherwise mocha would report a timeout error because your test function would never have signaled that it was done:
window.expect = chai.expect;
describe( 'my test', function() {
it( 'should do something', function ( done ) {
// done() is provided by it() to indicate asynchronous completion
// call done() with no parameter to indicate that it() is done() and successful
// or with an error to indicate that it() failed
setTimeout( function () {
// Called from the event loop, not it()
// So only the event loop could capture uncaught exceptions from here
try {
expect( true ).to.equal( false );
done(); // success: call done with no parameter to indicate that it() is done()
} catch( e ) {
done( e ); // failure: call done with an error Object to indicate that it() failed
}
}, 100 );
// returns immediately after setting timeout
// so it() can no longer catch exception happening asynchronously
}
}
Doing so on all your test cases is annoying and not DRY so you might want to provide a function to do this for you. Let's call this function `check()`:
function check( done, f ) {
try {
f();
done();
} catch( e ) {
done( e );
}
}
With `check()` you can now rewrite your asynchronous tests as follows:
window.expect = chai.expect;
describe( 'my test', function() {
it( 'should do something', function( done ) {
setTimeout( function () {
check( done, function() {
expect( true ).to.equal( false );
} );
}, 100 );
}
}
Problem
I'm running some asynchronous tests in Mocha using the Browser Runner and I'm trying to use Chai's expect style assertions: ``` window.expect = chai.expect; describe('my test', function() { it('should do something', function (done) { setTimeout(function () { expect(true).to.equal(false); }, 100); } } ``` This doesn't give me the normal failed assertion message, instead I get: ``` Error: the string "Uncaught AssertionError: expected true to equal false" was thrown, throw an Error :) at Runner.fail (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3475:11) at Runner.uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3748:8) at uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3778:10) ``` So it's obviously catching the error, it's just not displaying it correctly. Any ideas how to do this? I guess I could just call "done" with an error object but then I lose all the elegance of something like Chai and it becomes very clunky...