Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest testing multiple test file port 3000 already in use

I'm creating a testing for my express app. The project has multiple test files. In each module the server instance is required at beforeEach() method and closed at afterEach() method. but after testing one or two of the modules it'll raise address already in use and jest won't terminate.

beforeEach(() =>  {

    server = require('./../../../bin/www')});
afterEach(async() => { 
    server.close();
    /**
     * database cleanup logic goes here.
     */

 });

I want jest to terminate after all the test suites are completed.

like image 931
btinsae Avatar asked Jan 29 '19 14:01

btinsae


6 Answers

Just runs test suites in parallel by default. However, the machine that the tests are running on only has a single port 3000 (or port 4000, etc.)

This means that if you tell your app to listen on a port, and then start multiple concurrent processes, there will be a port collision and Jest will exit with EADDRINUSE - port already in use.

Like some people already mentioned, you can solve the issue by running your tests in sequence with --runInBand. However, you will lose out on the performance benefits of parallelization.

There is another way... do not explicitly listen on a port when running tests.

if (process.env.NODE_ENV !== 'test') {
  app.listen(port, () => console.log(`Listening on port ${port}`)
}

Now, when you feed your app to supertest, it will run your app on port 0 since it's not already running on a port.

const app = require('../app')
const request = require('supertest')

it('gets todos', async () => {
  const response = await request(app).get('/todos')
  expect(response.body.length).toEqual(3)
}

What exactly is port 0 you ask? That is how you tell Unix machines...

Choose the first randomly available port that you find.

Now that each test suite is running on a randomly available port, there is no longer a risk of port collisions which means we've solved the EADDRINUSE - port already in use error and we can continue running tests in parallel.

like image 162
J. Munson Avatar answered Sep 29 '22 10:09

J. Munson


I had this issue, and seem to have solved it by setting jest to only use one worker. I think the issue was caused by more than one instance of the server running with the same port, thereby causing the clash.

This is the line from my npm package.json file. The --maxWorkers=1 seems to have done the trick (https://jestjs.io/docs/en/cli#maxworkers-num-string).

"scripts": {
  "test": "jest --forceExit --detectOpenHandles  --watchAll --maxWorkers=1"
},
like image 22
John Forbes Avatar answered Sep 29 '22 09:09

John Forbes


the very basic thing to do is to put your app.listen() inside some other file , other than your file that consists all the routes . for example : index.js

const express = require("express");
const app = express();
const bodyParser = require("body-parser");

app.use(bodyParser.json());

const students = ["Elie", "Matt", "Joel", "Michael"];

app.get("/", (req, res) => {
  return res.json(students);
});

module.exports = app;

and server.js

const app = require("./index");

app.listen(3000, () => console.log("server starting on port 3000!"));

In this way Jest will not be reading app.listen() at all . cheers !

like image 40
VicCoder0659 Avatar answered Sep 29 '22 08:09

VicCoder0659


I'm using, node express server 4.16.2. If you're using a different version this may not apply to you. In your describe block when you're closing the server, await for it.

describe('auth midleware', () => {
        // loading the server
        beforeEach(() => {>         
            server = require('../../../index')
        });

        // closing the server
        afterEach(async () => {
            await server.close();        
        });


        // the tests will go here
    });

Also after you do this, run your node application in the command line.

node index.js

Check your package.json, how your script test tag is named. Mine is test.

{ ...
      "scripts": {
        "test": "jest --verbose --coverage --forceExit --watchAll --maxWorkers=1"
      }
      ...
    }

After that run your test again.

npm test  
like image 29
Sergiu Mare Avatar answered Sep 29 '22 10:09

Sergiu Mare


There is also an option --runInBand to run tests one by one.

like image 28
Dmitry Skryabin Avatar answered Sep 29 '22 09:09

Dmitry Skryabin


server = require('./../../../bin/www')});
afterEach(async() => { 
   await server.close();

you just have make it await to close the server properly.

like image 45
Chamath Kavindya Avatar answered Sep 29 '22 08:09

Chamath Kavindya