How to override an imported module in nestjs testing?

7.2k Views Asked by At

I'm quite new on nestjs, met an issue regarding how to override the load function of ConfigModule, hope someone can help me out, thanks in advance!

My e2e testing:

const moduleForTesting = await Test.createTestingModule({imports: [AppModule]});

My App Module:

import config from './config/index'

@Module({
  imports: [ConfigModule.forRoot({isGlobal: true, load: [config]})]
})

My config/index file:

export default async () => {
  someConfigs: ...
}

Now I want the e2e testings use another configurations, but I don't know how to override the AppModule, nor the load function:

// AppModule
import config from './config/index' // This is ok for production, but need to be overridden in testing

...
  imports: [ConfigModule.forRoot({isGlobal: true, load: [config]})]
4

There are 4 best solutions below

0
On BEST ANSWER

I don't know what is the elegant NestJs way to do that, but after a deep breath, I reconsidered what I really want to do and then found a hackie way to achieve that.

I need to mock the config file so that during testing, the load array will be mocked, where the jest.mock comes to the rescue:

// e2e testing file

jest.mock('../src/config/index', () => ({
    default: async () => ({
        someConfigs: 'mocked config'
    })
})) // <--- By putting the `jest.mock` before the `createTestingModule`, the `load` array will be mocked.

...
const moduleForTesting = await Test.createTestingModule({imports: [AppModule]});

2
On

See withModule method in TestModuleBuilder from @jbiskur/nestjs-test-utilities

NestJS feature request: https://github.com/nestjs/nest/issues/4905

0
On

Best way to override module import is by using TestingModuleBuilder method overrideModule, it works also for overrideGuard, overrideInterceptor, overrideProvider ...

So first put your config in const or var and export it

export const config = ConfigModule.forRoot({isGlobal: true, load: [config]});
@Module({
  imports: [
    config 
  ],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {
}

In your test create new config module

const testConfig = ConfigModule.forRoot({isGlobal: false, load: []});

const builder = Test.createTestingModule({
    imports: [AppModule]
});
const override = builder.overrideModule(config);
override.useModule(testConfig);
const moduleFixture = await builder.compile();
app = moduleFixture.createNestApplication();
await app.init();

In case of non DynamicModule use Type directly for example for OtherModule do

const builder = Test.createTestingModule({
    imports: [AppModule]
});
const override = builder.overrideModule(OtherModule);
override.useModule(TestOtherModule);
const moduleFixture = await builder.compile();
app = moduleFixture.createNestApplication();
await app.init();
0
On

You can use overridProvider

const moduleForTesting = await Test.createTestingModule({imports: [AppModule]}).overrideProvider(MyService).useValue(myServiceMock).compile()