typegoose / mongodb-memory-server

Manage & spin up mongodb server binaries with zero(or slight) configuration for tests.
https://typegoose.github.io/mongodb-memory-server/
MIT License
2.56k stars 185 forks source link

Jest + mongodb-memory-server + mongoose - Calling 'find' hangs indefinitely #840

Closed orelHunters closed 8 months ago

orelHunters commented 8 months ago

Versions

package: mongo-memory-server

What is the Problem?

I'm trying to add some tests to my node project using Jest + mongodb-memory-server (debug). I'm using globalSetup / globalTeardown for the initialization/destruction of the server and beforeAll/afterAll for connecting/disconnecting. I'm also able to see the server initializing and being connected to in the debug logs. I'm also doing a sample 'find' call within the context of 'beforeAll' after connecting and it works (returns empty).

However when the test itself reaches the part where it queries the Mongo it just hangs forever and doesn't produce any debug messages. This is very strange considering the same call just worked in the context of 'beforeAll' but doesn't work within the test while there isn't any debug output from the binary in between.

Code Example

jobs.test.ts

import mongoose from 'mongoose';
import { SomeMongoModel } from '../../src/db/models/some-mongo-model';
import { someJobLogic } from '../../src/jobs';

describe('Test jobs', () => {
  beforeAll(async () => {
    await mongoose.connect(process.env.MONGO_MOCK_URI);
    const testRows = await SomeMongoModel.find();
    console.log('test', { testRows }); // <- The query always works and testRows are []
  });
  afterAll(async () => {
    await mongoose.connection.close();
  });

  beforeEach(() => jest.useFakeTimers());
  afterEach(() => jest.useRealTimers());

  it('Some test', async () => {
    const { ok, res } = await someJobLogic();

    expect(ok).toBeTruthy();
    expect((res?.results || []).length).toBeGreaterThanOrEqual(1);
  }, 600000);
});

jobs.ts

import { SomeMongoModel } from '../db/models/some-mongo-model';

export const someJobLogic = async () => {
  const rows = await SomeMongoModel.find();
  console.info("Done") // <- Never reaches here
};

globalSetup.ts

import '../src/config/init';

import { MongoMemoryServer } from 'mongodb-memory-server';

module.exports = async () => {
  console.log('\nhello, this is just before tests start running');

  const instance = await MongoMemoryServer.create({
    instance: {
      dbName: 'test'
    }
  });
  const uri = instance.getUri();
  (global as any).__MONGOINSTANCE = instance;
  process.env.MONGO_MOCK_URI = `${uri}test`;
};

globalTeardown.ts

import '../src/config/init';

import { MongoMemoryServer } from 'mongodb-memory-server';

module.exports = async () => {
  console.log('\nhello, this is just after the tests finish running');

  const instance: MongoMemoryServer = (global as any).__MONGOINSTANCE;
  await instance.stop();
};

jest.config.ts

/** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */
const { pathsToModuleNameMapper } = require('ts-jest');
const { compilerOptions } = require('./tsconfig.base.json');

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
    prefix: '<rootDir>/'
  }),
  setupFiles: ['dotenv/config'],
  globalSetup: './tests/globalSetup.ts',
  globalTeardown: './tests/globalTeardown.ts',
  testTimeout: 120000,
  reporters: ['default', 'jest-junit'],
  testMatch: '**/*.test.ts',
  testPathIgnorePatterns: ['/node_modules/'],
  transformIgnorePatterns: ['/node_modules/']
};

Debug Output

link to logs

Do you know why it happenes?

no

hasezoey commented 8 months ago

it doesnt really make sense, but are the 2 model calls maybe on different connections / mongoose instances?

if that is not the case, does anything change if you remove the following?

beforeEach(() => jest.useFakeTimers()); afterEach(() => jest.useRealTimers());

also did you already try a higher mongoose version?

orelHunters commented 8 months ago

it doesnt really make sense, but are the 2 model calls maybe on different connections / mongoose instances?

if that is not the case, does anything change if you remove the following?

beforeEach(() => jest.useFakeTimers()); afterEach(() => jest.useRealTimers());

also did you already try a higher mongoose version?

OMG the issue was actually because of the fake timers... Not sure why it's the only thing I didn't try :/ It works now. TYSM!