Files
web-cad/frontend/tests/selectToolV2.test.ts
T

101 lines
3.8 KiB
TypeScript

/**
* CAD-14 Phase 3: selectTool V2 — Auswahl direkt auf dem V2-Dokument.
* Klick = hitTest via SelectionBridge, Leerklick leert, Shift additiv,
* Drag = Box-Select (Elemente mit Zentrum in BBox).
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { selectTool } from '../src/plugins/builtin/core-drawing';
import { CADDocument } from '../src/kernel/document/CADDocument';
import { YjsDocument } from '../src/crdt/YjsDocument';
import type { CADElement, Pt } from '../src/types/cad.types';
function pe(x: number, y: number, shift = false): { world: Pt; shift: boolean } {
return { world: { x, y }, shift } as never;
}
function makeCtx(ids: string[], hit: CADElement | null) {
const selected: string[][] = [];
const onChangeCalls: string[][] = [];
const realDoc = new CADDocument(new YjsDocument());
let currentIds = [...ids];
const ctx: any = {
options: {},
selection: {
getIds: () => currentIds,
setIds: (next: string[], additive?: boolean) => {
currentIds = additive ? [...currentIds, ...next] : next;
selected.push(currentIds);
},
hitTest: (_x: number, _y: number, _tol: number) => hit,
onChange: (ids2: string[]) => onChangeCalls.push(ids2),
},
doc: realDoc,
setStatus: () => {},
setPreview: () => {},
};
return { ctx, selected, onChangeCalls, realDoc, getCurrentIds: () => currentIds };
}
function lineEl(id: string, x1: number, y1: number, x2: number, y2: number): CADElement {
return {
id, type: 'line', layerId: 'l', x: (x1 + x2) / 2, y: (y1 + y2) / 2,
width: Math.abs(x2 - x1), height: Math.abs(y2 - y1),
properties: { x1, y1, x2, y2 },
} as unknown as CADElement;
}
describe('CAD-14 Phase 3: selectTool V2', () => {
beforeEach(() => {
selectTool.handlers.cancel?.({ setStatus: () => {}, setPreview: () => {} } as never);
});
it('Manifest: id=select, basic-tag (immer sichtbar)', () => {
expect(selectTool.manifest.id).toBe('select');
expect((selectTool.manifest.tags ?? []).includes('basic')).toBe(true);
});
it('Klick auf Element: hitTest-Treffer wird selektiert (setIds mit ID)', () => {
const el = lineEl('e1', 0, 0, 100, 100);
const { ctx, selected } = makeCtx([], el);
selectTool.handlers.down!(pe(50, 50), ctx);
expect(selected.length).toBe(1);
expect(selected[0]).toEqual(['e1']);
});
it('Leerklick (hitTest null): Auswahl geleert (setIds mit [])', () => {
const { ctx, selected } = makeCtx(['e9'], null);
selectTool.handlers.down!(pe(500, 500), ctx);
expect(selected.length).toBe(1);
expect(selected[0]).toEqual([]);
});
it('Shift-Klick additiv: setIds mit additive=true', () => {
const el = lineEl('e1', 0, 0, 100, 100);
const { ctx, selected } = makeCtx(['e9'], el);
selectTool.handlers.down!(pe(50, 50, true), ctx);
expect(selected.length).toBe(1);
// additive-Variante: bestaehige IDs + neue ID
expect(selected[0]).toEqual(['e9', 'e1']);
});
it('Box-Select: Element mit Zentrum in BBox wird selektiert', () => {
const { ctx, realDoc, getCurrentIds } = makeCtx([], null);
const el = lineEl('e1', 0, 0, 100, 100);
realDoc.addElement(el);
// down in leerer Gegend startet Box (Leerklick leert zuerst — korrekt),
// move zeigt Vorschau, up schliesst BBox um Element.
selectTool.handlers.down!(pe(-10, -10), ctx);
selectTool.handlers.move!(pe(200, 200), ctx);
selectTool.handlers.up!(pe(200, 200), ctx);
expect(getCurrentIds()).toEqual(['e1']);
});
it('onChange feuert nach Klick-Auswahl (App-Kanal)', () => {
const el = lineEl('e1', 0, 0, 100, 100);
const { ctx, onChangeCalls } = makeCtx([], el);
selectTool.handlers.down!(pe(50, 50), ctx);
expect(onChangeCalls.length).toBe(1);
expect(onChangeCalls[0]).toEqual(['e1']);
});
});