Jest: test is not exiting unless 'done' parameter is passed to afterAll() without being explicitly called

Created on 2 Oct 2018  ·  2Comments  ·  Source: facebook/jest

🐛 Bug Report

I've been trying for the last 2 days to figure out why the test is not existing despite following all the steps with no luck until by accident I left the 'done' parameter in afterAll() without actually explicitly calling it from inside. like this: afterAll((done)=>{ mongoose.disconnect() }). This made it exit and work properly but when I explicitly call donefrom the function using promises (async/await or then) or as a callback to mongoose.disconnect() such as afterAll(async (done)=> { await mongoose.disconnect(); done()})it does not exit and keeps hanging. when using --detectOpenHandles it tells me that app.listen(3001) is the potential open handler which I explicitly closed. I can't figure if this is a problem in my code or a bug. The way I was able to fix the problem above by passing done param without using it seemed more of a hack (or bug) than a real solution. is done supposed to do anything if it is passed only(without being called)?

To Reproduce

`` const request = require('supertest');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/debugging');
const app = require('../app');
let server = '';

describe('GET /products/:name', ()=>{

beforeEach(()=> { server = app.listen(3001)})
afterEach(()=> { server.close() })
// afterEach((done)=> { server.close(done) })  <-- this does not work also
afterAll((done) => { 
   mongoose.disconnect();
//  done();                    <--- does not work even when using await on mongoose  
// mongoose.disconnect(done);  <--- does not work also
})

it('should return a 404 status', async ()=>{
    const res = await request(server).get('/name');
    expect(res.status).toBe(404); 
})

})


when I explicitly call done() in afterAll I get this:

Jest has detected the following 1 open handle potentially keeping Jest from exiting:

● TCPSERVERWRAP

   8 |
   9 |
> 10 |     beforeEach(()=> { server = app.listen(3001)})
     |                                    ^
  11 |     afterEach(()=> { server.close() })
  12 |     // afterEach((done)=> { server.close(done) })  <-- this does not work also
  13 |     afterAll((done) => {

  at Function.listen (node_modules/express/lib/application.js:618:24)
  at Object.listen (tests/routes.test.js:10:36)

```

Expected behavior

To be able to exit process when calling done after disconnecting from server and db.

Link to repl or repo (highly encouraged)

to reproduce behaivor here is a sample rep here. note that the sample I provide is a working. Just try to call done using any method and the test will hang. also try removing the done param from afterAll() and the test will also hang.

Bug

Most helpful comment

Hey @tito300 this is happening because mongoose.disconnect() is a promise and you need to wait until the disconnect promise is resolved. It looks like you tried this a few ways but none of them were correct.

What did work (providing the done arguments without calling) only works because it's basically forcing Jest to wait for a done that is never called, so the open handle detection never runs

Here's why a few of your attempts were wrong:

This will call done before the promise resolves (i.e. before it's done)

afterAll((done) => { 
    mongoose.disconnect(); // 1 - start the disconnect
    done();  // 2 - call done
    // 3 - sometime later the disconnect actually happens
})

This will pass done to disconnect, which would work if disconnect accepted a callback (it does not)

afterAll((done) => { 
    mongoose.disconnect(done); 
})

Two ways that should work are:

// pass done to .then
afterAll(done => { 
    mongoose.disconnect().then(done); 
})

// return the promise
afterAll(() => { 
    return mongoose.disconnect();
})

Give these a try and let me know if they work!

All 2 comments

Hey @tito300 this is happening because mongoose.disconnect() is a promise and you need to wait until the disconnect promise is resolved. It looks like you tried this a few ways but none of them were correct.

What did work (providing the done arguments without calling) only works because it's basically forcing Jest to wait for a done that is never called, so the open handle detection never runs

Here's why a few of your attempts were wrong:

This will call done before the promise resolves (i.e. before it's done)

afterAll((done) => { 
    mongoose.disconnect(); // 1 - start the disconnect
    done();  // 2 - call done
    // 3 - sometime later the disconnect actually happens
})

This will pass done to disconnect, which would work if disconnect accepted a callback (it does not)

afterAll((done) => { 
    mongoose.disconnect(done); 
})

Two ways that should work are:

// pass done to .then
afterAll(done => { 
    mongoose.disconnect().then(done); 
})

// return the promise
afterAll(() => { 
    return mongoose.disconnect();
})

Give these a try and let me know if they work!

Same issue here. The async handlings proposed by @rickhanlonii did not work :(

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jardakotesovec picture jardakotesovec  ·  3Comments

gustavjf picture gustavjf  ·  3Comments

paularmstrong picture paularmstrong  ·  3Comments

withinboredom picture withinboredom  ·  3Comments

StephanBijzitter picture StephanBijzitter  ·  3Comments