how do I close pg-promise connection in node.js after all tests have run in jest?
Asked Answered
T

2

7

I need to close a PG-Promise database connection after testing a function in Jest.

This is initialised in one place(db.js) and required everywhere it is needed. In the case of the code below, it is required by seed.js which seed.spec.js is testing.

I know there is an afterAll hook in Jest, but that will close the connection everywhere which might cause tests to fail incorrectly?

The problem is solved with the --forceExit option, but it gives an error message and doesn't feel like the right way to solve this?

db.js:

const pgp = require('pg-promise')();
const db = pgp(connection);

module.exports = {db, pgp};

seed.spec.js:

require('dotenv').config();
const {pgp} = require('./db');

expect.extend(require('jest-json-schema').matchers);

const schema = require('./schemas');
const generate = require('./generate');
const seed = require('./seed');
const data = generate();

test ('the data returned by the seed function matches the schema', () => {
  return seed(data)
    .then(outputData => {
      expect(outputData).toMatch(schema);
    });
});

P.S. I have seen similar questions, but none of them quite matches my situation.

Thoer answered 20/8, 2018 at 1:36 Comment(7)
but that will close the connection everywhere which might cause tests to fail incorrectly - I'm not sure what you mean. It will close the connection in current suite. This is necessary for the runner to exit normally.Procurator
@estus okay so I get this, but problem is that there is only one connection opened in one place at first. To do it this way I'd really need to open a new connection for each teat suite and then close it at the end and then make all the tests run synchronously... What I could really do with is some sort of afterAllTestSuites() hookThoer
You have got Jest conception wrong. Each file is a different suite. They run as different processes in parallel. So there are several database connections. afterAll does what it says.Procurator
@estus thanks, I get that now - problem is that pg-promise works by making one connection to the database (I think under the hood it may do several, managed ones) and importing that. So I do need a hook that runs after all suites. Luckily I've found one, so am going to make an answer. Thanks for your help(which would have been perfect in other situations!)Thoer
I don't use pg-promise but I believe that it isn't any different than any other DB adapter that maintains a pool of connections. one connection to the database - it's one connection (pool) per process. Jest spawns several processes and there are several pg-promise instances. They don't know of each other, unless they maintain common pool in a database - and I'm quite sure they don't. Did afterAll fail for you? Because I'd expect it to be proper solution here. On the other hand, globalTeardown may not work because it's unaware of other pg-promise module instances.Procurator
yep afterAll didn't work - it was stuck waiting for the connection to time out. if it doesn't work out, I'll delete my answer:)Thoer
actually... it seems to be not working again now, I'm not sure why! Am going to try making a new instance in each test file as you suggestThoer
P
8

As with any other database, the connection should be closed in afterAll.

As the reference states, it's either pgp.end() or db.$pool.end():

afterAll(db.$pool.end);

UPDATE

From pg-promise v10.11.0, you no longer need to shut down the pool explicitely. Instead, you can just set connection option allowExitOnIdle: true, to let process exit when pool is idle.

Procurator answered 20/8, 2018 at 3:59 Comment(2)
Do I need to do this on every spec file, or is there a way to set this globally?Harrell
There's a way to do things globally, jestjs.io/docs/en/configuration#setupfiles-array . It doesn't apply well to this case because there's no shared context between setup files and specs, db connection needs to be exposed as global var. Not every test suite may involve db so doing this in every spec file may be better. In this specific case things can be made DRY by creating test helper module that wraps around db.js and adds respective afterAll and using it instead of db.js.Procurator
V
1

The closest solution I found to this was using the setupFilesAfterEnv Jest configuration option.

// jest.config.js
module.exports = {
    setupFilesAfterEnv: ['./jest/setup/afterAll']
}

// afterAll.js (path: ./jest/setup/afterAll.js)
const { db } = require('../../src/db')

afterAll(db.$pool.end)
Vegetative answered 25/10, 2020 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.