Dycey
Dycey

Reputation: 4705

How do I fix an "open handles" error in a Jest DB fixtures function?

I'm writing some Jest tests for a node/postgres web app.

Here's the fixtures helper file:

/*eslint no-console: ["error", { allow: ["warn", "error"] }]*/
const exec = require('child_process').exec;
const create_sql = 'bin/sql/tables_setup.sql';

function prepare_db(){ //eslint-disable-line no-unused-vars
  exec(
    'PGPASSWORD="node_password" createdb -U node_user testdb; exit 0',
    function(err) {
      if (err !== null) {
        console.error('Error creating db: ' + err);
      }
      exec(
        `PGPASSWORD="node_password" psql -U node_user -d testdb -f ${create_sql}; exit 0`,
        function(err){
          if (err !== null) {
            console.error('Error populating db: ' + err);
          }
        }
      );
    }
  );
}

function clean_db(){ //eslint-disable-line no-unused-vars
  exec(
    'PGPASSWORD="node_password" dropdb -U node_user testdb; exit 0',
    function(err){
      if (err !== null) {
        console.error('Error dropping db: ' + err );
      }
    }
  );
}

module.exports = { prepare_db, clean_db };

... and here's the test file ...

const app = require('../app');
const request = require('supertest');
const { prepare_db, clean_db } = require('./helpers/dbtool');

describe('GET /requests', () => {
  beforeEach( async () => {
    await prepare_db();
  });

  it('retrieves no details on empty database', async done => {
    const response = await request(app).get('/requests');
    expect(response.status).toBe(200);
    expect(JSON.stringify(response.body)).toBe('[]');
    done();
  });

  afterEach( async () => {
    await clean_db();
  });
});

The test is passing (ho ho), but I get the customary Jest has detected the following 2 open handles potentially keeping Jest from exiting error. I'm using jest --runInBand --detectOpenHandles test to run the tests.

I've tried adding a {timeout: 500} option when calling the exec, but no luck. I tried altering the signatures of prepare_db() and clean_db(), passing in done() as a callback, and calling done() after the exec. Again, no luck (done() undefined :-( ).

Am I missing some additional call to terminate the exec somehow to fix this? Are my async/awaits out of whack?

Upvotes: 1

Views: 626

Answers (1)

Dycey
Dycey

Reputation: 4705

D'oh!

See In node.js, how to use child_process.exec so all can happen asynchronously?

Simply needed to change exec instantiation in the helper file...

const util = require('util');
const exec = util.promisify(require('child_process').exec);

Upvotes: 1

Related Questions