122 lines
3.9 KiB
TypeScript
122 lines
3.9 KiB
TypeScript
|
|
/**
|
||
|
|
* CADDocument Tests (Task A2b).
|
||
|
|
* Kern-Verhalten: CRUD, Shallow-Merge, Transaktion = 1 Undo-Schritt,
|
||
|
|
* undo/redo-Stacks, deleteElements selektiv.
|
||
|
|
*/
|
||
|
|
import { describe, it, expect } from 'vitest';
|
||
|
|
import { CADDocument } from '../src/kernel/document/CADDocument';
|
||
|
|
import { createInMemoryDoc } from './helpers/inMemoryDoc';
|
||
|
|
import type { CADElement } from '../src/types/cad.types';
|
||
|
|
|
||
|
|
function makeEl(id: string, props: Record<string, unknown> = {}): CADElement {
|
||
|
|
return {
|
||
|
|
id,
|
||
|
|
type: 'rect',
|
||
|
|
layerId: 'layer-1',
|
||
|
|
x: 10,
|
||
|
|
y: 20,
|
||
|
|
width: 30,
|
||
|
|
height: 40,
|
||
|
|
properties: props,
|
||
|
|
} as unknown as CADElement;
|
||
|
|
}
|
||
|
|
|
||
|
|
function makeDoc(): { doc: CADDocument } {
|
||
|
|
const { ydoc } = createInMemoryDoc();
|
||
|
|
return { doc: new CADDocument(ydoc) };
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('CADDocument', () => {
|
||
|
|
it('a) addElement → getAllElements enthaelt es', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.addElement(makeEl('e1'));
|
||
|
|
const all = doc.getAllElements();
|
||
|
|
expect(all.length).toBe(1);
|
||
|
|
expect(all[0].id).toBe('e1');
|
||
|
|
expect(doc.getElement('e1')).toBeDefined();
|
||
|
|
expect(doc.getElement('missing')).toBeUndefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('b) transact um zwei addElements = EIN Undo-Schritt entfernt BEIDE', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.transact(() => {
|
||
|
|
doc.addElement(makeEl('a'));
|
||
|
|
doc.addElement(makeEl('b'));
|
||
|
|
});
|
||
|
|
expect(doc.getAllElements().length).toBe(2);
|
||
|
|
expect(doc.canUndo()).toBe(true);
|
||
|
|
|
||
|
|
expect(doc.undo()).toBe(true);
|
||
|
|
expect(doc.getAllElements().length).toBe(0); // beide weg mit einem undo!
|
||
|
|
expect(doc.canUndo()).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('c) redo stellt beide Elemente wieder her', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.transact(() => {
|
||
|
|
doc.addElement(makeEl('a'));
|
||
|
|
doc.addElement(makeEl('b'));
|
||
|
|
});
|
||
|
|
doc.undo();
|
||
|
|
expect(doc.getAllElements().length).toBe(0);
|
||
|
|
|
||
|
|
expect(doc.canRedo()).toBe(true);
|
||
|
|
expect(doc.redo()).toBe(true);
|
||
|
|
expect(doc.getAllElements().length).toBe(2);
|
||
|
|
expect(doc.getElement('a')).toBeDefined();
|
||
|
|
expect(doc.getElement('b')).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('d) updateElement merged properties SHALLOW (bestehende Keys bleiben)', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.addElement(makeEl('m', { fill: 'red', rotation: 45, stroke: 'black' }));
|
||
|
|
|
||
|
|
doc.updateElement('m', { properties: { fill: 'blue' } });
|
||
|
|
const el = doc.getElement('m')!;
|
||
|
|
expect(el.properties.fill).toBe('blue'); // ueberschrieben
|
||
|
|
expect(el.properties.rotation).toBe(45); // erhalten
|
||
|
|
expect(el.properties.stroke).toBe('black'); // erhalten
|
||
|
|
});
|
||
|
|
|
||
|
|
it('d2) updateElement kann Top-Level-Felder setzen und wirft bei fehlender ID', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.addElement(makeEl('m'));
|
||
|
|
doc.updateElement('m', { x: 999 });
|
||
|
|
expect(doc.getElement('m')!.x).toBe(999);
|
||
|
|
expect(() => doc.updateElement('ghost', { x: 1 })).toThrow(/nicht gefunden/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('e) deleteElements entfernt nur die genannten IDs', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.transact(() => {
|
||
|
|
doc.addElement(makeEl('keep1'));
|
||
|
|
doc.addElement(makeEl('del1'));
|
||
|
|
doc.addElement(makeEl('del2'));
|
||
|
|
doc.addElement(makeEl('keep2'));
|
||
|
|
});
|
||
|
|
|
||
|
|
doc.deleteElements(['del1', 'del2', 'unbekannt']); // unbekannte still ignorieren
|
||
|
|
const ids = doc.getAllElements().map((e) => e.id).sort();
|
||
|
|
expect(ids).toEqual(['keep1', 'keep2']);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('undo nach deleteElements stellt geloeschte Elemente wieder her', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
doc.addElement(makeEl('x1'));
|
||
|
|
doc.addElement(makeEl('x2'));
|
||
|
|
|
||
|
|
doc.deleteElements(['x1']);
|
||
|
|
expect(doc.getAllElements().length).toBe(1);
|
||
|
|
|
||
|
|
doc.undo(); // Delete rueckgaengig
|
||
|
|
expect(doc.getAllElements().length).toBe(2);
|
||
|
|
expect(doc.getElement('x1')).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('undo/redo liefern false auf leeren Stacks', () => {
|
||
|
|
const { doc } = makeDoc();
|
||
|
|
expect(doc.undo()).toBe(false);
|
||
|
|
expect(doc.redo()).toBe(false);
|
||
|
|
});
|
||
|
|
});
|