feat: 开发broker相关代码,开发全局代码

This commit is contained in:
R524809
2025-11-18 18:01:04 +08:00
parent a9d7fc9038
commit 7acadf191f
29 changed files with 3149 additions and 106 deletions

View File

@@ -0,0 +1,12 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": "..",
"testEnvironment": "node",
"testMatch": ["**/test/**/*.integration.spec.ts"],
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/src/$1"
}
}

View File

@@ -0,0 +1,240 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { AppModule } from '../../../src/app.module';
import { Broker } from '../../../src/modules/broker/broker.entity';
import { Response } from '../../../src/common/interceptors/transform.interceptor';
describe('BrokerController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
jest.setTimeout(30000);
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule], // 导入整个应用模块
}).compile();
app = moduleFixture.createNestApplication();
await app.init(); // 初始化应用(包括所有中间件、管道、拦截器等)
});
afterAll(async () => {
await app.close();
});
describe('POST /api/broker', () => {
it('应该成功创建券商(完整流程)', () => {
return request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'E2E_TEST',
brokerName: 'E2E测试券商',
region: 'CN',
sortOrder: 1,
isActive: true,
})
.expect(201)
.expect((res) => {
// 验证响应格式(经过 TransformInterceptor 处理)
expect(res.body).toHaveProperty('code', 0);
expect(res.body).toHaveProperty('message', 'success');
expect(res.body).toHaveProperty('data');
expect(res.body.data).toHaveProperty(
'brokerCode',
'E2E_TEST',
);
expect(res.body.data).toHaveProperty(
'brokerName',
'E2E测试券商',
);
expect(res.body.data).toHaveProperty('brokerId');
});
});
it('应该返回 400 当数据验证失败时', () => {
return request(app.getHttpServer())
.post('/api/broker')
.send({
// 缺少必需字段
brokerCode: 'TEST',
})
.expect(400)
.expect((res) => {
// 验证错误响应格式(经过 HttpExceptionFilter 处理)
expect(res.body).toHaveProperty('code');
expect(res.body).toHaveProperty('message');
expect(res.body.code).not.toBe(0);
});
});
it('应该返回 409 当券商代码已存在时', async () => {
// 先创建一个券商
await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'DUPLICATE_TEST',
brokerName: '重复测试',
region: 'CN',
})
.expect(201);
// 尝试创建重复的券商
return request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'DUPLICATE_TEST',
brokerName: '重复测试2',
region: 'CN',
})
.expect(409)
.expect((res) => {
expect(res.body.code).toBe(409);
expect(res.body.message).toContain('already exists');
});
});
});
describe('GET /api/broker', () => {
it('应该返回券商列表', async () => {
// 先创建一个券商
const createResponse = await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'GET_TEST',
brokerName: '查询测试',
region: 'CN',
})
.expect(201);
// 查询券商列表
return request(app.getHttpServer())
.get('/api/broker')
.expect(200)
.expect((res) => {
expect(res.body).toHaveProperty('code', 0);
expect(res.body).toHaveProperty('data');
expect(Array.isArray(res.body.data)).toBe(true);
// 验证创建的券商在列表中
const found = res.body.data.find(
(b: { brokerCode: string }) =>
b.brokerCode === 'GET_TEST',
);
expect(found).toBeDefined();
});
});
it('应该支持按条件查询', async () => {
// 先创建一个券商
await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'QUERY_TEST',
brokerName: '条件查询测试',
region: 'CN',
})
.expect(201);
// 按 brokerCode 查询
return request(app.getHttpServer())
.get('/api/broker?brokerCode=QUERY_TEST')
.expect(200)
.expect((res) => {
expect(res.body.code).toBe(0);
expect(res.body.data).toHaveLength(1);
expect(res.body.data[0].brokerCode).toBe('QUERY_TEST');
});
});
});
describe('GET /api/broker/:id', () => {
it('应该返回单个券商', async () => {
// 先创建一个券商
const createResponse = await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'GET_ONE_TEST',
brokerName: '单个查询测试',
region: 'CN',
})
.expect(201);
const brokerId = (createResponse.body as Response<Broker>).data
.brokerId;
// 查询单个券商
return request(app.getHttpServer())
.get(`/api/broker/${brokerId}`)
.expect(200)
.expect((res) => {
expect(res.body.code).toBe(0);
expect(res.body.data.brokerId).toBe(brokerId);
expect(res.body.data.brokerCode).toBe('GET_ONE_TEST');
});
});
it('应该返回 404 当券商不存在时', () => {
return request(app.getHttpServer())
.get('/api/broker/99999')
.expect(404)
.expect((res) => {
expect(res.body.code).toBe(404);
});
});
});
describe('PATCH /api/broker/:id', () => {
it('应该成功更新券商', async () => {
// 先创建一个券商
const createResponse = await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'UPDATE_TEST',
brokerName: '更新测试',
region: 'CN',
})
.expect(201);
const brokerId = (createResponse.body as Response<Broker>).data
.brokerId;
// 更新券商
return request(app.getHttpServer())
.patch(`/api/broker/${brokerId}`)
.send({
brokerName: '更新后的名称',
})
.expect(200)
.expect((res) => {
expect(res.body.code).toBe(0);
expect(res.body.data.brokerName).toBe('更新后的名称');
});
});
});
describe('DELETE /api/broker/:id', () => {
it('应该成功删除券商', async () => {
// 先创建一个券商
const createResponse = await request(app.getHttpServer())
.post('/api/broker')
.send({
brokerCode: 'DELETE_TEST',
brokerName: '删除测试',
region: 'CN',
})
.expect(201);
const brokerId = (createResponse.body as Response<Broker>).data
.brokerId;
// 删除券商
await request(app.getHttpServer())
.delete(`/api/broker/${brokerId}`)
.expect(204);
// 验证已删除
await request(app.getHttpServer())
.get(`/api/broker/${brokerId}`)
.expect(404);
});
});
});

