import { beforeEach, describe, expect, it } from 'vitest'; import { resetStore } from '../test/storeTestUtils'; import { useStore } from './useStore'; describe('useStore', () => { beforeEach(() => { resetStore(); }); it('stores and clears auth state with localStorage', () => { useStore.getState().login('token-1', { id: 1, username: 'admin', role: 'admin' }); expect(useStore.getState().isAuthenticated).toBe(true); expect(useStore.getState().token).toBe('token-1'); expect(useStore.getState().currentUser?.username).toBe('admin'); expect(localStorage.getItem('token')).toBe('token-1'); useStore.getState().logout(); expect(useStore.getState().isAuthenticated).toBe(false); expect(useStore.getState().currentUser).toBeNull(); expect(useStore.getState().projects).toEqual([]); expect(useStore.getState().frames).toEqual([]); expect(localStorage.getItem('token')).toBeNull(); }); it('manages projects, frames, masks, annotations and templates', () => { const project = { id: '1', name: 'Project', status: 'ready' as const }; useStore.getState().addProject(project); useStore.getState().updateProject({ ...project, name: 'Updated' }); useStore.getState().setCurrentProject(project); useStore.getState().setFrames([{ id: 'f1', projectId: '1', index: 0, url: '/f1.jpg', width: 640, height: 360 }]); useStore.getState().setCurrentFrame(0); useStore.getState().addMask({ id: 'm1', frameId: 'f1', pathData: 'M 0 0 Z', label: 'mask', color: '#fff' }); useStore.getState().setSelectedMaskIds(['m1']); useStore.getState().setMaskPreviewOpacity(35); useStore.getState().setBrushSize(36); useStore.getState().setEraserSize(44); useStore.getState().updateMask('m1', { label: 'updated mask', saveStatus: 'dirty' }); useStore.getState().addAnnotation({ id: 'a1', frameId: 'f1', type: 'mask', points: [], label: 'ann', color: '#fff' }); useStore.getState().addTemplate({ id: 't1', name: 'Template', classes: [], rules: [] }); useStore.getState().updateTemplate({ id: 't1', name: 'Template 2', classes: [], rules: [] }); useStore.getState().setActiveClass({ id: 'c1', name: '胆囊', color: '#ff0000', zIndex: 10 }); expect(useStore.getState().projects[0].name).toBe('Updated'); expect(useStore.getState().currentProject?.id).toBe('1'); expect(useStore.getState().frames).toHaveLength(1); expect(useStore.getState().currentFrameIndex).toBe(0); expect(useStore.getState().selectedMaskIds).toEqual(['m1']); expect(useStore.getState().maskPreviewOpacity).toBe(35); expect(useStore.getState().brushSize).toBe(36); expect(useStore.getState().eraserSize).toBe(44); expect(useStore.getState().masks[0]).toEqual(expect.objectContaining({ label: 'updated mask', saveStatus: 'dirty' })); expect(useStore.getState().annotations).toHaveLength(1); expect(useStore.getState().templates[0].name).toBe('Template 2'); expect(useStore.getState().activeClassId).toBe('c1'); useStore.getState().removeAnnotation('a1'); useStore.getState().clearMasks(); useStore.getState().removeTemplate('t1'); expect(useStore.getState().annotations).toEqual([]); expect(useStore.getState().masks).toEqual([]); expect(useStore.getState().selectedMaskIds).toEqual([]); expect(useStore.getState().templates).toEqual([]); }); it('keeps undo and redo history for mask edits', () => { useStore.getState().addMask({ id: 'm1', frameId: 'f1', pathData: 'M 0 0 Z', label: 'mask 1', color: '#fff' }); useStore.getState().addMask({ id: 'm2', frameId: 'f1', pathData: 'M 1 1 Z', label: 'mask 2', color: '#000' }); expect(useStore.getState().masks.map((mask) => mask.id)).toEqual(['m1', 'm2']); useStore.getState().undoMasks(); expect(useStore.getState().masks.map((mask) => mask.id)).toEqual(['m1']); useStore.getState().redoMasks(); expect(useStore.getState().masks.map((mask) => mask.id)).toEqual(['m1', 'm2']); }); });