feat: 完成前端重构,采用 Ant Design 5 和完整测试体系
- 采用 Ant Design 5 作为 UI 组件库,替换自定义组件 - 集成 React Router v7 提供路由导航 - 使用 TanStack Query v5 管理数据获取和缓存 - 建立 Vitest + React Testing Library 测试体系 - 添加 Playwright E2E 测试覆盖 - 使用 MSW mock API 响应 - 配置 TypeScript strict 模式 - 采用 SCSS Modules 组织样式 - 更新 OpenSpec 规格以反映前端架构变更 - 归档 frontend-refactor 变更记录
This commit is contained in:
131
frontend/src/__tests__/api/stats.test.ts
Normal file
131
frontend/src/__tests__/api/stats.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { getStats } from '@/api/stats';
|
||||
|
||||
const mockStats = [
|
||||
{
|
||||
id: 1,
|
||||
provider_id: 'prov-1',
|
||||
model_name: 'gpt-4',
|
||||
request_count: 100,
|
||||
date: '2025-01-15',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
provider_id: 'prov-2',
|
||||
model_name: 'claude-3',
|
||||
request_count: 50,
|
||||
date: '2025-01-16',
|
||||
},
|
||||
];
|
||||
|
||||
describe('stats API', () => {
|
||||
const server = setupServer();
|
||||
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
|
||||
afterEach(() => server.resetHandlers());
|
||||
afterAll(() => server.close());
|
||||
|
||||
describe('getStats', () => {
|
||||
it('calls /api/stats without params', async () => {
|
||||
let receivedUrl: string | null = null;
|
||||
|
||||
server.use(
|
||||
http.get('/api/stats', ({ request }) => {
|
||||
receivedUrl = request.url;
|
||||
return HttpResponse.json(mockStats);
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await getStats();
|
||||
|
||||
expect(receivedUrl).toMatch(/\/api\/stats$/);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
providerId: 'prov-1',
|
||||
modelName: 'gpt-4',
|
||||
requestCount: 100,
|
||||
date: '2025-01-15',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
providerId: 'prov-2',
|
||||
modelName: 'claude-3',
|
||||
requestCount: 50,
|
||||
date: '2025-01-16',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('builds correct query string with snake_case keys when params are provided', async () => {
|
||||
let receivedUrl: string | null = null;
|
||||
|
||||
server.use(
|
||||
http.get('/api/stats', ({ request }) => {
|
||||
receivedUrl = request.url;
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
);
|
||||
|
||||
await getStats({
|
||||
providerId: 'prov-1',
|
||||
modelName: 'gpt-4',
|
||||
startDate: '2025-01-01',
|
||||
endDate: '2025-01-31',
|
||||
});
|
||||
|
||||
expect(receivedUrl).toContain('provider_id=prov-1');
|
||||
expect(receivedUrl).toContain('model_name=gpt-4');
|
||||
expect(receivedUrl).toContain('start_date=2025-01-01');
|
||||
expect(receivedUrl).toContain('end_date=2025-01-31');
|
||||
});
|
||||
|
||||
it('omits undefined params from query string', async () => {
|
||||
let receivedUrl: string | null = null;
|
||||
|
||||
server.use(
|
||||
http.get('/api/stats', ({ request }) => {
|
||||
receivedUrl = request.url;
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
);
|
||||
|
||||
await getStats({
|
||||
providerId: 'prov-1',
|
||||
});
|
||||
|
||||
expect(receivedUrl).toContain('provider_id=prov-1');
|
||||
expect(receivedUrl).not.toContain('model_name');
|
||||
expect(receivedUrl).not.toContain('start_date');
|
||||
expect(receivedUrl).not.toContain('end_date');
|
||||
});
|
||||
|
||||
it('returns UsageStats array with camelCase keys', async () => {
|
||||
server.use(
|
||||
http.get('/api/stats', () => {
|
||||
return HttpResponse.json(mockStats);
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await getStats();
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toEqual({
|
||||
id: 1,
|
||||
providerId: 'prov-1',
|
||||
modelName: 'gpt-4',
|
||||
requestCount: 100,
|
||||
date: '2025-01-15',
|
||||
});
|
||||
expect(result[1]).toEqual({
|
||||
id: 2,
|
||||
providerId: 'prov-2',
|
||||
modelName: 'claude-3',
|
||||
requestCount: 50,
|
||||
date: '2025-01-16',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user