Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setup mongoose connection in custom Jest test environment

I'm trying to setup a custom Jest test environment where I can connect to the database once before tests start running and disconnect from it after all tests finish. I would like to avoid using helper functions in beforeAll() and afterAll() hooks in every test file. Below is how my current setup looks like. When I run the test it is failing due to readyState being 0 which stands for disconnected. What am I missing?

jest.config.js

module.exports = {
    testEnvironment: './mongo-environment'
}

mongo-environment.js

const mongoose = require('mongoose')
const NodeEnvironment = require('jest-environment-node')

class MongoEnvironment extends NodeEnvironment {
  constructor (config) {
    super(config)
  }

  async setup () {
    await this.setupMongo()
    await super.setup()
  }

  async teardown () {
    await this.teardownMongo()
    await super.teardown()
  }

  runScript (script) {
    return super.runScript(script)
  }

  setupMongo () {
    return new Promise((resolve, reject) => {
      mongoose.connect('mongodb://localhost/test')
        .then(mongoose => {
          const db = mongoose.connection

          Promise
            .all(Object.keys(db.collections).map(name => db.dropCollection(name)))
            .then(resolve)
            .catch(reject)
        })
        .catch(reject)
    })
  }

  teardownMongo () {
    return mongoose.disconnect()
  }
}

module.exports = MongoEnvironment

example.spec.js

const mongoose = require('mongoose')

describe('test', () => {
  it('connection', () => {
    expect(mongoose.connection.readyState).toBe(1)
  })
})
like image 698
katranci Avatar asked Nov 18 '22 17:11

katranci


1 Answers

I have got this to work using combination of setupFilesAfterEnv and testEnvironment and global object.

Setup your DB connection and store the URL in the global object in your custom-environment.js : ( please refer Jest doc for deets )

// my-custom-environment
const NodeEnvironment = require('jest-environment-node');
const { MongoMemoryServer } = require('mongodb-memory-server');

class CustomEnvironment extends NodeEnvironment {
  constructor(config, context) {
    super(config, context);
    this.testPath = context.testPath;
    this.docblockPragmas = context.docblockPragmas;
    this.db = {}
  }

  async setup() {
    await super.setup();
    this.db = await MongoMemoryServer.create()
    this.global.MONGO_URI = this.db.getUri()
  }

  async teardown() {   
    await this.db.stop()
    await super.teardown();
  }

  getVmContext() {
    return super.getVmContext();
  }

}

module.exports = CustomEnvironment;

In your setup file that you will run after environment has been setup, configure your mongoose to connect to the global URI that you set previously.

jest.config.js :

module.exports = {
setupFilesAfterEnv : ['./setup-unitTest-db.js']
}

setup-unitTest-db.js :

 require('dotenv').config();

const mongoose = require('mongoose');

const mongooseConfig = { useNewUrlParser: true, domainsEnabled: true, useUnifiedTopology: true  }

mongoose
    .connect( global.MONGO_URI, mongooseConfig)
    .then(() => {
        mongoose.set('useFindAndModify', false)
    })

afterAll (async () => {
    await mongoose.connection.dropDatabase();
    await mongoose.connection.close();
})

And finally, tell Jest to use your custom test environment file by providing the complete path to your environment file by adding the docblock on top of your test file thusly :

// this goes in your test suite
/**
 * @jest-environment ./nodeWithMongo
 */
like image 136
Souparno Avatar answered Nov 24 '22 00:11

Souparno