I perfome some e2E test in nestJs microservice (using Redis as transporter).
Everything is going well except that the process never end.
This is the message displayed on console
Ran all test suites.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
Here is the code of my controller
import {Body, Controller, HttpCode, Post, Query} from '@nestjs/common';
import { AppService } from './app.service';
import {Client, ClientProxy, MessagePattern, Transport} from '@nestjs/microservices';
import {AdminDto} from "./admin.dto";
import {Admin} from "./admin.interface";
import {Observable} from "rxjs";
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
/** Useful for test only **/
@Client({ transport: Transport.REDIS })
client: ClientProxy;
@Post()
@HttpCode(200)
call(@Query('command') cmd, @Body() data: any): Observable<any> {
return this.client.send<number>({ cmd }, data);
}
/** End of test **/
@MessagePattern({cmd: 'createAdmin'})
async createClient(adminDto: AdminDto): Promise<Admin> {
return await this.appService.create(adminDto);
}
}
And this is my app.e2e-soec.ts file, as you can see, I close all connection on afterEach fuction.
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import {Transport} from "@nestjs/microservices";
import {AppModule} from "../src/app.module";
import * as mongoose from "mongoose";
import {connection} from "mongoose";
describe('AppController (e2e)', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication();
server = app.getHttpAdapter().getInstance();
app.connectMicroservice({
transport: Transport.REDIS,
options: {
url: 'redis://0.0.0.0:6379',
},
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`/POST (create admin)`, done => {
const adminDto = {
firstName : 'test',
lastName: 'toto',
password: '1234',
email: '[email protected]',
roles: ['ROLE_ADMIN']
};
return request(server)
.post('/?command=createAdmin')
.send(adminDto)
.end((error, response) => {
expect(response.status).toEqual(200);
expect(response.body).toMatchObject({
_id: expect.any(String),
firstName: "test",
lastName: "toto"
});
done();
});
});
afterEach(async done => {
await mongoose.connection.close();
await connection.close();
await app.close();
done();
});
});
EDIT
As Jesse Carter advice, I’ve added leaked-handles
to get more clues
Seems it’s because of redis
tcp handle leaked at one of:
at RedisClient.Object.<anonymous>.RedisClient.create_stream (/Users/myUser/project/admin-service/node_modules/redis/index.js:195:31)
tcp stream {
fd: 38,
readable: true,
writable: true,
address: { address: '127.0.0.1', family: 'IPv4', port: 54468 },
serverAddr: null
}
4
Answers
Occasionally you might run into an error from Jest indicating that it did not exit properly, eg:
This is usually a sign that there is indeed a problem and shouldn’t be ignored. However, taking the advice of running with
--detectOpenHandles
doesn’t always give actionable feedback about where the problem lies.An alternative community package called leaked-handles is available which might help track down the culprit. Install this package to your
dev dependencies
for the project that has non-exiting tests and put the coderequire('leaked-handles)
at the top of the test files. Observe any output regarding leaks in your test runner. It will often tell you exactly what port or service is still active and preventing the test from closing.If you capture this output and share it here we will be able to help you with more specifics about what cleanup logic may be missing.
Side Note:
I would generally advise that you do module level startup and tear down in the
beforeAll
andafterAll
lifecycle methods as opposed to doing in between each test. It might not be related to your issues but will make a big difference in how long your test suites take to runI also have this issue with Redis. Seeing
TCPSERVERWRAP
when using the--detectOpenHandles
flag with Jest.As a workaround, you can pass the
--forceExit
flag to Jest.It might be late but you have to call the close function from the module variable, like this:
Thats what worked for me.
It happens to me becuase of TypeOrm connection is not getting closed after finishing the Test suite. In order to resolve the issue,
Option 1
Set TypeOrmModuleOption -> keepConnectionAlive: false
Close the app at the end of the test suite.
Option 2
Close the connection inside
afterAll()