I have a simple async callback test that I've set up with mocha
:
describe('test', function () {
it('should not work', function(done) {
client.on('success', function () {
return done('client saw success message but should have errored');
});
client.on('error', function (err) {
return done();
});
});
});
The idea is that the client does some async operation and should receive an error event. If it receives anything else, then the test should fail.
Unfortunately, mocha
keeps complaining:
done() called multiple times
I've done all sorts of things to verify that this is not true. For example, I've tried throwing an error before the done
in the success handler, logging when control reaches the success handler, etc.
How can I get this test to run without telling me I'm calling done
twice? I would throw an error instead of calling done
with an error message, but that would cause the test to fail with a timeout instead of the error I want.
Your tests are failing because you are still listening for events after the test is finished.
A completed test doesn't automatically remove the event listeners.
On your next test you are firing the event again but previous test event
listeners are called again since they are still listening for the event.
Since done
was already called on them when that test completed,
they fire again hence you get the error that done was called multiple times
.
Couple of options here:
once
listener.describe('test', () => {
it('should work', done => {
const finish = err => {
done(err)
client.removeListener('success', finish)
client.removeListener('error', finish)
}
client.on('error', finish)
client.on('success', result => {
result.should.equal('foo')
// rest of tests for result...
finish()
})
client.fireEvent()
})
})
Note that you might need to use off
or removeEventListener
instead of removeListener
- whichever method your client
uses to remove a listener.
once
listener:
Alternatively, you can use the once
listener to listen for events. Like the name suggests, this handler fires only once so there's no need to manually remove listeners afterwards.
describe('test', function () {
it('should work', done => {
client.once('error', done)
client.once('success', result => {
result.should.equal('foo')
// rest of tests for result...
done()
})
client.fireEvent()
})
})
Warning: These methods have an important caveat. They don't allow you to test the edge case on whether your client
actually fires the event just once. If client
erroneously fires success
more than once your test would erroneously succeed as well. I'm not sure how you can handle this gracefully at this time but comments are welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With