I am having troubles trying to use assert.throws in my Mocha unit tests,
I have this method:
var getMetadatas = function (file, callback) {
fs.readFile(file, {encoding: 'utf-8'}, function(err, data){
// stuff
if (somethingWentWrong)
throw new Error('Something went wrong')
// callback call
})
}
And in my unit tests I have:
it('should throw an error when passing a bad formatted file', function(){
assert.throws(
getMetadatas('someBadFormattedFile', function(metadatas){})
)
})
The results I get are random, sometimes the error is being thrown (I got Uncaught Error: something went wrong
) and the test is failing, sometimes it passes.
I have tried a couple of other things, such as passing the error through the callback and do:
var fn = function(){
parse.getMetadatas('test/test_incorrect.md', function (err, metas) {
if (err) throw err
})
}
assert.throws( function() { fn() }, Error )
And I got as output: AssertionError: Missing expected exception (Error)..
so I guess he doesn't see anything...
The only way I can get assert.throws
to work as I expected is with a synchronous function:
assert.throws(
function () {throw new Error('error')}
)
I was wondering if it had to do something with done()
, but still even by calling it in my callback, no success. Did I miss something?
I am having troubles trying to use assert.throws in my Mocha unit tests,
I have this method:
var getMetadatas = function (file, callback) {
fs.readFile(file, {encoding: 'utf-8'}, function(err, data){
// stuff
if (somethingWentWrong)
throw new Error('Something went wrong')
// callback call
})
}
And in my unit tests I have:
it('should throw an error when passing a bad formatted file', function(){
assert.throws(
getMetadatas('someBadFormattedFile', function(metadatas){})
)
})
The results I get are random, sometimes the error is being thrown (I got Uncaught Error: something went wrong
) and the test is failing, sometimes it passes.
I have tried a couple of other things, such as passing the error through the callback and do:
var fn = function(){
parse.getMetadatas('test/test_incorrect.md', function (err, metas) {
if (err) throw err
})
}
assert.throws( function() { fn() }, Error )
And I got as output: AssertionError: Missing expected exception (Error)..
so I guess he doesn't see anything...
The only way I can get assert.throws
to work as I expected is with a synchronous function:
assert.throws(
function () {throw new Error('error')}
)
I was wondering if it had to do something with done()
, but still even by calling it in my callback, no success. Did I miss something?
- assert.throws is not going to work for exceptions that are raised asynchronously. – Ankur Anand Commented May 1, 2017 at 14:25
3 Answers
Reset to default 3This is all pretty simple down to 3-4 lines of code if we remove ments. You just have to follow the specific pattern I have presented below.
it('Should throw error from an asynchronous function', async function() {
try {
await someAsycnFunction();
/**
* The next line forces the test fail in case someAsyncFucntion() does not throw.
*/
assert.fail('The expected Error was not thrown.');
} catch (err) {
/**
* (optional) Here we assert the error object prototype name for the cases when we
* want to check the error type is the expected one (e.g. we have
* extended the base JS exception to make our own exception).
*/
assert.typeOf(err, 'Error', 'someAsycnFunction did not throw expected error.');
/**
* (optional) Here we assert that the error message is the expected one.
*/
assert.include(err.message, 'ExpectedErrorMessage', 'someAsycnFunction error message does not match the expected one.');
/**
* (optional) Here we re-throw the caught error to assert it includes the
* expected error message substring (as a regex).
*/
assert.throws(() => {
throw err;
}, Error, /ExpectedErrorMessage/);
}
});
The most basic implementation may include only one assertion of your choice in the catch
block. The key for this approach is to wrap the throwing async function in try/catch
and forcefully fail the test in the try
block.
This is the correct code
var fn = function(){
parse.getMetadatas('test/test_incorrect.md', function (err, metas) {
if (err) throw err
})
}
assert.throws( function() { fn() }, Error )
The message
AssertionError: Missing expected exception (Error)..
says that the wrong type of exception was thrown. You don't say which assert you are using, but presumably the 'Error' in the assert.throws specifies what type of exception is expected. You need to change it to match the actual exception that is thrown.
I suppose it is also possible that the message is saying that no exception was actually thrown. You'll need to check the documentation for your library or write a simple test to check what is wrong.
I managed to get it to work by improving David Norman's answer. As I stated in my question, my test lacked the done()
call, but even if I was calling it after the throw err
, I was having a timeout exception with Mocha. Anyway, this is the code snippet I used for the test of another asynchronous method I wrote, and it pass and does not get a timeout error:
var fn = function () {
fs.rmrf(path.join(pathDir, 'non', 'existing'), function (err) {
done()
assert.ifError(err)
})
}
assert.throws(function () { fn() } , /No directory/)
Where /No directory/
matches the text description of the Error being thrown in fn
's callback. It could be Error
but I wanted to be sure of wich error assert.throws
was detecting.