/** * Task G1 – Layout-Datenmodell: Yjs Map layoutId → LayoutDefinition. * * LayoutDefinition: { id, name, viewport: { center: {x,y}, scale }, * frameBlockRef? }. CRUD über CADDocument, undo-getrackt, Persistence * läuft automatisch über die Yjs-Doc-Serialisierung (drawing json). */ import { describe, it, expect } from 'vitest'; import { CADDocument } from '../src/kernel/document/CADDocument'; import { createInMemoryDoc } from './helpers/inMemoryDoc'; function mkDoc(): CADDocument { const { ydoc } = createInMemoryDoc(); return new CADDocument(ydoc); } const LAYOUT = { id: 'layout-1', name: 'A4 Plan', viewport: { center: { x: 100, y: 50 }, scale: 0.5 }, frameBlockRef: 'frame-a4', }; describe('G1: Layout-CRUD', () => { it('addLayout + getLayout: Layout landet mit allen Feldern in der Map', () => { const doc = mkDoc(); doc.addLayout(LAYOUT); const loaded = doc.getLayout('layout-1'); expect(loaded).toBeDefined(); expect(loaded!.name).toBe('A4 Plan'); expect(loaded!.viewport.center.x).toBe(100); expect(loaded!.viewport.center.y).toBe(50); expect(loaded!.viewport.scale).toBe(0.5); expect(loaded!.frameBlockRef).toBe('frame-a4'); }); it('getAllLayouts liefert Array; leer ohne Layouts', () => { const doc = mkDoc(); expect(doc.getAllLayouts()).toHaveLength(0); doc.addLayout(LAYOUT); doc.addLayout({ ...LAYOUT, id: 'layout-2', name: 'A3 Plan' }); const all = doc.getAllLayouts(); expect(all).toHaveLength(2); expect(all.map((l) => l.name)).toContain('A3 Plan'); }); it('updateLayout ändert name und viewport shallow (id/struktur bleibt)', () => { const doc = mkDoc(); doc.addLayout(LAYOUT); doc.updateLayout('layout-1', { name: 'A4 geändert', viewport: { center: { x: 0, y: 0 }, scale: 2 } }); const loaded = doc.getLayout('layout-1'); expect(loaded!.name).toBe('A4 geändert'); expect(loaded!.viewport.scale).toBe(2); expect(loaded!.frameBlockRef).toBe('frame-a4'); // unverändert erhalten }); it('deleteLayout entfernt Layout still (unbekannte ID kein Fehler)', () => { const doc = mkDoc(); doc.addLayout(LAYOUT); doc.deleteLayout('layout-1'); expect(doc.getLayout('layout-1')).toBeUndefined(); expect(() => doc.deleteLayout('gibts-nicht')).not.toThrow(); }); }); describe('G1: Undo-Integration', () => { it('Undo entfernt hinzugefügtes Layout wieder', () => { const doc = mkDoc(); doc.addLayout(LAYOUT); expect(doc.getLayout('layout-1')).toBeDefined(); doc.undo(); expect(doc.getLayout('layout-1')).toBeUndefined(); doc.redo(); expect(doc.getLayout('layout-1')).toBeDefined(); }); it('Layout-Undo ist EIN Schritt (nicht mit Element-Transaktion vermischt)', () => { const doc = mkDoc(); doc.addLayout(LAYOUT); doc.deleteLayout('layout-1'); // Zwei Schritte: undo stellt Löschung wieder her doc.undo(); expect(doc.getLayout('layout-1')).toBeDefined(); doc.undo(); expect(doc.getLayout('layout-1')).toBeUndefined(); }); });