[英]Express/Typescript + Jest + Supertest + TypeORM - Random Timeout Exception & Memory Leak
我正在嘗試為快遞 API 編寫單元測試。每個測試套件在測試之前創建一個快遞服務器的新實例。
當每個測試套件獨立運行時似乎沒有問題,當一起運行時我看到一些問題。
9 個測試套件完成后,每個單獨的測試似乎 output 以下警告:
(node:5282) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connection listeners added to [Server]. Use emitter.setMaxListeners() to increase limit
at _addListener (node:events:453:17)
at Server.addListener (node:events:469:10)
at Server.<anonymous> (node_modules/async-listener/index.js:90:10) => this.on('connection', function (socket) {...
at Server.<anonymous> (node_modules/async-listener/index.js:97:23) => return original.apply(this, arguments);
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
at Server.<anonymous> (node_modules/async-listener/index.js:97:23)
我對僅抑制此警告不感興趣,特別是如果這與 memory 泄漏有關,所以請不要建議這樣做。
一些隨機(似乎)測試有時會因錯誤而失敗:
thrown: "Exceeded timeout of 20000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
我確信這與指定的超時值無關,因為這些測試將在不到 500 毫秒的時間內成功,並且無論超時值設置為多少,測試都會失敗。
Example.test.ts 文件
import Server from '../../server';
import { generateTestData } from '../generate-database-data';
import * as request from 'supertest';
import { APIRoutes } from '../../routes';
const server = new Server(); // New instance of express server
describe('API Test', () => {
// Sets up TypeORM DB connection
beforeAll(async() => await server.connect());
// Run raw sql statements using typeorm query runner to truncate and populate fresh data for each test case
beforeEach(async () => await generateTestData(server.connection));
// Close TypeORM connection after all tests
afterAll(async () => await server.connection.close());
test('Get All', async () => {
const response = await request(server.app)
.get(APIRoutes.ROUTE)
.set('Accept', 'application/json');
expect(response.status).toEqual(200);
expect(response.body.length).toEqual(4);
});
...
});
服務器.ts
import * as express from 'express';
import 'express-async-errors';
import { createConnection } from 'typeorm';
import { configureRoutes } from './routes';
require('dotenv').config({path: process.env.NODE_ENV === 'test' ? '.env.test' : '.env'});
class Server {
public app: express.Application;
public server;
public connection;
constructor() {
this.app = express();
this.configuration();
}
public configuration() {
this.app.set('port', process.env.PORT);
this.app.use(express.json());
}
public async connect() {
this.connection = await createConnection({
'type': 'mysql',
'host': process.env.DB_HOST,
'port': parseInt(process.env.DB_PORT),
'username': process.env.DB_USERNAME,
'password': process.env.DB_PASSWORD,
'database': process.env.DB_DATABASE,
'dropSchema': process.env.DB_DROP_SCHEMA === 'true',
'synchronize': true,
'logging': ['error'],
'logger': 'file',
'entities': process.env.NODE_ENV === 'test' ? ['src/entities/**/*.ts'] : ['build/src/entities/**/*.js'],
'cli': { 'entitiesDir': 'build/src/entities' },
'extra': process.env.NODE_ENV === 'test' ? {
'connectionLimit': 0
} : {},
});
configureRoutes(this.app);
return
}
public async start() {
await this.connect();
if (process.env.NODE_ENV !== 'test') {
this.server = this.app.listen(process.env.PORT, () => {
console.log(`App listening on the port ${process.env.PORT}`);
});
}
}
public async stop() {
await this.server?.close();
await this.connection?.close();
}
}
// start express server
if(process.env.NODE_ENV !== 'test') {
const server = new Server();
server.start();
}
export default Server;
相關依賴
"devDependencies": {
"@babel/core": "^7.17.8",
"@babel/preset-env": "^7.16.11",
"@types/express": "^4.17.13",
"@types/jest": "^27.0.1",
"@types/node": "^17.0.18",
"@types/supertest": "^2.0.12",
"babel-jest": "^27.5.1",
"jest": "^27.2.0",
"jest-express": "^1.12.0",
"supertest": "^6.1.6",
"ts-jest": "^27.0.5",
"ts-node": "^10.5.0",
"typescript": "^4.5.5"
},
"dependencies": {
"dotenv": "^8.6.0",
"express": "^4.17.2",
"express-async-errors": "^3.1.1",
"helmet": "^5.0.2",
"typeorm": "^0.2.42"
}
我不認為這是與 typeorm 和數據庫連接相關的問題,因為我可以刪除連接以及生成測試數據的查詢,並且一些測試仍然會失敗並出現相同的超時錯誤和警告消息。 根據at Server.addListener (node:events:469:10)
這提示我相信此錯誤與快速服務器或超級測試有關。
這 2 個問題似乎沒有關聯 - 我相信我已經找到了超時錯誤問題的解決方案。
這個問題似乎是數據庫連接是如何通過 typeorm 建立的結果。
我從 express 服務器中刪除了數據庫連接邏輯,並在setupFilesAfterEnv
文件中對其進行了獨立初始化。 在beforeAll
function 如果當前連接不存在,我創建連接。 如果存在當前連接,我將調用.connect()
方法。
我有一個腳本正在運行以無限期地運行測試,在過去一小時內沒有出現任何錯誤情況,因此我相信問題已得到解決。
但是,我仍然看到MaxListenersExceededWarning
警告。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.