当 NestJS E2E 测试停止时,不显示以下消息:
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.
如何确保端到端测试运行后主数据库连接和端到端数据库连接都已关闭?
我搜索了其他类似的 StackOverflow 问题,但找不到解决我的问题的答案,因此我提出了自己的问题。
请参阅下面的分析,了解我如何得出回答这个问题将实现我的目标的结论。
我做了一些实验,我相信我已经缩小了原因,但我不确定如何解决它。我相信这是由于 NestJS 在 NestJS E2E 测试中未关闭主数据库连接造成的。
这是我的数据库模块设置代码:
export const getConfig = () => TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => {
console.log('starting database...', configService.get<number>('db.port'));
return ({
type: 'mysql',
host: configService.get<string>('db.host'),
port: configService.get<number>('db.port'),
username: configService.get<string>('db.username'),
password: configService.get<string>('db.password'),
database: configService.get<string>('db.database'),
autoLoadEntities: true,
namingStrategy: new SnakeNamingStrategy(),
});
},
inject: [ConfigService],
});
app.module.ts
:
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { getConfig as getAppConfig } from './config/module-config';
import { getConfig as getDatabaseConfig } from './database/module-config';
import { HealthController } from './health/health.controller';
@Module({
imports: [
getAppConfig(),
TerminusModule,
getDatabaseConfig(),
],
controllers: [HealthController],
})
export class AppModule {}
main.ts
import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as helmet from 'helmet';
import { AppModule } from './app.module';
/**
* Applies common app config to both the main application and e2e test app config.
* It's important that both the main app and the e2e apps are configured the same
* @param app Nest application to apply configuration to
*/
export const applyAppConfig = (app : INestApplication) => {
app.setGlobalPrefix('api');
app.use(helmet());
};
async function bootstrap() {
const app = await NestFactory.create(AppModule);
applyAppConfig(app);
app.enableShutdownHooks();
const port = process.env.PORT || 0;
if (process.env.NODE_ENV !== 'test') {
await app.listen(port);
}
console.info(`App running on: localhost:${port}`);
}
bootstrap();
一个
utils.ts
文件,其中包含一些用于设置 e2e 测试的函数:
export const getTestConfig = () =>
ConfigModule.forRoot({
isGlobal: true,
load: [testConfiguration],
});
/**
* Creates a test app for e2e tests that has the same configuration as the main application
* @param {TestingModule} moduleRef A list of testing modules to inject into the app, so each e2e test injects only the dependencies it needs to function
* @returns {INestApplication} A fully initialized INestApplication
*/
export const createTestApp = async (moduleRef : TestingModule) : Promise<INestApplication> => {
const app = moduleRef.createNestApplication();
applyAppConfig(app);
return await app.init();
};
还有我的缩写
app.e2e-spec.ts
:
describe('AppController', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
getTestConfig(),
AppModule
],
}).compile();
app = await createTestApp(moduleRef);
});
afterAll(async () => {
await app.close();
});
describe('GET /api/health', () => {
it('returns 200', () => {
return request(app.getHttpServer())
.get('/api/health')
.expect(200);
});
});
// ... rest of the code excluded
注:
12360
是我的主数据库,12361
是我的E2E数据库
[Nest] 6017 - 12/24/2020, 12:39:52 PM [NestFactory] Starting Nest application...
console.log
starting database... 12360
at InstanceWrapper.useFactory [as metatype] (src/database/module-config.ts:8:13)
at async Promise.all (index 3)
console.log
starting database... 12361
at InstanceWrapper.useFactory [as metatype] (src/database/module-config.ts:8:13)
at async Promise.all (index 3)
console.info
App running on: localhost:3200
at bootstrap (src/main.ts:41:11)
PASS test/app.e2e-spec.ts
AppController
GET /api/health
✓ returns 200 (23 ms)
GET /api/restdocs/
✓ returns 200 (3 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.637 s, estimated 4 s
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.
检查 MySQL 连接显示 e2e 测试未正确终止主数据库连接。主数据库与用户
test
(应用程序当前连接的用户)有一个额外的连接,这一事实可以证明这一点。其他四个连接是 MySQL Workbench 连接(由用户 root
创建)。
不知道您是否仍在寻找这个问题的答案,但我也遇到了同样的问题。也尝试使用 DataSource.destroy() (使用 TypeORM)。
最终以下解决方案对我有用。
所以 package.json 中我的脚本条目中的行如下所示:
“测试:e2e”:“jest --config ./test/jest-e2e.json --detectOpenHandles --forceExit”