Reputation: 73
I use the NestJS framework. When using @nestjs/typeorm, I create a repository with users. Using this approach to creating a repository, my e2e tests. When working with a database, all data is successfully saved. There are no problems with the connection. Here are my files:
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { AuthModule } from './modules/auth/auth.module';
@Module({
imports: [
TypeOrmModule.forRoot(),
AuthModule,
],
})
export class AppModule {
constructor(private readonly connection: Connection) { }
}
auth.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { Users } from '../../entity/Users';
@Module({
imports: [TypeOrmModule.forFeature([Users])],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
auth.service.ts
...
// my repo
constructor(
@InjectRepository(Users)
private readonly usersRepository: Repository<Users>,
) { }
...
app.e2e-spec.ts
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(404)
.expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); //todo fix me
});
});
Everything is written in accordance with the documentation. When you run npm run test:e2e, the console gives the following error:
> [email protected] test:e2e
> jest --config ./test/jest-e2e.json
[Nest] 7206 - 2/2/2019, 5:06:52 PM [TypeOrmModule] Unable to connect to the database. Retrying (1)...
Error: getaddrinfo ENOTFOUND postgres postgres:5432
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
[Nest] 7206 - 2/2/2019, 5:06:55 PM [TypeOrmModule] Unable to connect to the database. Retrying (2)... +3234ms
Error: getaddrinfo ENOTFOUND postgres postgres:5432
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
FAIL test/app.e2e-spec.ts (6.198s)
AppController (e2e)
✕ / (GET) (6ms)
● AppController (e2e) › / (GET)
Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
at mapper (../node_modules/jest-jasmine2/build/queue_runner.js:41:52)
● AppController (e2e) › / (GET)
TypeError: Cannot read property 'getHttpServer' of undefined
17 |
18 | it('/ (GET)', () => {
> 19 | return request(app.getHttpServer())
| ^
20 | .get('/')
21 | .expect(404)
22 | .expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); // todo fix me
at Object.<anonymous> (app.e2e-spec.ts:19:24)
Please, help me!
Upvotes: 6
Views: 13551
Reputation: 1194
If you want to write e2e tests with mocks you don't need to import the AppModule
you only should import your AppController
and AppService
, in this way you avoid to connect to your database and use mocks to test the entire application flow.
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppController } from './../src/app.controller';
import { AppService } from './../src/app.service';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [],
controllers: [AppController],
providers: [AppService],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(404)
.expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); //todo fix me
});
});
With this approach you get a clean testing module without TypeOrmModule
.
NOTE: if you need to mock the service, the Test
has a method overrideProvider
to override your service and mothods like useClass
, useValue
or useFactory
to provide your mock.
If you want to write an integration test to confirm that all together works fine you can override the configuration of your TypeOrmModule
, passing it to the testing module with a new DB configuration like this post describes.
I hope I've helped. Good luck and regards.
Upvotes: 12
Reputation: 4936
Never uses TypeOrmModule
in unit test. It will be make connect to DB. When your DB not started you will can not run unit test.
Try this example.
// mytest.e2e-spec.ts
import * as request from 'supertest';
import { Test } from "@nestjs/testing";
import { INestApplication } from '@nestjs/common';
import { MyTestsController } from './myTests.controller';
import { MyTestsService } from ".";
import { Warehouse } from './myTest.entity';
import { getRepositoryToken } from '@nestjs/typeorm';
describe("MyTestsController (e2e)", () => {
let app: INestApplication;
const myTests = [
{
id: "1ccc2222a-8072-4ff0-b5ff-103cc85f3be6",
name: "Name #1",
}
];
const myTestsCount = 1;
const getAllResult = { myTests, myTestsCount };
// Mock data for service
let myTestsService = { getAll: () => getAllResult };
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [
MyTestsService,
{
provide: getRepositoryToken(Warehouse),
useValue: myTestsService
}
],
controllers: [MyTestsController],
})
.overrideProvider(MyTestsService)
.useValue(myTestsService)
.compile();
app = module.createNestApplication();
await app.init();
});
beforeEach(async () => {});
it(`/GET all myTests`, async() => {
return await request(app.getHttpServer())
.get('/myTests')
.expect(200)
.expect(myTestsService.getAll());
});
afterAll(async () => {
await app.close();
});
});
And the service
// myTests.service.ts
public async getAll(query?): Promise<myTestsRO> {
const qb = await this.repo.createQueryBuilder("myTests");
const myTestsCount = await qb.getCount();
if ("limit" in query) {
qb.limit(query.limit);
}
if ("offset" in query) {
qb.offset(query.offset);
}
const myTests = await qb
.getMany()
.then(myTests =>
myTests.map(entity => WarehouseDto.fromEntity(entity))
);
return { myTests, myTestsCount };
}
And controller
// myTest.controller.ts
@Get()
public async getAll(@Query() query): Promise<myTestsRO> {
try {
return await this.myTestsService.getAll(query);
} catch (error) {
throw new InternalServerErrorException(error.message);
}
}
Hope this help!
Upvotes: 0
Reputation: 73
That error can occur even if you typed your api paths wrong. It doesnt log the error but it always throws on that line you shown. I also had a similar problem, i was putting globalPrefix to /api
and in my tests i forgot that its another nest application instance, so removing /api/ from e2e mocks fixed everything.
Upvotes: 0
Reputation: 652
Be sure to close the app
object with app.close()
per the example at https://docs.nestjs.com/fundamentals/testing#end-to-end-testing.
Upvotes: 1