I'm trying to test my websocket server, by opening a websocket client in my mocha test file, connection to the ws server and awaiting response. I send an http request to the ws server, and then a message is sent via websocket to the client, where I store the results and test it.
I get the response I want and the test passes, but the mocha test itself does not terminate and I'm forced to close it manually.
I have read this - explaining that there is probably still some async process open, such as an open socket, but I try to terminate the socket, and I get the 'close' event to fire (I get the console log message I defined in the 'close' event listener), but the test still isn't over.
I'm using ws (npm), mocha, chai (for asserts) and supertest (to invoke the server to send a response).
versions:
"ws": "^7.3.0",
"mocha": "^7.0.0",
"chai": "^4.2.0",
"supertest": "^4.0.2",
node: v12.9.1
I know I can use the --exit flag, as is suggested in this stack overflow answer, but I prefer not to, if it can be avoided.
Here is the relevant code:
'use strict';
const supertest = require('supertest');
const assert = require('chai').assert;
const paths = require('../common/paths');
const { sign } = require('../common/signing');
const WebSocket = require('ws');
describe.only('Events server tests', function () {
this.timeout(11000);
const docId = 'doc_events_' + Date.now();
const wsServerUrl = 'ws://localhost:8080/subscribe?params={"prefix_doc_id":"doc_events_"}';
const ws = new WebSocket(wsServerUrl);
let id_from_msg;
// Connection opened
ws.addEventListener('open', function (event) {
console.log('connection started!');
});
// Listen for messages
ws.addEventListener('message', function (event) {
console.log('\n\nMessage from server ', event.data, ' ', typeof event.data);
try {
// the msg recived via websocket is in the form of: "doc_id":X, and I store the docID in order to check if it matches the docId that was sent in the test.
if (event.data.includes('doc_id')) {
id_from_msg = JSON.parse(event.data).doc_id;
}
} catch (error) {
console.log('error: ', error);
}
});
ws.addEventListener('close', () => {
console.log('closed connection!');
});
before((done) => {
console.log('start');
done();
});
after((done) => {
ws.terminate();
// ws.close();
done();
console.log('after?');
});
it('Test 1 - send simple request to events server', (done) => {
const eventsUrl = paths.EVENTS.EVENTS();
const eventsObj = {
reqId: '',
docId: docId,
sessionId: 1,
status: 200
};
// This tests is used to invoke response from the socket server, and it works fine, the tests passes and ends without an issue.
supertest('http://localhost:3035')
.post(eventsUrl)
.set('Authorization', sign('post', eventsUrl, eventsObj))
.send(eventsObj)
.expect(200)
.expect(res => {
assert.ok(res.body);
assert.equal(id_from_msg, docId);
})
.end(done);
});
});
As you can see, I tried both ws.close() and ws.terminate() inside the "after" section, and both yield the same result: the test does not end, and the console.log('after?') line is fired after done() is called.
I tried to overwrite 'onclose' method and to fire in manually, but to no avail.
I tried also to close the websocket in the test itself (I mean in the 'it' section, even though I don't like it semantically) - but the test suit itself does not terminate, same as before.
Is there a way to make sure that the websocket is properly closed before done() is called in after?