I am looking for a correct way to completely reset my express server between tests! It seems that this is not just a problem for me, many other users have asked the same question, and many blog posts had been written on the argument. The proposed solutions are not working nor satisfactory for me. Here there is another similar question and an article that well describes the problem and suggests some solutions:
Stack overflow Closing an express server after running jasmine specs
Blog: https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/
Here a package is specifically created to solve this problem: https://www.npmjs.com/package/server-destroy
Now, a minimal working example to reproduce my condition. In the code under test, an express server is created; when called on some endpoint, the server increments a value and returns it:
( function() {
'use strict'
const enableDestroy = require( 'server-destroy' )
const app = require( 'express' )()
const http = require( 'http' )
let val = 0
app.use( '/inc', (req, res) => {
val ++
res.send(val.toString())
} )
const server = http.createServer( app )
server.listen( 3000 )
enableDestroy(server);
module.exports = server
} )()
The test consists in two identical test cases; both of them call the server on the endpoint, and check the returned value.
before_each
and after_each
sections are provided in order to assure a new connection is created before the single test case is run, and then closed, to assure independence between the two test cases:
const chai = require( 'chai' )
const chaiHttp = require( 'chai-http' )
const expect = chai.expect
chai.use( chaiHttp )
let server
describe( 'first test group', () => {
beforeEach( () => {
server = require( './server' )
} ),
afterEach( ( done ) => {
server.destroy( done )
delete require.cache[require.resolve( './server' )]
} ),
it( 'should respond 1', ( done ) => {
chai.request( server )
.get( '/inc' )
.set( 'Connection', 'close' )
.end( ( err, res ) => {
expect( res.text ).to.be.equal( '1' )
done()
} )
} ),
it( 'should respond 1', ( done ) => {
chai.request( server )
.get( '/inc' )
.set( 'Connection', 'close' )
.end( ( err, res ) => {
expect( res.text ).to.be.equal( '1' )
done()
} )
} )
} )
The test fails because the server is not running after the first test. Please note that in the after_each
section I forced a cache cleaning for lost completely the last server instance. The test succeeds if a single test case is run:
first test group
✓ should respond 1
1) "after each" hook for "should respond 1"
1 passing (70ms)
1 failing
1) first test group
"after each" hook for "should respond 1":
Error: Not running
at Server.close (net.js:1620:12)
at emitCloseNT (net.js:1671:8)
at _combinedTickCallback (internal/process/next_tick.js:135:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
The configuration I used:
How can I solve this problem? And what does the error message mean?
It works with a little modification
I didn't use server-destroy
since server.close
works just fine
server.js
// ( function() { // no need for this
'use strict'
//const enableDestroy = require( 'server-destroy' )
const app = require( 'express' )()
const http = require( 'http' )
let val = 0
app.use( '/inc', (req, res) => {
val ++
res.send(val.toString())
} )
const server = http.createServer( app )
server.listen( 3000 )
// enableDestroy(server);
module.exports = server
// } )()
test.js
const chai = require( 'chai' )
const chaiHttp = require( 'chai-http' )
const expect = chai.expect
chai.use( chaiHttp )
let server
describe( 'first test group', () => {
beforeEach( () => {
server = require( './server' )
} ),
afterEach( ( done ) => {
// UPDATE DON'T CLOSE THE SERVER
delete require.cache[require.resolve( './server' )]
done()
//server.close( () => {
// delete require.cache[require.resolve( './server' )]
// done()
//})
} ),
it( 'should respond 1', ( done ) => {
chai.request( server )
.get( '/inc' )
.set( 'Connection', 'close' )
.end( ( err, res ) => {
expect( res.text ).to.be.equal( '1' )
done()
} )
} ),
it( 'should respond 1', ( done ) => {
chai.request( server )
.get( '/inc' )
.set( 'Connection', 'close' )
.end( ( err, res ) => {
expect( res.text ).to.be.equal( '1' )
done()
} )
} )
} )