Using a different database for tests
I'm trying to make use of an in-memory database (mongodb-memory-server) when running my tests, but I can't get it to work. I think that the fact that I'm requiring "loaders" when I create a server instance in the tests creates a mongoose connection with the actual database (mongoose.ts is one of the loaders). So I'm unable to connect with the test database.
I've gone through the "test-related" issues on this repo, and all of them seemed to make use of mocks, but I don't want to do that.
I'd appreciate any suggestions on how to resolve this---how to essentially, given this project structure, make use of a test database such as mongodb-memory-server.
Here's what my db-manager looks like - it houses the methods required to create the test DB.
import mongoose from "mongoose";
import { MongoMemoryServer } from "mongodb-memory-server"
let mongod: MongoMemoryServer;
async function createMongoDB() {
if (!mongod) {
mongod = await MongoMemoryServer.create({
binary: {
version: "5.0.8"
}
})
}
}
/**
* Connect to the in-memory database.
*/
const connect = async () => {
await createMongoDB()
const uri = mongod.getUri()
process.env.databaseURI = uri
const connection = mongoose.connect(uri, { dbName: "riteshop-test-db"});
return connection
}
/**
* Clear the in-memory database.
*/
const clear = async () => {
const collections = mongoose.connection.collections;
for (const key in collections) {
await collections[key].deleteMany({});
}
};
/**
* Disconnect from in-memory database.
*/
const disconnect = async () => {
await mongoose.connection.dropDatabase()
await mongoose.connection.close()
await mongod.stop()
}
export default { connect, clear, disconnect }
Also, here is what my test looks like
import request from "supertest"
import db from "../db-manager"
import config from "../../../src/config"
import express from "express"
describe("Health Check", () => {
const app = express()
beforeEach(async () => {
await db.connect()
// requiring the loaders is necessary because that's how the server is started normally
// but that also means the db connection in `src/loaders/mongoose` would be initialized/attempted.
// I don't want it attempted but it sorts of needs to be because the connection is needed by the dependency injector.
await require("../../../src/loaders").default({ expressApp: app})
app.listen(config.testPort)
})
afterEach(async () => {
await db.clear()
await db.disconnect()
})
describe('Endpoints availability', () => {
it('should return 404', async () => {
const res = await request(app).get('/api/nonexisting').send()
expect(res.status).toEqual(404)
})
})
})
UPDATE: A few mins later
What I do now, which seems to work, is to
- first, disconnect from the main db instance
- then connect to the test db instance
const app = express()
beforeEach(async () => {
await require("../../../src/loaders").default({ expressApp: app})
// disconecting from main DB
mongoose.connection.close()
// connecting to test DB
await db.connect()
app.listen(config.testPort)
})
I'm hoping there's a much neater way to go about it. Furthermore, I'm not sure if this approach is consequence-free as the instance I had to disconnect from is what was passed to the dependencyInjectorLoader, and subsequently, the agendaInstance as seen in the repo's source code.
Can't you use a different .env file for testing?