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); }); }); });