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

83 Views Asked by At

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.

1

There are 1 best solutions below

0
Alfred Doh-Nani On BEST ANSWER

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.