I have some tests which bind to a UDP port, e.g.
describe('the server', function() {
it('should respond to a udp packet', function(done) {
const udp = dgram.createSocket('udp4');
udp.on('error', function(error) {
console.log(error);
});
udp.on('message', function(msg, rinfo) {
console.log('msg', msg);
console.log('rinfo', rinfo);
// TODO: check the reply
udp.close();
done();
});
udp.bind();
// send a request
const bytes = Buffer.from("421a0800117860bc457f0100001a0653455256455222054d54303031", 'hex');
udp.send(bytes, SERVER_PORT, SERVER_ADDR)
});
});
When the test completes successfully, that code path can call udp.close()
which lets mocha exit.
When a test exceeds mocha's 2 second time-out, I see the error but mocha does not exit as the UDP port is still listening.
Is there some form of callback/event that I can use to close a listening UDP socket when mocha's 2 second time-out fires?
This can be achieved with an afterEach
hook. An afterEach
hook is a function that gets executed after each test, whether passed or failed (but not skipped). So it is useful to perform cleanup operations, like closing a socket in this case.
Like all Mocha hooks, an afterEach
is defined inside a describe
function call, and it applies to all tests in that scope. If you only want the hook to run after one particular test only, put that test into a dedicated describe
function.
So the changes to do here are the following:
udp
from the it
function into the containing describe
function. This will make udp
accesible from both it
and afterEach
.afterEach
hook to perform the cleanup operation: udp.close();
. Remember that this will run whether the test passes or fails for any reason, so it's a good idea to avoid assumptions about the progress of the test. Here: don't assume that udp
has been already created.udp.close();
, these are no longer needed now.describe('the server', function() {
let udp;
afterEach(() => {
if (udp) {
udp.close();
udp = undefined;
}
});
it('should respond to a udp packet', function(done) {
udp = dgram.createSocket('udp4');
udp.on('error', function(error) {
console.log(error);
});
udp.on('message', function(msg, rinfo) {
console.log('msg', msg);
console.log('rinfo', rinfo);
// TODO: check the reply
done();
});
udp.bind();
// send a request
const bytes = Buffer.from("421a0800117860bc457f0100001a0653455256455222054d54303031", 'hex');
udp.send(bytes, SERVER_PORT, SERVER_ADDR)
});
});
One thing to note is that in case of a timeout, the test function may keep running after the socket has been closed, producing all kinds of baffling error messages: this is not surprising.
Another interesting thing to note is that variables scoped in a describe
function call (unlike those in an it
function call) have the same lifetime of the Mocha run. For this reason it is a common practice to create those variable lazily when needed (in the tests) and to clear up manually by setting them explicitly to undefined
or null
as soon as they are no longer needed.