Files
cyh-tk-backend/test/api-standard.e2e-spec.ts
zhxiao1124 4eff4d877e refactor: 完成项目整体目录重构与路径别名配置
1.  重构项目文件结构,统一文件存放位置与命名规则
2.  配置tsconfig路径别名,替换原有相对路径导入
3.  迁移drama-status枚举到dramas.types统一管理
4.  新增全局配置文件与工具类,补充完整注释与文档
5.  修复所有导入路径与依赖引用问题
2026-07-02 19:17:56 +08:00

112 lines
3.2 KiB
TypeScript

import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { validate as validateUuid, version as uuidVersion } from 'uuid';
import { AppModule } from '../src/app/app.module';
import { bootstrapApp } from '../src/bootstrap';
import { loginAdmin } from './test-helpers';
describe('API standard', () => {
let app: INestApplication;
let adminToken: string;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleRef.createNestApplication();
bootstrapApp(app);
await app.init();
adminToken = await loginAdmin(app);
});
afterAll(async () => {
await app.close();
});
it('wraps successful responses with code, data, message, timestamp, requestId and cost', async () => {
const response = await request(app.getHttpServer())
.get('/api/app/v1/health')
.expect(200);
expect(response.body).toEqual({
code: 0,
data: { status: 'ok' },
message: 'success',
timestamp: expect.any(Number),
requestId: expect.any(String),
cost: expect.stringMatching(/^\d+ms$/),
});
expect(validateUuid(response.body.requestId)).toBe(true);
expect(uuidVersion(response.body.requestId)).toBe(4);
});
it('reuses a valid X-Request-Id header', async () => {
const requestId = '0f5c2e16-1e44-4d55-93a4-ef7c66d9d1f2';
const response = await request(app.getHttpServer())
.get('/api/app/v1/health')
.set('X-Request-Id', requestId)
.expect(200);
expect(response.body.requestId).toBe(requestId);
});
it('wraps errors in the standard response shape', async () => {
const response = await request(app.getHttpServer())
.get('/api/app/v1/missing')
.expect(404);
expect(response.body).toEqual({
code: 404,
data: {},
message: expect.any(String),
timestamp: expect.any(Number),
requestId: expect.any(String),
cost: expect.stringMatching(/^\d+ms$/),
});
});
it('returns paginated lists using data.list and data.pagination', async () => {
const response = await request(app.getHttpServer())
.get('/api/admin/v1/logs/requests')
.set('Authorization', `Bearer ${adminToken}`)
.expect(200);
expect(response.body.code).toBe(0);
expect(response.body.data).toEqual({
list: expect.any(Array),
pagination: {
page: 1,
pageSize: 20,
total: expect.any(Number),
},
});
});
it('can query a request log by requestId', async () => {
const requestId = '180facd4-68f9-48c9-b6b1-3d8eab56a681';
await request(app.getHttpServer())
.get('/api/app/v1/health')
.set('X-Request-Id', requestId)
.expect(200);
const response = await request(app.getHttpServer())
.get(`/api/admin/v1/logs/requests/${requestId}`)
.set('Authorization', `Bearer ${adminToken}`)
.expect(200);
expect(response.body.data).toMatchObject({
requestId,
method: 'GET',
path: '/api/app/v1/health',
statusCode: 200,
responseCode: 0,
message: 'success',
});
expect(response.body.data.costMs).toEqual(expect.any(Number));
});
});