用 jest @nestjs 运行 e2e 测试

Posted

技术标签:

【中文标题】用 jest @nestjs 运行 e2e 测试【英文标题】:Running e2e tests with jest @ nestjs 【发布时间】:2020-11-16 11:12:53 【问题描述】:

我正在尝试使用 jest 和 nestjs 运行 e2e 测试,但我遇到了最奇怪的错误,在我的谷歌搜索中没有返回任何内容(ExpressAdapter 不是构造函数):


    $ env-cmd -f .env.test jest --config ./test/jest-e2e.json
     FAIL  test/sensor.e2e-spec.ts (29.498 s)
      SensorController (e2e)
        × /sensors (GET) (15165 ms)

      ● SensorController (e2e) › /sensors (GET)

        Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.

          at mapper (../node_modules/jest-jasmine2/build/queueRunner.js:29:45)

      ● SensorController (e2e) › /sensors (GET)

        TypeError: Cannot read property 'getHttpServer' of undefined

          24 |
          25 |   it('/sensors (GET)', () => 
        > 26 |     return request(app.getHttpServer()).get('/sensors').expect(200);
             |                        ^
          27 |   );
          28 |
          29 |   afterAll(async () => 

          at Object.<anonymous> (sensor.e2e-spec.ts:26:24)

    Test Suites: 1 failed, 1 total
    Tests:       1 failed, 1 total
    Snapshots:   0 total
    Time:        29.69 s
    Ran all test suites.

    ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

          17 |     ).compile();
          18 |
        > 19 |     app = moduleFixture.createNestApplication();
             |                         ^
          20 |
          21 |     await app.init();
          22 |     fixture = await SensorFixture(app);

          at ../node_modules/@nestjs/testing/testing-module.js:25:117
          at Object.loadPackage (../node_modules/@nestjs/common/utils/load-package.util.js:9:27)
          at TestingModule.createHttpAdapter (../node_modules/@nestjs/testing/testing-module.js:25:56)
          at TestingModule.createNestApplication (../node_modules/@nestjs/testing/testing-module.js:13:43)
          at Object.<anonymous> (sensor.e2e-spec.ts:19:25)
    (node:1500) UnhandledPromiseRejectionWarning: TypeError: Caught error after test environment was torn down

    ExpressAdapter is not a constructor
    (node:1500) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
    (node:1500) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    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.
    error Command failed with exit code 1.
    info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

我的 jest-e2e.json:


    
      "moduleFileExtensions": ["js", "json", "ts"],
      "rootDir": ".",
      "testEnvironment": "node",
      "testRegex": ".e2e-spec.ts$",
      "transform": 
        "^.+\\.(t|j)s$": "ts-jest"
      ,
      "moduleNameMapper": 
        "~(.*)$": "<rootDir>/../src/$1"
      
    


jest.config.js:

    module.exports = 
      verbose: true,
      preset: 'ts-jest',
      rootDir: 'src',
      moduleNameMapper: 
        '~(.*)$': '<rootDir>/$1',
      ,
      moduleFileExtensions: ['js', 'json', 'ts'],
      moduleDirectories: [
        "node_modules", 
        "src"
      ],
    ;

我正在使用 typeorm,我很确定我的测试数据库配置是正确的,因为我的单元测试执行没有问题(我正在针对实际的测试数据库运行它们)。

ormconfig.js:

module.exports = 
  type: process.env.DB_TYPE,
  host: process.env.DB_HOST,
  port: process.env.DB_PORT,
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  entities: process.env.DB_ENTITIES.split(' '),
  synchronize: process.env.DB_SYNCHRONIZE,
  autoLoadEntities: true,
  logging: process.env.DB_LOGGING,

环境变量:

DB_TYPE = "postgres"
DB_HOST = "localhost"
DB_PORT = 5432
DB_USERNAME = "postgres"
DB_PASSWORD = "postgres"
DB_DATABASE = "sensor-dashboard-test"
DB_SYNCHRONIZE = true
DB_LOGGING = true
DB_ENTITIES = "**/*.entity.ts,.js ../src/modules/**/*.entity.ts,.js"

我的依赖:

  "dependencies": 
    "@nestjs/common": "^7.0.0",
    "@nestjs/core": "^7.0.0",
    "@nestjs/platform-express": "^7.0.0",
    "@nestjs/typeorm": "^7.1.0",
    "class-transformer": "^0.2.3",
    "class-validator": "^0.12.2",
    "date-fns": "^2.15.0",
    "env-cmd": "^10.1.0",
    "nestjs-admin": "^0.4.0",
    "nestjs-typeorm-paginate": "^2.1.1",
    "pg": "^8.3.0",
    "postgres": "^1.0.2",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^6.5.4",
    "typeorm": "^0.2.25",
    "uuid": "^8.2.0"
  ,

以及失败的整个 e2e 测试:

import  Test, TestingModule  from '@nestjs/testing';
import  INestApplication  from '@nestjs/common';
import * as request from 'supertest';
import 
  SensorFixtureInterface,
  SensorFixture,
 from '~modules/sensor/sensor.fixture';
import  AppModule  from '~app.module';

describe('SensorController (e2e)', () => 
  let app: INestApplication;
  let fixture: SensorFixtureInterface;

  beforeEach(async () => 
    const moduleFixture: TestingModule = await Test.createTestingModule(
      imports: [AppModule],
    ).compile();

    app = moduleFixture.createNestApplication();

    await app.init();
    fixture = await SensorFixture(app);
  );

  it('/sensors (GET)', () => 
    return request(app.getHttpServer()).get('/sensors').expect(200);
  );

  afterAll(async () => 
    await app.close();
  );
);

app.module.ts:

import  Module  from '@nestjs/common';
import  AppService  from './app.service';
import  SensorModule  from '~/modules/sensor/sensor.module';
import  DefaultAdminModule  from 'nestjs-admin';
import  TypeOrmModule  from '@nestjs/typeorm';
import  MeasurementModule  from '~/modules/measurement/measurement.module';

@Module(
  imports: [
    SensorModule,
    MeasurementModule,
    DefaultAdminModule,
    TypeOrmModule.forRoot(),
  ],
  controllers: [],
  providers: [AppService],
)
export class AppModule 

整个项目的链接:https://github.com/xtrinch/sensor-dashboard-nestjs-backend

【问题讨论】:

【参考方案1】:

我遇到了同样的错误,并通过仅将 ts 文件(实体)传递到我的 typeorm 测试环境来修复它。

例如:

module.exports = 
  type: DB_TYPE,
  host: DB_HOST,
  port: DB_PORT,
  username: DB_USERNAME,
  password: DB_PASSWORD,
  database: DB_DATABASE,
  migrations: ['**/migrations/*.ts,js'],
  entities: NODE_ENV === 'test' ? ['**/*.entity.ts'] : ['**/*.entity.ts,js'],
  cli: 
    entitiesDir: 'src/database/entities',
    migrationsDir: 'src/database/migrations',
  ,
;

【讨论】:

我遇到了同样的问题,我浪费了几个小时搜索然后我找到了这个并解决了我的问题。谢谢

以上是关于用 jest @nestjs 运行 e2e 测试的主要内容,如果未能解决你的问题,请参考以下文章

如何用 jest 在服务 (NestJS) 中测试模型 (Mongoose)

使用 NestJS 队列时关闭 redis 连接

如何使用 GRAPHQL 测试 e2e Nestjs API

在 Visual Studio Code 编辑器中完全禁用 Jest 测试运行器的自动运行

NestJS 在 e2e 测试中模拟 JWT 身份验证

运行 npm test 时忽略 e2e 文件夹