// @vitest-environment happy-dom import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { UndoManager } from '@presentation/services/UndoManager'; describe('UndoManager', () => { beforeEach(() => { UndoManager.clear(); // Reset le callback UndoManager.onUndo(() => {}); }); afterEach(() => { // Toujours nettoyer electronAPI sans supprimer window delete (window as any).electronAPI; }); describe('snapshot / canUndo / label', () => { it('canUndo retourne false sans snapshot', () => { expect(UndoManager.canUndo()).toBe(false); }); it('canUndo retourne true après un snapshot', () => { UndoManager.snapshot('{"data":1}', 'test'); expect(UndoManager.canUndo()).toBe(true); }); it('label retourne le label du snapshot', () => { UndoManager.snapshot('{}', 'Suppression enclos'); expect(UndoManager.label()).toBe('Suppression enclos'); }); it('label retourne une chaîne vide sans snapshot', () => { expect(UndoManager.label()).toBe(''); }); it('un nouveau snapshot écrase le précédent (1 seul niveau)', () => { UndoManager.snapshot('{"v":1}', 'premier'); UndoManager.snapshot('{"v":2}', 'second'); expect(UndoManager.label()).toBe('second'); }); }); describe('clear', () => { it('clear supprime le snapshot', () => { UndoManager.snapshot('{}', 'test'); expect(UndoManager.canUndo()).toBe(true); UndoManager.clear(); expect(UndoManager.canUndo()).toBe(false); }); it('label retourne vide après clear', () => { UndoManager.snapshot('{}', 'test'); UndoManager.clear(); expect(UndoManager.label()).toBe(''); }); }); describe('expiration', () => { it('canUndo retourne false après expiration (10s)', () => { UndoManager.snapshot('{}', 'test'); vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 11_000); expect(UndoManager.canUndo()).toBe(false); vi.restoreAllMocks(); }); it('canUndo retourne true avant expiration', () => { UndoManager.snapshot('{}', 'test'); vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 5_000); expect(UndoManager.canUndo()).toBe(true); vi.restoreAllMocks(); }); }); describe('undo', () => { it('undo retourne false sans snapshot', () => { expect(UndoManager.undo()).toBe(false); }); it('undo retourne false sans electronAPI', () => { UndoManager.snapshot('{}', 'test'); expect(UndoManager.undo()).toBe(false); }); it('undo appelle saveData et le callback', () => { const saveData = vi.fn(); const undoCallback = vi.fn(); (window as any).electronAPI = { saveData }; UndoManager.onUndo(undoCallback); UndoManager.snapshot('{"restored":true}', 'test'); const result = UndoManager.undo(); expect(result).toBe(true); expect(saveData).toHaveBeenCalledWith('{"restored":true}'); expect(undoCallback).toHaveBeenCalled(); expect(UndoManager.canUndo()).toBe(false); }); it('undo ne fonctionne pas deux fois de suite', () => { const saveData = vi.fn(); (window as any).electronAPI = { saveData }; UndoManager.onUndo(() => {}); UndoManager.snapshot('{}', 'test'); UndoManager.undo(); expect(UndoManager.undo()).toBe(false); }); }); describe('snapshotCurrent', () => { it('retourne false sans electronAPI', async () => { const result = await UndoManager.snapshotCurrent('test'); expect(result).toBe(false); }); it('retourne false si loadData retourne null', async () => { (window as any).electronAPI = { loadData: vi.fn().mockResolvedValue(null) }; const result = await UndoManager.snapshotCurrent('test'); expect(result).toBe(false); }); it('prend un snapshot si loadData retourne des données', async () => { (window as any).electronAPI = { loadData: vi.fn().mockResolvedValue('{"ok":true}') }; const result = await UndoManager.snapshotCurrent('Suppression DD'); expect(result).toBe(true); expect(UndoManager.canUndo()).toBe(true); expect(UndoManager.label()).toBe('Suppression DD'); }); }); });