1
0

feat: 前端集成 Prettier 代码格式化

This commit is contained in:
2026-04-24 13:40:53 +08:00
parent 52007c9461
commit 365943e4c4
61 changed files with 1968 additions and 1698 deletions

View File

@@ -1,10 +1,10 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import React from 'react';
import { useStats } from '@/hooks/useStats';
import type { UsageStats, StatsQueryParams } from '@/types';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import React from 'react'
import { useStats } from '@/hooks/useStats'
import type { UsageStats, StatsQueryParams } from '@/types'
// Test data
const mockStats: UsageStats[] = [
@@ -22,7 +22,7 @@ const mockStats: UsageStats[] = [
requestCount: 50,
date: '2026-04-01',
},
];
]
const mockFilteredStats: UsageStats[] = [
{
@@ -32,24 +32,24 @@ const mockFilteredStats: UsageStats[] = [
requestCount: 200,
date: '2026-04-01',
},
];
]
// Track the request URL for assertions
let capturedUrl: URL | null = null;
let capturedUrl: URL | null = null
// MSW handlers
const handlers = [
http.get('/api/stats', ({ request }) => {
capturedUrl = new URL(request.url);
const providerId = capturedUrl.searchParams.get('provider_id');
capturedUrl = new URL(request.url)
const providerId = capturedUrl.searchParams.get('provider_id')
if (providerId === 'provider-2') {
return HttpResponse.json(mockFilteredStats);
return HttpResponse.json(mockFilteredStats)
}
return HttpResponse.json(mockStats);
return HttpResponse.json(mockStats)
}),
];
]
const server = setupServer(...handlers);
const server = setupServer(...handlers)
function createTestQueryClient() {
return new QueryClient({
@@ -57,43 +57,39 @@ function createTestQueryClient() {
queries: { retry: false },
mutations: { retry: false },
},
});
})
}
function createWrapper() {
const testQueryClient = createTestQueryClient();
const testQueryClient = createTestQueryClient()
return function Wrapper({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={testQueryClient}>
{children}
</QueryClientProvider>
);
};
return <QueryClientProvider client={testQueryClient}>{children}</QueryClientProvider>
}
}
beforeAll(() => server.listen());
beforeAll(() => server.listen())
afterEach(() => {
server.resetHandlers();
capturedUrl = null;
});
afterAll(() => server.close());
server.resetHandlers()
capturedUrl = null
})
afterAll(() => server.close())
describe('useStats', () => {
it('fetches stats without params', async () => {
const { result } = renderHook(() => useStats(), {
wrapper: createWrapper(),
});
})
await waitFor(() => expect(result.current.isSuccess).toBe(true));
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(result.current.data).toEqual(mockStats);
expect(result.current.data).toHaveLength(2);
expect(result.current.data![0]!.modelName).toBe('gpt-4o');
expect(result.current.data![1]!.requestCount).toBe(50);
expect(result.current.data).toEqual(mockStats)
expect(result.current.data).toHaveLength(2)
expect(result.current.data![0]!.modelName).toBe('gpt-4o')
expect(result.current.data![1]!.requestCount).toBe(50)
// Verify no query params were sent
expect(capturedUrl!.search).toBe('');
});
expect(capturedUrl!.search).toBe('')
})
it('with filter params passes them correctly', async () => {
const params: StatsQueryParams = {
@@ -101,40 +97,40 @@ describe('useStats', () => {
modelName: 'claude-sonnet-4-5',
startDate: '2026-04-01',
endDate: '2026-04-15',
};
}
const { result } = renderHook(() => useStats(params), {
wrapper: createWrapper(),
});
})
await waitFor(() => expect(result.current.isSuccess).toBe(true));
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(result.current.data).toEqual(mockFilteredStats);
expect(result.current.data).toHaveLength(1);
expect(result.current.data![0]!.modelName).toBe('claude-sonnet-4-5');
expect(result.current.data).toEqual(mockFilteredStats)
expect(result.current.data).toHaveLength(1)
expect(result.current.data![0]!.modelName).toBe('claude-sonnet-4-5')
// Verify query params were passed correctly (snake_case)
expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-2');
expect(capturedUrl!.searchParams.get('model_name')).toBe('claude-sonnet-4-5');
expect(capturedUrl!.searchParams.get('start_date')).toBe('2026-04-01');
expect(capturedUrl!.searchParams.get('end_date')).toBe('2026-04-15');
});
expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-2')
expect(capturedUrl!.searchParams.get('model_name')).toBe('claude-sonnet-4-5')
expect(capturedUrl!.searchParams.get('start_date')).toBe('2026-04-01')
expect(capturedUrl!.searchParams.get('end_date')).toBe('2026-04-15')
})
it('with partial filter params only sends provided params', async () => {
const params: StatsQueryParams = {
providerId: 'provider-1',
};
}
const { result } = renderHook(() => useStats(params), {
wrapper: createWrapper(),
});
})
await waitFor(() => expect(result.current.isSuccess).toBe(true));
await waitFor(() => expect(result.current.isSuccess).toBe(true))
// Verify only provider_id was sent
expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-1');
expect(capturedUrl!.searchParams.get('model_name')).toBeNull();
expect(capturedUrl!.searchParams.get('start_date')).toBeNull();
expect(capturedUrl!.searchParams.get('end_date')).toBeNull();
});
});
expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-1')
expect(capturedUrl!.searchParams.get('model_name')).toBeNull()
expect(capturedUrl!.searchParams.get('start_date')).toBeNull()
expect(capturedUrl!.searchParams.get('end_date')).toBeNull()
})
})