I have a NestJS project configured with TypeORM. The e2e test is the one that is generated by the CLI:
import { Test, TestingModule } from '#nestjs/testing';
import { INestApplication } from '#nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
The error I get is the following:
RepositoryNotFoundError: No repository for "Question" was found. Looks like this entity is not registered in current "default" connection?
at RepositoryNotFoundError.TypeORMError [as constructor] (../src/error/TypeORMError.ts:7:9)
at new RepositoryNotFoundError (../src/error/RepositoryNotFoundError.ts:10:9)
at EntityManager.Object.<anonymous>.EntityManager.getRepository (../src/entity-manager/EntityManager.ts:975:19)
at Connection.Object.<anonymous>.Connection.getRepository (../src/connection/Connection.ts:354:29)
at InstanceWrapper.useFactory [as metatype] (../node_modules/#nestjs/typeorm/dist/typeorm.providers.js:17:30)
at TestingInjector.instantiateClass (../node_modules/#nestjs/core/injector/injector.js:304:55)
at callback (../node_modules/#nestjs/core/injector/injector.js:48:41)
at TestingInjector.resolveConstructorParams (../node_modules/#nestjs/core/injector/injector.js:124:24)
at TestingInjector.loadInstance (../node_modules/#nestjs/core/injector/injector.js:52:9)
AppModule is configured like this:
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '#nestjs/typeorm';
import { QuestionsModule } from './questions/questions.module';
import { Connection, getConnectionOptions } from 'typeorm';
#Module({
imports: [
// docker run --name postgres_questions_answers -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_DB=dev_questions_answers -p 5432:5432 -d postgres
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions(), {
// FIXME: This is done so Jest e2e doesnt raise Cannot create a new connection named "default", because connection with such name already exist and it now has an active connection session.
keepConnectionAlive: process.env.NODE_ENV === 'test',
}),
}),
QuestionsModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
constructor(private connection: Connection) {}
}
And the QuestionsModule like this:
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { QuestionsService } from './questions.service';
import { QuestionsController } from './questions.controller';
import { Question } from '../entities/question.entity';
#Module({
imports: [TypeOrmModule.forFeature([Question])],
controllers: [QuestionsController],
providers: [QuestionsService],
})
export class QuestionsModule {}
Project runs fine in development and production mode, so I am wondering what am I doing wrong here?
Related
I'm experimenting with NestJs, following a tutorial. I've decided I want to write some tests on the code I've written.
I'm writing tests for the ProductController and the test file for the controller mocks the ProductModule to which the controller belongs. My ProductModule imports MongooseModule and presumably I need to mock that import in the TestingModule of the controller test file.
How can I go about mocking that import?
ProductModule;
import { Module } from '#nestjs/common';
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ProductSchema } from './schemas/product.schema';
#Module({
imports: [
MongooseModule.forFeature([{ name: 'Product', schema: ProductSchema }]),
],
providers: [ProductService],
controllers: [ProductController],
})
export class ProductModule {}
ProductController test file;
import { Test, TestingModule } from '#nestjs/testing';
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
describe('ProductController', () => {
let controller: ProductController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductService],
controllers: [ProductController],
}).compile();
controller = module.get<ProductController>(ProductController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
For the ProductController test I'd use a custom provider like
{
provide: ProductService,
useValue: {
method1: jest.fn(),
methodN: jest.fn()
}
}
For your ProductService test I'd mock the #InjectModel('Product') by using getModelToken() and a custom provider like
{
provide: getModelToken('Product'),
useValue: {
productModelMethod1: jest.fn(),
}
}
You can see a repo here with a bunch of test examples
I'm trying to unit test a middleware to avoid sending a request but I'm actually not able to retreive the middleware with .get
import { NestApplicationContext } from '#nestjs/core';
import { BodyParserMiddleware } from '../../../src/config/body-parser/body-parser.middleware';
import { FeaturesModule } from '../../../src/features/features.module';
describe('CatsController', () => {
let app: NestApplicationContext;
beforeAll(() => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
});
describe('findAll', () => {
it('should return an array of cats', async () => {
console.log(app.get(BodyParserMiddleware));
});
});
});
my app module looks like this
import { Module } from '#nestjs/common';
import { FeaturesModule } from './features/features.module';
#Module({
imports: [FeaturesModule],
})
export class AppModule {}
and the last one feature module
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { BodyParserMiddleware } from '../config/body-parser/body-parser.middleware';
#Module({
imports: [
AuthModule,
],
})
export class FeaturesModule implements NestModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(BodyParserMiddleware).forRoutes('api/v*/*/get-many');
}
}
Nest could not find BodyParserMiddleware element (this provider does not exist in the current context)
this is the error that im having
anyone knows how to retreive the middleware from the app container?
Also when I try to get the Features module to see if there is any clue there where I can go I receive
FeaturesModule {}
I'm usign nestjs-prisma in NestJs and I have in the following import for the prisma module in the app.module, so in every service I can use the PrismaService as the library allows it.
app.module.ts
import { Module } from '#nestjs/common';
import { PrismaModule } from 'nestjs-prisma';
import { CategoryModule } from './category/category.module';
#Module({
imports: [PrismaModule.forRoot({ isGlobal: true }), CategoryModule],
})
export class AppModule {}
I want to do a e2e test just for the CategoryModule and need to mock the PrismaService, how can i do that?
You need to mook first of all the PrismaModule and then import in it the PrismaService, here is an example.
category.e2e-spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { INestApplication } from '#nestjs/common';
import * as request from 'supertest';
import { PrismaModule, PrismaService } from 'nestjs-prisma';
import { CategoryModule } from '../src/category/category.module';
describe('CategoryModule (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
// Here you have to mock the category funtions that you'll use
const mockPrismaService = {
provide: PrismaService,
useFactory: () => ({
category: {
findMany: jest.fn(() => [])
},
}),
};
// Here is the creation of the module and the definition for the service
const mockPrismaModule = {
module: PrismaModule,
providers: [mockPrismaService],
global: true,
};
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [CategoryModule, mockPrismaModule], // Here is the import for the mock module
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('(GET) /category', () => {
return request(app.getHttpServer()).get('/category').expect(200);
});
});
Hi I currently want to mock my configService injected as RegisterAs which allows me to have strong typing when accessing my environment variables, my problem with this is that when I mock the configService in my unit test and try to manipulate the environment values it doesn't I'm making it.
I show some of what I have.
My Nestjs Project:
src/
|- config/
| |- environment.ts
|- modules/
| |- auth/
| |- auth.service.ts
| |- auth.service.spec.ts
|- app.module.ts
|- main.ts
|+- ...
app.module.ts
import * as Joi from 'joi';
import { AuthModule } from './modules/auth/auth.module';
import { ConfigModule } from '#nestjs/config';
import { Module } from '#nestjs/common';
import { ScheduleModule } from '#nestjs/schedule';
import env from './config/environment';
#Module({
imports: [
ScheduleModule.forRoot(),
ConfigModule.forRoot({ // <= I load the variables and validate them with Joi
isGlobal: true,
load: [env],
validationSchema: Joi.object().keys({
JWT_SESSION: Joi.string().trim(),
JWT_SESSION_EXP: Joi.number(),
}),
}),
AuthModule,
],
})
export class AppModule {}
config/environment.ts
import { registerAs } from '#nestjs/config';
export default registerAs('env', () => ({
jwtSession: process.env.JWT_SESSION || undefined,
expSession: Number(process.env.JWT_SESSION_EXP) || undefined,
}));
auth.service.ts
import * as moment from 'moment';
import { ConfigType } from '#nestjs/config';
import { Inject, Injectable, Logger } from '#nestjs/common';
import { AuthResponse } from './interfaces/login.interface';
import { AuthenticationDto } from './dto/auth.dto';
import { HttpService } from '#nestjs/axios';
import { JwtFidelity } from './interfaces/jwt-fidelity.interface';
import env from './../../config/environment';
import jwt_decode from 'jwt-decode';
import { lastValueFrom } from 'rxjs';
#Injectable()
export class AuthService {
constructor(
#Inject(env.KEY) private configService: ConfigType<typeof env>, // <= I inject the environment variables like this
) {}
isTokenExpired(): boolean { // <= This checks if the token has expired
if (!this.configService.jwtSession) return true;
if (!this.configService.expSession) return true;
return false;
}
}
auth.service.spec.ts
Note: this is where i would like you to help me.
import { ConfigModule, ConfigService } from '#nestjs/config';
import { HttpModule, HttpService } from '#nestjs/axios';
import { Test, TestingModule } from '#nestjs/testing';
import { AuthService } from '../auth.service';
import environment from '../../../config/environment';
import { of } from 'rxjs';
const env = () => ({
auth: {
partner: {
jwtSeesion:
'jwt-token',
expSession: '1661878302',
},
},
});
describe('AuthService', () => {
let service: AuthService;
let httpService: HttpService;
let configService: ConfigService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, ConfigModule.forRoot({ load: [environment] })],
providers: [
HttpService,
AuthService,
ConfigService,
{ provide: 'CONFIGURATION(env)', useFactory: env },
],
})
.overrideProvider(HttpService)
.useValue({ request: jest.fn() })
.overrideProvider(ConfigService)
.useValue({ jwtSession: jest.fn() })
.compile();
service = module.get<AuthService>(AuthService);
httpService = module.get<HttpService>(HttpService);
configService = module.get<ConfigService>(ConfigService);
});
it('should be defined', () => {
expect(service).toBeDefined();
expect(httpService).toBeDefined();
expect(configService).toBeDefined();
});
describe('AuthController.isTokenExpired', () => {
it('variable jwtSession undefined', async () => {
configService.jwtSession = undefined; // <= I would like the possibility of doing something like that
jest.spyOn(configService, 'jwtSession').mockReturnValue('hola' as any); // <= Or something like that
const isExpired = await service.isTokenExpired();
expect(isExpired).toBeTruthy();
});
});
});
I would like that at the level of each test I can be able to manipulate the value of the environment variables that I have injected with #Inject(env.KEY) private configService: ConfigType<typeof env>, in my auth.service.ts
I have an AppModule file as follows:
import { Module } from '#nestjs/common'
import { RabbitMQModule } from '#golevelup/nestjs-rabbitmq'
#Module({
imports: [
RabbitMQModule.forRoot(RabbitMQModule, {
exchanges: [
{
name: 'my_rabbit',
type: 'direct',
},
],
uri: process.env.RABBITMQ_URI,
connectionInitOptions: { wait: true },
}),
],
})
export class AppModule {}
I have tried to mock rabbitmq using #golevelup/nestjs-rabbitmq like this:
import { Module } from '#nestjs/common'
import { RabbitMQModule } from '#golevelup/nestjs-rabbitmq'
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
AppModule
],
})
.overrideProvider(AmqpConnection)
.useValue(createMock<AmqpConnection>())
.compile()
})
This is giving me error:
[Nest] 2745 - 24/07/2022, 17:02:54 ERROR [AmqpConnection] Disconnected from RabbitMQ broker (default)
Error: connect ECONNREFUSED 127.0.0.1:5672
If i mock the whole rabbitmq module like:
jest.mock('#golevelup/nestjs-rabbitmq')
I will get errors like:
Nest cannot create the AppModule instance.
The module at index [0] of the AppModule "imports" array is undefined.
Has anyone successfully mocked RabbitMQ? Please assist if possible.
I solve this problem mocking an AmqpConnection like this.
import { AmqpConnection } from "#nestjs-plus/rabbitmq";
import { TestingModule, Test } from "#nestjs/testing";
import { IntegrationQueueService } from "./integration-queue.service";
describe('IntegrationQueueService', () => {
type MockType<T> = {
[P in keyof T]?: jest.Mock<{}>;
};
const mockFactory: () => MockType<AmqpConnection> = jest.fn(() => ({
publish: jest.fn(() => AmqpConnection),
}))
let service: IntegrationQueueService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
IntegrationQueueService,
{
provide: AmqpConnection,
useFactory: mockFactory,
},
],
})
.compile();
service = module.get<IntegrationQueueService> (IntegrationQueueService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
})