View File

@@ -0,0 +1,150 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BrokerService } from '../../../src/modules/broker/broker.service';
import { Broker } from '../../../src/modules/broker/broker.entity';
import { BrokerModule } from '../../../src/modules/broker/broker.module';
import { CreateBrokerDto } from '../../../src/modules/broker/dto/create-broker.dto';
import { BatchCreateBrokerDto } from '../../../src/modules/broker/dto/batch-create-broker.dto';
import { getDatabaseConfig } from '../../../src/database/database.config';
import { brokersConfig } from '../../../src/modules/broker/config/brokers.config';
describe('BrokerService (集成测试)', () => {
let service: BrokerService;
let repository: Repository<Broker>;
let module: TestingModule;
beforeAll(async () => {
jest.setTimeout(30000); // 设置超时为 30 秒
// 创建测试模块,使用真实数据库连接
module = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env.development', '.env'],
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
const config = getDatabaseConfig(configService);
// 使用测试数据库(如果配置了),否则使用开发数据库
const testDatabase =
configService.get<string>('DB_DATABASE') ||
(config.database as string);
return {
...config,
database: testDatabase,
synchronize: true, // 测试环境允许同步
dropSchema: false, // 不删除现有数据
} as typeof config;
},
inject: [ConfigService],
}),
BrokerModule,
],
}).compile();
service = module.get<BrokerService>(BrokerService);
repository = module.get<Repository<Broker>>(getRepositoryToken(Broker));
// 清理测试数据(可选)
await repository.clear();
});
afterAll(async () => {
// 测试结束后清理
// await repository.clear();
await module.close();
});
describe.skip('create - 集成测试', () => {
it('应该成功在数据库中创建券商', async () => {
const createBrokerDto: CreateBrokerDto = {
brokerCode: 'HTZQ_TEST',
brokerName: '华泰证券测试',
region: 'CN',
sortOrder: 1,
isActive: true,
};
const result = await service.create(createBrokerDto);
console.log(result);
expect(result).toBeDefined();
expect(result.brokerId).toBeDefined();
expect(result.brokerCode).toBe(createBrokerDto.brokerCode);
expect(result.brokerName).toBe(createBrokerDto.brokerName);
// 验证数据确实保存到数据库
const savedBroker = await repository.findOne({
where: { brokerId: result.brokerId },
});
expect(savedBroker).toBeDefined();
expect(savedBroker?.brokerCode).toBe(createBrokerDto.brokerCode);
// 清理
// await repository.remove(result);
});
it('应该使用数据库默认值', async () => {
const createBrokerDto: CreateBrokerDto = {
brokerCode: 'ZSZQ_TEST',
brokerName: '招商证券测试',
region: 'CN',
// 不提供 sortOrder 和 isActive
};
const result = await service.create(createBrokerDto);
expect(result.sortOrder).toBe(0); // 数据库默认值
expect(result.isActive).toBe(true); // 数据库默认值
// 清理
// await repository.remove(result);
});
});
describe.only('batchCreate - 集成测试', () => {
it('应该成功从配置文件批量创建券商', async () => {
// 从配置文件读取券商数据
const batchCreateDto: BatchCreateBrokerDto = {
brokers: brokersConfig,
};
const result = await service.batchCreate(batchCreateDto);
// 验证创建成功
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBeGreaterThan(0);
// 验证数据确实保存到数据库
const savedBrokers = await repository.find({
where: brokersConfig.map((broker) => ({
brokerCode: broker.brokerCode,
region: broker.region,
})),
});
expect(savedBrokers.length).toBe(brokersConfig.length);
// 验证部分数据
const cnBrokers = savedBrokers.filter((b) => b.region === 'CN');
const hkBrokers = savedBrokers.filter((b) => b.region === 'HK');
const usBrokers = savedBrokers.filter((b) => b.region === 'US');
expect(cnBrokers.length).toBeGreaterThan(0);
expect(hkBrokers.length).toBeGreaterThan(0);
expect(usBrokers.length).toBeGreaterThan(0);
// 验证 brokerImage 为 null 或 undefined
savedBrokers.forEach((broker) => {
expect(broker.brokerImage).toBeFalsy(); // null 或 undefined 都通过
});
// 注意:不删除数据,保留在数据库中
});
});
});