listen
├─ e2e
│ ├─ xxx.spec.ts
│ └─ xxx.spec.ts
└─ src
├─ app.controller.ts
├─ app.module.ts
└─ app.service.ts
-
src/app.service.ts
import { Injectable } from '@nestjs/common' @Injectable() export class AppService { sayHello(): string { return 'Hello World!' } }
-
src/app.controller.ts
import { Controller, Get } from '@nestjs/common' // eslint-disable-next-line @typescript-eslint/consistent-type-imports import { AppService } from './app.service' @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.sayHello() } }
-
src/app.module.ts
import { Module } from '@nestjs/common' import { AppController } from './app.controller' import { AppService } from './app.service' @Module({ controllers: [AppController], providers: [AppService] }) export class AppModule {}
-
e2e/xxx.spec.ts
import type { TestingModule } from '@nestjs/testing' import { Test } from '@nestjs/testing' import { expect } from 'chai' import { AppModule } from '../src/app.module' import type { INestApplication } from '@nestjs/common' describe('...', () => { let testModule: TestingModule let app: INestApplication let server beforeEach(async () => { testModule = await Test.createTestingModule({ // 切入点 1 imports: [AppModule] }).compile() // 切入点 2 // 可以下沉到 it() 中 app = testModule.createNestApplication() // 可以下沉到 it() 中 server = app.getHttpServer() await app.init() // 切入点 4,模拟发起多次请求以便在 it 中判断结果 }) afterEach(async () => { await app.close() }) it('...', async () => { // 切入点 3 }) it('...', async () => { // TODO }) })
可以指定不同底层 http 适配框架
import { ExpressAdapter } from '@nestjs/platform-express'
import * as express from 'express'
app = testModule.createNestApplication(new ExpressAdapter(express))
// 或
import { FastifyAdapter } from '@nestjs/platform-fastify'
app = testModule.createNestApplication(new FastifyAdapter())
// 1. 使用 supertest 模拟发起请求并使用 jest 内置断言判断
await request(server).get('/').expect(200)
// 或
await request(server).get('/').expect(200, {
/* response body data*/
})
await request(server).get('/notfound').expect(404)
// 2. expect 可以多次使用
const response = await request(server).get('/').expect(200)
// chai
expect(response.body.title).to.equal('My Website')
// 3. expect 中可以是函数
request(server)
.post('/cats')
.send(cat)
.expect(201)
.expect(({ body }) => body.name === cat.name)
// 4. 可以进行相关配置
app.setLocal('title', 'My Website')
app.setGlobalPrefix('/api')
// 5. 可以使用 chai 库提供的断言
expect(await app.getUrl()).to.be.eql(`http://127.0.0.1:3000`)
// 5. 可以以 try catch 方式测试异常情况
try {
await app.getUrl()
} catch (err) {
expect(err).to.be.eql(
'app.listen() needs to be called before calling app.getUrl()'
)
}
const performHttpCall = end => {
request(server)
.get('/hello')
.end((err, res) => {
if (err) return end(err)
end()
})
}
await new Promise(resolve => performHttpCall(resolve))
await new Promise(resolve => performHttpCall(resolve))
await new Promise(resolve => performHttpCall(resolve))
it(`should create controller for each request`, async () => {
expect(HelloController.COUNTER).to.be.eql(3)
})