I'm currently taking over a backend written with NestJS, typeorm on Mysql and passport package for authentication. I'm currently trying to write both unit and e2e tests according to the NestJS documentation but I can't really make it work.
I've tried both importing the root AppModule or a single module. In the first case, it complains that it cannot connect to the database. I've overridden the configs provider for that, made it work on a testing Sqlite database, still passport module will raise an error saying that cannot access property challenge of undefined.
So, let's start with e2e testing, here is my app module:
imports: [
ConfigModule,
CoreModule,
Logger,
AuthModule,
TypeOrmModule.forRootAsync({
imports: [TypeOrmConfigService],
useClass: TypeOrmConfigService,
}),
UsersModule,
CoreModule,
DataModule,
InitializationModule,
TokensModule,
ProjectsModule,
ReportsModule,
AccountsModule,
NotificationModule,
FaqModule,
StrategicModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
and here is my e2e-spec file in which i override the config service to setup a temporary database:
class MockTypeOrmConfigService implements TypeOrmOptionsFactory {
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'sqlite' as any,
database: ':memory:',
synchronize: true,
dropSchema: true,
entities: [`../src/**/*.entity{.ts,.js}`],
};
}
}
const mockTypeOrmConfigService = new MockTypeOrmConfigService();
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(TypeOrmConfigService)
.useValue(mockTypeOrmConfigService)
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/faq (GET)', () => {
return request(app.getHttpServer())
.get('/faq')
.expect(200)
.expect('Hello World!');
});
});
this would actually work if only a big part of my schema definition is based on mysql fields (for example json, composite autoincrement and blobs). So my next tentative would be to use single controller modules to create the app and run e2e tests there. Let's say I have this controller:
@Controller('faq')
@UseGuards(AuthGuard())
@ApiBearerAuth()
export class FaqController {
constructor(private readonly faqService: FaqService) {}
@Get()
@ApiOkResponse({ type: FaqEntryDto, isArray: true })
async getAll(): Promise<FaqEntryDto[]> {
return this.faqService.findAll();
}
@Post()
@UseGuards(new RolesGuard(UserRole.Admin))
async create(@Body() body: FaqEntryDto) {
return this.faqService.create(body);
}
@Put('/:id')
@UseGuards(new RolesGuard(UserRole.Admin))
async update(
@Param('id', new ParseIntPipe()) id: number,
@Body() body: FaqEntryDto
) {
return this.faqService.update(id, body);
}
@Delete('/:id')
@UseGuards(new RolesGuard(UserRole.Admin))
async delete(@Param('id', new ParseIntPipe()) id: number) {
return this.faqService.delete(id);
}
}
and this my test (in which I also override the repository provider:
ntroller (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [FaqModule],
providers: [FaqService],
})
.overrideProvider(getRepositoryToken(FaqEntity))
.useValue({})
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/faq')
.expect(200)
.expect('Hello World!');
});
});
then, I would always get messages from the passport auth module, for instance:
[Nest] 4976 - 8/29/2019, 8:27:00 AM [ExceptionHandler] In order to use "defaultStrategy", please, ensure to import PassportModule in each place where AuthGuard() is being used. Otherwise, passport won't work correctly.
[Nest] 4976 - 8/29/2019, 8:27:00 AM [ExceptionHandler] Cannot read property 'challenge' of undefined +44ms
TypeError: Cannot read property 'challenge' of undefined
I also tried with overrideGuard
on AuthGuard
but the result is exactly the same.
Additionally I would like to use typeorm-fixture package but also on this front I'm having big trouble.