common mistake labelnode node_modules/.bin/mocha --version(Local) and mocha --version(Global). We recommend avoiding the use of globally installed Mocha.I am testing an nodejs-app with a server and a client component on nodejs 8.9.0 with mocha 4.0.1 and chai 4.1.2.
For mocha to end properly, I have to make sure that all socketio and http-servers are closed after the tests have been run. This works fine with normal tests, but as soon as I register a middleware to the socketio-server, the mocha-process won't close and stay open forever.
copy into a minimal test-file:
// test.spec.js
'use strict'
const Express = require('express')
const Http = require('http')
const io = require('socket.io')
const ioclient = require('socket.io-client')
const NODE_PORT = process.env.NODE_PORT || 3000
describe('Client', function () {
beforeEach(() => {
const express = new Express()
this._http = Http.Server(express)
this._socketio = io(this._http)
this._http.listen(NODE_PORT)
})
// this test works perfectly, even when I copy it and run it
// multiple times in this suite
it('should connect to a socketio-server', (done) => {
const client = ioclient.connect(`http://localhost:${NODE_PORT}`)
this._socketio.on('connection', () => {
client.close()
done()
})
})
// this test also finished, but the suite hangs afterwards - as if
// a socket-client or socket-server was not closed properly.
it('should finish the test suite even with a middleware', (done) => {
const client = ioclient.connect(`http://localhost:${NODE_PORT}`)
this._socketio.use((socket, next) => {
return next()
})
this._socketio.on('connection', () => {
client.close()
done()
})
})
afterEach(() => {
this._socketio.close()
this._http.close()
})
})
Install dependencies: npm i [email protected] [email protected] [email protected] [email protected]
Run the Testfile: npx mocha test.spec.js
Expected behavior: [What you expect to happen]
All tests to run, and mocha exiting properly
Actual behavior: [What actually happens]
All tests run, mocha does not exit
Reproduces how often: [What percentage of the time does it reproduce?]
100%
see above
Note: This is a cross-post from https://stackoverflow.com/q/47094615/898999
So, the problem was, that the server closed the client connection on a successful connection event. The client did not get any information on that, but instead saw a failed connection and tried to reconnect. This opened a socket to the server again and because the server was already closed, the connection error kept coming.
This behavior stopped node from properly destroying all objects, which in turn explaines the hanging. The solution is to call done() only after the client has declared a connection open, not after the server has declared a connection open like so:
'use strict'
const Express = require('express')
const Http = require('http')
const ioserver = require('socket.io')
const ioclient = require('socket.io-client')
const NODE_PORT = process.env.NODE_PORT || 3000
describe('Client', function () {
beforeEach(() => {
const express = new Express()
this._http = Http.Server(express)
this._ioserver = ioserver(this._http)
this._http.listen(NODE_PORT)
this._client = null
})
it('should connect to a socketio-server', (done) => {
this._ioserver.on('connection', () => {
done()
})
this._client = ioclient.connect(`http://localhost:${NODE_PORT}`)
})
it('should finish the test suite even with a middleware', (done) => {
this._ioserver.use((socket, next) => {
return next()
})
this._client = ioclient.connect(`http://localhost:${NODE_PORT}`)
// if we wait for the server and kill the server socket,
// the client will try to reconnect and won't be killed
// by mocha.
this._client.on('connect', () => {
done()
})
})
afterEach(() => {
// this last call forces the client to stop connecting
// even if tests failed
this._client.close()
this._ioserver.close()
this._http.close()
})
})
Most helpful comment
So, the problem was, that the server closed the client connection on a successful connection event. The client did not get any information on that, but instead saw a failed connection and tried to reconnect. This opened a socket to the server again and because the server was already closed, the connection error kept coming.
This behavior stopped node from properly destroying all objects, which in turn explaines the hanging. The solution is to call
done()only after the client has declared a connection open, not after the server has declared a connection open like so: