import type { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import request from 'supertest'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { MarketDetailController } from '../src/market-overview/detail/market-detail.controller'; import { MarketDetailService } from '../src/market-overview/detail/market-detail.service'; import { TDX_CLIENT_PORT } from '../src/market-overview/market-overview.service'; const indexResponse = { ErrorId: '0', Value: { '000001.SH': { Date: ['20260817', '20260818'], Open: ['100', '102'], High: ['103', '106'], Low: ['99', '101'], Close: ['102', '105'], Amount: ['1000', '1200'], Volume: ['100', '120'], }, }, }; describe('市场详情 HTTP API', () => { let app: INestApplication | undefined; afterEach(async () => { await app?.close(); app = undefined; }); it('返回指数详情并隐藏 TDX 原始字段', async () => { const client = { request: vi.fn().mockResolvedValue(indexResponse) }; const moduleRef = await Test.createTestingModule({ controllers: [MarketDetailController], providers: [MarketDetailService, { provide: TDX_CLIENT_PORT, useValue: client }], }).compile(); app = moduleRef.createNestApplication(); app.setGlobalPrefix('api/v1'); await app.init(); const response = await request(app.getHttpServer()) .get('/api/v1/market-overview/indices/000001.SH/detail?count=2') .expect(200); expect(response.body).toMatchObject({ source: 'tdx', data: { instrument: { code: '000001.SH', name: '上证指数', type: 'index' }, series: [{ time: '20260817' }, { time: '20260818' }], availableViews: { kline: true, intraday: false }, }, }); expect(JSON.stringify(response.body)).not.toContain('ErrorId'); }); it('拒绝越界数量和非法代码且不调用 TDX', async () => { const client = { request: vi.fn() }; const moduleRef = await Test.createTestingModule({ controllers: [MarketDetailController], providers: [MarketDetailService, { provide: TDX_CLIENT_PORT, useValue: client }], }).compile(); app = moduleRef.createNestApplication(); app.setGlobalPrefix('api/v1'); await app.init(); await request(app.getHttpServer()) .get('/api/v1/market-overview/indices/not-a-code/detail') .expect(400); await request(app.getHttpServer()) .get('/api/v1/market-overview/indices/000001.SH/detail?count=121') .expect(400); expect(client.request).not.toHaveBeenCalled(); }); it('板块详情先读目录再返回行业 K 线', async () => { const client = { request: vi .fn() .mockResolvedValueOnce({ ErrorId: '0', Value: [{ Code: '881001.SH', Name: '行业总览' }], }) .mockResolvedValueOnce({ ErrorId: '0', Value: { '881001.SH': { Date: ['20260817', '20260818'], Open: ['100', '102'], High: ['103', '106'], Low: ['99', '101'], Close: ['102', '105'], Amount: ['1000', '1200'], Volume: ['100', '120'], }, }, }), }; const moduleRef = await Test.createTestingModule({ controllers: [MarketDetailController], providers: [MarketDetailService, { provide: TDX_CLIENT_PORT, useValue: client }], }).compile(); app = moduleRef.createNestApplication(); app.setGlobalPrefix('api/v1'); await app.init(); const response = await request(app.getHttpServer()) .get('/api/v1/market-overview/sectors/881001.SH/detail') .expect(200); expect(response.body.data.instrument).toEqual({ code: '881001.SH', name: '行业总览', type: 'sector', }); expect(client.request).toHaveBeenCalledTimes(2); }); });