video-shuoshan/web/test/unit/generationStore.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

219 lines
7.6 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
// Stub localStorage before auth store initialization (imported transitively by generation store)
vi.stubGlobal('localStorage', {
getItem: vi.fn(() => null),
setItem: vi.fn(),
removeItem: vi.fn(),
clear: vi.fn(),
length: 0,
key: vi.fn(() => null),
});
// Mock auth API to prevent network calls from auth store
vi.mock('../../src/lib/api', () => ({
authApi: {
login: vi.fn(),
register: vi.fn(),
refreshToken: vi.fn(),
getMe: vi.fn(),
},
videoApi: { generate: vi.fn().mockResolvedValue({ data: { remaining_quota: 45 } }) },
adminApi: { getStats: vi.fn(), getUserRankings: vi.fn(), updateUserQuota: vi.fn() },
default: { interceptors: { request: { use: vi.fn() }, response: { use: vi.fn() } } },
}));
vi.mock('../../src/components/Toast', () => ({
showToast: vi.fn(),
}));
import { useGenerationStore } from '../../src/store/generation';
import { useInputBarStore } from '../../src/store/inputBar';
function createMockFile(name: string, type: string): File {
return new File(['mock'], name, { type });
}
describe('Generation Store', () => {
beforeEach(() => {
vi.useFakeTimers();
useInputBarStore.getState().reset();
useGenerationStore.setState({ tasks: [] });
});
afterEach(() => {
vi.useRealTimers();
});
describe('addTask', () => {
it('should return null when canSubmit is false', () => {
const result = useGenerationStore.getState().addTask();
expect(result).toBeNull();
});
it('should create a task when prompt has text', () => {
useInputBarStore.getState().setPrompt('test prompt');
const id = useGenerationStore.getState().addTask();
expect(id).not.toBeNull();
expect(useGenerationStore.getState().tasks).toHaveLength(1);
});
it('should create task with correct properties', () => {
useInputBarStore.getState().setPrompt('a beautiful scene');
useInputBarStore.getState().setModel('seedance_2.0_fast');
useInputBarStore.getState().setAspectRatio('16:9');
useInputBarStore.getState().setDuration(10);
useGenerationStore.getState().addTask();
const task = useGenerationStore.getState().tasks[0];
expect(task.prompt).toBe('a beautiful scene');
expect(task.model).toBe('seedance_2.0_fast');
expect(task.aspectRatio).toBe('16:9');
expect(task.duration).toBe(10);
expect(task.mode).toBe('universal');
expect(task.status).toBe('generating');
expect(task.progress).toBe(0);
});
it('should snapshot references in universal mode', () => {
useInputBarStore.getState().addReferences([
createMockFile('img1.jpg', 'image/jpeg'),
createMockFile('img2.jpg', 'image/jpeg'),
]);
useGenerationStore.getState().addTask();
const task = useGenerationStore.getState().tasks[0];
expect(task.references).toHaveLength(2);
expect(task.references[0].type).toBe('image');
});
it('should snapshot frames in keyframe mode', () => {
useInputBarStore.getState().switchMode('keyframe');
useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg'));
useInputBarStore.getState().setLastFrame(createMockFile('last.jpg', 'image/jpeg'));
useGenerationStore.getState().addTask();
const task = useGenerationStore.getState().tasks[0];
expect(task.references).toHaveLength(2);
expect(task.references[0].label).toBe('首帧');
expect(task.references[1].label).toBe('尾帧');
});
it('should clear input after submit', () => {
useInputBarStore.getState().setPrompt('test');
useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]);
useGenerationStore.getState().addTask();
expect(useInputBarStore.getState().prompt).toBe('');
expect(useInputBarStore.getState().references).toHaveLength(0);
});
it('should prepend new tasks (newest first)', () => {
useInputBarStore.getState().setPrompt('first');
useGenerationStore.getState().addTask();
useInputBarStore.getState().setPrompt('second');
useGenerationStore.getState().addTask();
const tasks = useGenerationStore.getState().tasks;
expect(tasks).toHaveLength(2);
expect(tasks[0].prompt).toBe('second');
expect(tasks[1].prompt).toBe('first');
});
it('should simulate progress over time', () => {
useInputBarStore.getState().setPrompt('test');
useGenerationStore.getState().addTask();
// Advance timers to trigger progress
vi.advanceTimersByTime(2000);
const task = useGenerationStore.getState().tasks[0];
expect(task.progress).toBeGreaterThan(0);
});
});
describe('removeTask', () => {
it('should remove a task by id', () => {
useInputBarStore.getState().setPrompt('test');
const id = useGenerationStore.getState().addTask()!;
expect(useGenerationStore.getState().tasks).toHaveLength(1);
useGenerationStore.getState().removeTask(id);
expect(useGenerationStore.getState().tasks).toHaveLength(0);
});
it('should not affect other tasks', () => {
useInputBarStore.getState().setPrompt('first');
const id1 = useGenerationStore.getState().addTask()!;
useInputBarStore.getState().setPrompt('second');
useGenerationStore.getState().addTask();
useGenerationStore.getState().removeTask(id1);
expect(useGenerationStore.getState().tasks).toHaveLength(1);
expect(useGenerationStore.getState().tasks[0].prompt).toBe('second');
});
});
describe('reEdit', () => {
it('should restore prompt from task', () => {
useInputBarStore.getState().setPrompt('original prompt');
const id = useGenerationStore.getState().addTask()!;
// Input is cleared after submit
expect(useInputBarStore.getState().prompt).toBe('');
useGenerationStore.getState().reEdit(id);
expect(useInputBarStore.getState().prompt).toBe('original prompt');
});
it('should restore settings from task', () => {
useInputBarStore.getState().setPrompt('test');
useInputBarStore.getState().setAspectRatio('16:9');
useInputBarStore.getState().setDuration(10);
const id = useGenerationStore.getState().addTask()!;
// Reset to defaults
useInputBarStore.getState().setAspectRatio('21:9');
useInputBarStore.getState().setDuration(15);
useGenerationStore.getState().reEdit(id);
expect(useInputBarStore.getState().aspectRatio).toBe('16:9');
expect(useInputBarStore.getState().duration).toBe(10);
});
it('should do nothing for non-existent task', () => {
useInputBarStore.getState().setPrompt('existing');
useGenerationStore.getState().reEdit('non_existent_id');
expect(useInputBarStore.getState().prompt).toBe('existing');
});
});
describe('regenerate', () => {
it('should create a new task based on existing one', () => {
useInputBarStore.getState().setPrompt('test');
useGenerationStore.getState().addTask();
const originalId = useGenerationStore.getState().tasks[0].id;
useGenerationStore.getState().regenerate(originalId);
expect(useGenerationStore.getState().tasks).toHaveLength(2);
const newTask = useGenerationStore.getState().tasks[0]; // newest first
expect(newTask.id).not.toBe(originalId);
expect(newTask.prompt).toBe('test');
expect(newTask.status).toBe('generating');
expect(newTask.progress).toBe(0);
});
it('should do nothing for non-existent task', () => {
useGenerationStore.getState().regenerate('non_existent');
expect(useGenerationStore.getState().tasks).toHaveLength(0);
});
});
});