jestjsnestjsnestnode.js-typeormnestjs-typeorm

Nestjs/Jest Is there a way to override Module in imported Module in e2e test


Im writing an e2e test for my api. To implement e2e test i have to use AppModule in imports when creating TestingModule:

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    })
...

The problem is that AppModule has import TypeOrmModule.forRootAsync({useFactory: getTypeOrmConfig, dataSourceFactory: getDataSource, }), where getTypeOrmConfig gets config from variable environment. But in test i am mocking services and i dont need to have db connection.

Im looking for a way to override this module with another configuration, that is for e2e tests only.

Change variables in .env doesnt fits, because integration tests are working with live database, and i dont want to download different .env in my CI for running different kinds of tests.

I have tried overrideModule:

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    })
      .overrideModule(
        TypeOrmModule.forRoot({}), || TypeOrmModule || TypeOrmModule.forRootAsync({})
      )
      .useModule(
        TypeOrmModule.forRoot({
          type: "sqlite",
          database: "./test/database-mock/db",
        }),
      )
...

But it doesnt work - app still tries to connect to the live database.

Is there a way to override imported module in AppModule while creating TestModule? We can override providers in imported modules inside AppModule, im looking for method to do this but with imported module.


Solution

  • While configuring TypeOrmModule, I intentionally use process.env instead of the configService to get my environment variables.

    TypeOrmModule.forRootAsync({
          useFactory: () => {
            //N.B: I use process.env here instead of configService.get
            // because of e2e tests. process.env can be mutated and updated
            // with connection details for a testcontainer database
            return {
              type: 'postgres' as const,
              host: process.env.DB_HOST,
              port: +process.env.DB_PORT,
              applicationName: 'app',
              username: process.env.DB_USERNAME,
              password: process.env.DB_PASSWORD,
              database: process.env.DB_NAME,
              autoLoadEntities: true,
              synchronize: IS_DEV,
              logging: false,
            };
          },
        });
    

    This is because I use testcontainers for my e2e tests and I mutate the process.env object in the beforeAll hook of my test.

    postgreSqlContainer = await new PostgreSqlContainer()
          .withName('testcontainer')
          .withDatabase('testcontainer')
          .start();
    
        //update database enviroment variables in order for typeorm to connect       enter code hereto the testcontainer DB
    
        process.env.DB_HOST = postgreSqlContainer.getHost();
        process.env.DB_PORT = postgreSqlContainer.getPort().toString();
        process.env.DB_USERNAME = postgreSqlContainer.getUsername();
        process.env.DB_PASSWORD = postgreSqlContainer.getPassword();
        process.env.DB_NAME = postgreSqlContainer.getDatabase();
    
        const moduleFixture: TestingModule = await Test.createTestingModule({
          imports: [AppModule],
        }).compile();
        app = moduleFixture.createNestApplication();
        await app.init();
        server = request(app.getHttpServer());
    

    This allows me to change the database connection credentials at runtime before the tests run.