import { describe, it, expect, beforeEach, vi } from 'vitest'; import { useInputBarStore } from '../../src/store/inputBar'; function createMockFile(name: string, type: string): File { return new File(['mock'], name, { type }); } describe('InputBar Store', () => { beforeEach(() => { useInputBarStore.getState().reset(); }); describe('Initial State', () => { it('should have correct default values', () => { const state = useInputBarStore.getState(); expect(state.generationType).toBe('video'); expect(state.mode).toBe('universal'); expect(state.model).toBe('seedance_2.0'); expect(state.aspectRatio).toBe('21:9'); expect(state.duration).toBe(15); expect(state.prompt).toBe(''); expect(state.references).toEqual([]); expect(state.firstFrame).toBeNull(); expect(state.lastFrame).toBeNull(); }); }); describe('Generation Type', () => { it('should set generation type', () => { useInputBarStore.getState().setGenerationType('image'); expect(useInputBarStore.getState().generationType).toBe('image'); }); }); describe('Model Selection', () => { it('should set model', () => { useInputBarStore.getState().setModel('seedance_2.0_fast'); expect(useInputBarStore.getState().model).toBe('seedance_2.0_fast'); }); }); describe('Aspect Ratio', () => { it('should set aspect ratio and save as previous', () => { useInputBarStore.getState().setAspectRatio('16:9'); const state = useInputBarStore.getState(); expect(state.aspectRatio).toBe('16:9'); expect(state.prevAspectRatio).toBe('16:9'); }); }); describe('Duration', () => { it('should set duration in universal mode and save as previous', () => { useInputBarStore.getState().setDuration(10); const state = useInputBarStore.getState(); expect(state.duration).toBe(10); expect(state.prevDuration).toBe(10); }); it('should set duration in keyframe mode without saving as previous', () => { useInputBarStore.getState().switchMode('keyframe'); useInputBarStore.getState().setDuration(10); const state = useInputBarStore.getState(); expect(state.duration).toBe(10); expect(state.prevDuration).toBe(15); // original default }); }); describe('Prompt', () => { it('should set prompt text', () => { useInputBarStore.getState().setPrompt('test prompt'); expect(useInputBarStore.getState().prompt).toBe('test prompt'); }); }); describe('Universal References', () => { it('should add references', () => { const files = [createMockFile('img1.jpg', 'image/jpeg')]; useInputBarStore.getState().addReferences(files); expect(useInputBarStore.getState().references).toHaveLength(1); expect(useInputBarStore.getState().references[0].type).toBe('image'); }); it('should limit references to 5', () => { const files = Array.from({ length: 6 }, (_, i) => createMockFile(`img${i}.jpg`, 'image/jpeg') ); useInputBarStore.getState().addReferences(files); expect(useInputBarStore.getState().references).toHaveLength(5); }); it('should not add more when already at 5', () => { const files = Array.from({ length: 5 }, (_, i) => createMockFile(`img${i}.jpg`, 'image/jpeg') ); useInputBarStore.getState().addReferences(files); expect(useInputBarStore.getState().references).toHaveLength(5); useInputBarStore.getState().addReferences([createMockFile('extra.jpg', 'image/jpeg')]); expect(useInputBarStore.getState().references).toHaveLength(5); }); it('should detect video files correctly', () => { const files = [createMockFile('vid.mp4', 'video/mp4')]; useInputBarStore.getState().addReferences(files); expect(useInputBarStore.getState().references[0].type).toBe('video'); }); it('should remove a reference by id', () => { const files = [createMockFile('img1.jpg', 'image/jpeg')]; useInputBarStore.getState().addReferences(files); const id = useInputBarStore.getState().references[0].id; useInputBarStore.getState().removeReference(id); expect(useInputBarStore.getState().references).toHaveLength(0); }); it('should call revokeObjectURL when removing reference', () => { const files = [createMockFile('img1.jpg', 'image/jpeg')]; useInputBarStore.getState().addReferences(files); const id = useInputBarStore.getState().references[0].id; useInputBarStore.getState().removeReference(id); expect(URL.revokeObjectURL).toHaveBeenCalled(); }); it('should clear all references', () => { const files = [ createMockFile('img1.jpg', 'image/jpeg'), createMockFile('img2.jpg', 'image/jpeg'), ]; useInputBarStore.getState().addReferences(files); useInputBarStore.getState().clearReferences(); expect(useInputBarStore.getState().references).toHaveLength(0); }); }); describe('Keyframe Frames', () => { it('should set first frame', () => { const file = createMockFile('first.jpg', 'image/jpeg'); useInputBarStore.getState().setFirstFrame(file); const state = useInputBarStore.getState(); expect(state.firstFrame).not.toBeNull(); expect(state.firstFrame!.label).toBe('首帧'); }); it('should set last frame', () => { const file = createMockFile('last.jpg', 'image/jpeg'); useInputBarStore.getState().setLastFrame(file); const state = useInputBarStore.getState(); expect(state.lastFrame).not.toBeNull(); expect(state.lastFrame!.label).toBe('尾帧'); }); it('should clear first frame when setting null', () => { useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg')); useInputBarStore.getState().setFirstFrame(null); expect(useInputBarStore.getState().firstFrame).toBeNull(); }); it('should revoke old URL when replacing frame', () => { useInputBarStore.getState().setFirstFrame(createMockFile('a.jpg', 'image/jpeg')); useInputBarStore.getState().setFirstFrame(createMockFile('b.jpg', 'image/jpeg')); expect(URL.revokeObjectURL).toHaveBeenCalled(); }); }); describe('canSubmit', () => { it('should return false when no content', () => { expect(useInputBarStore.getState().canSubmit()).toBe(false); }); it('should return true when prompt has text', () => { useInputBarStore.getState().setPrompt('hello'); expect(useInputBarStore.getState().canSubmit()).toBe(true); }); it('should return false for whitespace-only prompt', () => { useInputBarStore.getState().setPrompt(' '); expect(useInputBarStore.getState().canSubmit()).toBe(false); }); it('should return true when universal references exist', () => { useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]); expect(useInputBarStore.getState().canSubmit()).toBe(true); }); it('should return true when first frame exists in keyframe mode', () => { useInputBarStore.getState().switchMode('keyframe'); useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg')); expect(useInputBarStore.getState().canSubmit()).toBe(true); }); it('should return true when last frame exists in keyframe mode', () => { useInputBarStore.getState().switchMode('keyframe'); useInputBarStore.getState().setLastFrame(createMockFile('last.jpg', 'image/jpeg')); expect(useInputBarStore.getState().canSubmit()).toBe(true); }); }); describe('Mode Switching', () => { it('should switch to keyframe mode with correct defaults', () => { useInputBarStore.getState().switchMode('keyframe'); const state = useInputBarStore.getState(); expect(state.mode).toBe('keyframe'); expect(state.duration).toBe(5); expect(state.references).toEqual([]); }); it('should clear universal references when switching to keyframe', () => { useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]); useInputBarStore.getState().switchMode('keyframe'); expect(useInputBarStore.getState().references).toEqual([]); }); it('should restore aspect ratio and duration when switching back to universal', () => { useInputBarStore.getState().setAspectRatio('16:9'); useInputBarStore.getState().setDuration(10); useInputBarStore.getState().switchMode('keyframe'); useInputBarStore.getState().switchMode('universal'); const state = useInputBarStore.getState(); expect(state.aspectRatio).toBe('16:9'); expect(state.duration).toBe(10); }); it('should clear keyframe data when switching back to universal', () => { useInputBarStore.getState().switchMode('keyframe'); useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg')); useInputBarStore.getState().setLastFrame(createMockFile('last.jpg', 'image/jpeg')); useInputBarStore.getState().switchMode('universal'); const state = useInputBarStore.getState(); expect(state.firstFrame).toBeNull(); expect(state.lastFrame).toBeNull(); }); it('should not do anything when switching to same mode', () => { useInputBarStore.getState().setPrompt('test'); useInputBarStore.getState().switchMode('universal'); expect(useInputBarStore.getState().prompt).toBe('test'); }); it('should preserve prompt text across mode switches', () => { useInputBarStore.getState().setPrompt('my prompt'); useInputBarStore.getState().switchMode('keyframe'); expect(useInputBarStore.getState().prompt).toBe('my prompt'); useInputBarStore.getState().switchMode('universal'); expect(useInputBarStore.getState().prompt).toBe('my prompt'); }); }); describe('Reset', () => { it('should reset all state to defaults', () => { useInputBarStore.getState().setPrompt('hello'); useInputBarStore.getState().setModel('seedance_2.0_fast'); useInputBarStore.getState().setAspectRatio('16:9'); useInputBarStore.getState().setDuration(5); useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]); useInputBarStore.getState().reset(); const state = useInputBarStore.getState(); expect(state.prompt).toBe(''); expect(state.model).toBe('seedance_2.0'); expect(state.aspectRatio).toBe('21:9'); expect(state.duration).toBe(15); expect(state.references).toEqual([]); expect(state.mode).toBe('universal'); expect(state.generationType).toBe('video'); }); }); });