Search code examples
typescriptmongoosejestjs

Mongoose find does not return documents in jest test


I want to test that a NestJS application writes a certain amount of documents to the database using an E2E test approach where my jest tests execute some HTTP requests against the application running in docker and then fetch the mongoDB documents and verify the amount of documents.

But my mongoose model always returns an empty array when executing find({})

I checked the collection with mongoDB compass and it does in fact contain the documents.

I have no idea what could be wrong. The schema imported from the application code where it is defined as follows

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type MyDocument = MyData & Document;

@Schema({timestamps: true, autoIndex:false, collection: 'my_documents'})
export class MyData {
    @Prop({ required: true })
    message: string;
}

export const MySchema = SchemaFactory.createForClass(MyData);

This is the test code:

import { MyData, MySchema } from 'apps/api/src/app/schema';
import axios from 'axios';
import { connect, model } from 'mongoose';
import { resetDb, sleep } from '../support/helpers';

describe('Post twice, then get', () => {
  beforeEach(async () => {
    await resetDb();
    // let things settle
    await sleep(10000);
  });

  it('should return two messages', async () => {
    const deleteResult = await axios.delete('/');
    expect(deleteResult.status).toBe(200);
    const post1 = await axios.post('/', { message: 'Hello' });
    expect(post1.status).toBe(201);
    const post2 = await axios.post('/', { message: 'Hello2' });
    expect(post2.status).toBe(201);

    const res = await axios.get('/');

    expect(res.status).toBe(200);
    await connect(process.env.MONGODB_URI);
    const myModel = model<MyData>('MyData', MySchema);
    const documents = await myModel.find({});
    console.log(documents);
    expect(documents.length).toBe(2);
  });
});

I created a minimal reproducible repository that is based on an nx monorepo: https://github.com/CodingSpiderFox/nx-neste2e-mcve

To reproduce the issue that keeps api.spec.ts from succeeding, it should be enough to run the example with the command npx nx e2e api-e2e from the root of the repository. The target will automatically run a script that builds and dockerizes the applications and start the mongodb and application containers via docker compose from the jest global setup defined in apps/api-e2e/src/support/global-setup.ts


Solution

  • Fixed the problem in https://github.com/CodingSpiderFox/nx-neste2e-mcve/commit/511766b195e850c427114ef1d39310a597143e91 It seems that the problem was that the connection was not using the logical "api" db.

    However, I had already tried to run mongoose.connection.useDb('api') before executing the query which didn't work either. Then I realized that "useDb" seems to return a new connection. I thought that "useDb" function would change the active database for the entire mongoose Object.

    So the actual fix was:

    • Acquire new connection to the correct logical DB with useDb()
    • create the model on the new connection. Then it works.

    I find this aspect of the mongoose API extremely counter intuitive.

    When using MSSQL Server, IIRC, the USE "dbname" command changed the active DB directly on the active connection without creating a new connection.