NestJS E2E 测试在关闭后不会清理主数据库连接

问题描述 投票:0回答:1

目标

当 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
创建)。

主要数据库连接

测试数据库连接

mysql testing database-connection nestjs e2e-testing
1个回答
0
投票

不知道您是否仍在寻找这个问题的答案,但我也遇到了同样的问题。也尝试使用 DataSource.destroy() (使用 TypeORM)。

最终以下解决方案对我有用。

  1. 添加标志 --detectOpenHandles 以消除警告
  2. 只要所有测试运行成功/不成功,添加标志 --forceExit 即可退出

所以 package.json 中我的脚本条目中的行如下所示:

“测试:e2e”:“jest --config ./test/jest-e2e.json --detectOpenHandles --forceExit”

© www.soinside.com 2019 - 2024. All rights reserved.