video-shuoshan/web/test/unit/apiClient.test.ts
zyc ffe92f7b15 Initial commit: 即梦视频生成平台
- web/: React + Vite + TypeScript 前端
- backend/: Django + DRF + SimpleJWT 后端
- prototype/: HTML 设计原型
- docs/: PRD 和设计评审文档
- test: 单元测试 + E2E 极限测试
2026-03-13 09:59:33 +08:00

199 lines
6.6 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
// We test the API module's structure and endpoint definitions
// The actual HTTP calls are mocked; we verify correct URL/method/payload patterns
vi.mock('axios', () => {
const mockAxiosInstance = {
get: vi.fn().mockResolvedValue({ data: {} }),
post: vi.fn().mockResolvedValue({ data: {} }),
put: vi.fn().mockResolvedValue({ data: {} }),
patch: vi.fn().mockResolvedValue({ data: {} }),
interceptors: {
request: { use: vi.fn() },
response: { use: vi.fn() },
},
};
return {
default: {
create: vi.fn(() => mockAxiosInstance),
post: vi.fn(),
},
};
});
import { authApi, videoApi, adminApi, profileApi } from '../../src/lib/api';
import api from '../../src/lib/api';
describe('API Client', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('authApi', () => {
it('should have register method that posts to /auth/register', async () => {
await authApi.register('user1', 'user1@test.com', 'pass123');
expect(api.post).toHaveBeenCalledWith(
'/auth/register',
{ username: 'user1', email: 'user1@test.com', password: 'pass123' }
);
});
it('should have login method that posts to /auth/login', async () => {
await authApi.login('user1', 'pass123');
expect(api.post).toHaveBeenCalledWith(
'/auth/login',
{ username: 'user1', password: 'pass123' }
);
});
it('should have refreshToken method that posts to /auth/token/refresh', async () => {
await authApi.refreshToken('my-refresh-token');
expect(api.post).toHaveBeenCalledWith(
'/auth/token/refresh',
{ refresh: 'my-refresh-token' }
);
});
it('should have getMe method that gets /auth/me', async () => {
await authApi.getMe();
expect(api.get).toHaveBeenCalledWith('/auth/me');
});
});
describe('videoApi', () => {
it('should have generate method that posts FormData to /video/generate', async () => {
const formData = new FormData();
formData.append('prompt', 'test prompt');
await videoApi.generate(formData);
expect(api.post).toHaveBeenCalledWith(
'/video/generate',
formData,
{ headers: { 'Content-Type': 'multipart/form-data' } }
);
});
});
describe('adminApi', () => {
it('should have getStats method that gets /admin/stats', async () => {
await adminApi.getStats();
expect(api.get).toHaveBeenCalledWith('/admin/stats');
});
it('should have getUsers with default params', async () => {
await adminApi.getUsers();
expect(api.get).toHaveBeenCalledWith('/admin/users', { params: {} });
});
it('should have getUsers with search params', async () => {
await adminApi.getUsers({ page: 2, search: 'alice' });
expect(api.get).toHaveBeenCalledWith('/admin/users', {
params: { page: 2, search: 'alice' },
});
});
it('should have updateUserQuota that puts /admin/users/:id/quota', async () => {
await adminApi.updateUserQuota(42, 600, 6000);
expect(api.put).toHaveBeenCalledWith('/admin/users/42/quota', {
daily_seconds_limit: 600,
monthly_seconds_limit: 6000,
});
});
});
});
describe('API Client Configuration', () => {
it('should export authApi with all 4 methods', () => {
expect(authApi).toBeDefined();
expect(typeof authApi.register).toBe('function');
expect(typeof authApi.login).toBe('function');
expect(typeof authApi.refreshToken).toBe('function');
expect(typeof authApi.getMe).toBe('function');
});
it('should export videoApi with generate method', () => {
expect(videoApi).toBeDefined();
expect(typeof videoApi.generate).toBe('function');
});
it('should export adminApi with Phase 3 methods', () => {
expect(adminApi).toBeDefined();
expect(typeof adminApi.getStats).toBe('function');
expect(typeof adminApi.getUsers).toBe('function');
expect(typeof adminApi.getUserDetail).toBe('function');
expect(typeof adminApi.updateUserQuota).toBe('function');
expect(typeof adminApi.updateUserStatus).toBe('function');
expect(typeof adminApi.getRecords).toBe('function');
expect(typeof adminApi.getSettings).toBe('function');
expect(typeof adminApi.updateSettings).toBe('function');
});
it('should export profileApi with Phase 3 methods', () => {
expect(profileApi).toBeDefined();
expect(typeof profileApi.getOverview).toBe('function');
expect(typeof profileApi.getRecords).toBe('function');
});
});
describe('Admin API Phase 3 — Additional Endpoint Tests', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('adminApi.getUserDetail fetches /admin/users/:id', async () => {
await adminApi.getUserDetail(7);
expect(api.get).toHaveBeenCalledWith('/admin/users/7');
});
it('adminApi.updateUserStatus patches /admin/users/:id/status', async () => {
await adminApi.updateUserStatus(5, false);
expect(api.patch).toHaveBeenCalledWith('/admin/users/5/status', { is_active: false });
});
it('adminApi.getRecords fetches /admin/records with params', async () => {
await adminApi.getRecords({ page: 2, search: 'bob', start_date: '2026-03-01' });
expect(api.get).toHaveBeenCalledWith('/admin/records', {
params: { page: 2, search: 'bob', start_date: '2026-03-01' },
});
});
it('adminApi.getSettings fetches /admin/settings', async () => {
await adminApi.getSettings();
expect(api.get).toHaveBeenCalledWith('/admin/settings');
});
it('adminApi.updateSettings puts /admin/settings', async () => {
const settings = {
default_daily_seconds_limit: 900,
default_monthly_seconds_limit: 9000,
announcement: 'test',
announcement_enabled: true,
};
await adminApi.updateSettings(settings);
expect(api.put).toHaveBeenCalledWith('/admin/settings', settings);
});
});
describe('Profile API Phase 3', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('profileApi.getOverview fetches /profile/overview with default period', async () => {
await profileApi.getOverview();
expect(api.get).toHaveBeenCalledWith('/profile/overview', { params: { period: '7d' } });
});
it('profileApi.getOverview supports 30d period', async () => {
await profileApi.getOverview('30d');
expect(api.get).toHaveBeenCalledWith('/profile/overview', { params: { period: '30d' } });
});
it('profileApi.getRecords fetches /profile/records with pagination', async () => {
await profileApi.getRecords(2, 10);
expect(api.get).toHaveBeenCalledWith('/profile/records', {
params: { page: 2, page_size: 10 },
});
});
});