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

148 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Task D3 Point/XLine/Ray: Konstruktions-Elemente.
*
* pointTool: Klick-Platzierer (kleiner Kreis mit point:true-Marker,
* r=1.5 wie DXF-POINT-Import). xlineTool: 2 Klicks (Basis+Richtung),
* sehr lange Linie in BEIDE Richtungen. rayTool: halblang (nur eine
* Richtung). Alle mit construction:true und auf defpoints-Layer
* (auto-angelegt falls fehlt).
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { pointTool, xlineTool, rayTool } from '../src/plugins/builtin/core-drawing';
import { CADDocument } from '../src/kernel/document/CADDocument';
import { createInMemoryDoc } from './helpers/inMemoryDoc';
import type { CADElement, Pt } from '../src/types/cad.types';
function mkCtx() {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
const previews: (CADElement | null)[] = [];
const statuses: string[] = [];
const ctx: any = {
doc,
options: {},
setStatus: (m: string) => statuses.push(m),
setPreview: (el: CADElement | null) => previews.push(el),
};
return { ctx, doc, previews, statuses };
}
function pe(x: number, y: number): { world: Pt } {
return { world: { x, y } } as never;
}
beforeEach(() => {
pointTool.handlers.cancel?.({ setStatus: () => {}, setPreview: () => {} } as never);
xlineTool.handlers.cancel?.({ setStatus: () => {}, setPreview: () => {} } as never);
rayTool.handlers.cancel?.({ setStatus: () => {}, setPreview: () => {} } as never);
});
describe('D3: pointTool', () => {
it('Klick platziert Kreis mit point-Marker (r=1.5, wie DXF POINT)', () => {
const { ctx, doc } = mkCtx();
pointTool.handlers.down!(pe(55, 66), ctx);
const els = doc.getAllElements();
expect(els).toHaveLength(1);
const el = els[0];
expect(el.type).toBe('circle');
expect(el.x).toBe(55);
expect(el.y).toBe(66);
expect(el.properties.radius).toBe(1.5);
expect(el.properties.point).toBe(true);
});
it('defpoints-Layer wird automatisch angelegt falls fehlt', () => {
const { ctx, doc } = mkCtx();
expect(doc.getLayer('defpoints')).toBeUndefined();
pointTool.handlers.down!(pe(0, 0), ctx);
expect(doc.getLayer('defpoints')).toBeDefined();
expect(doc.getLayer('defpoints')!.name).toBe('defpoints');
});
it('Element landet auf defpoints-Layer mit construction:true', () => {
const { ctx, doc } = mkCtx();
pointTool.handlers.down!(pe(10, 10), ctx);
const el = doc.getAllElements()[0];
expect(el.layerId).toBe('defpoints');
expect(el.properties.construction).toBe(true);
});
});
describe('D3: xlineTool (Konstruktionslinie, beide Richtungen)', () => {
it('2 Klicks erzeugen sehr lange Linie durch beide Punkte in BEIDE Richtungen', () => {
const { ctx, doc } = mkCtx();
xlineTool.handlers.down!(pe(0, 0), ctx);
xlineTool.handlers.down!(pe(10, 10), ctx);
const els = doc.getAllElements();
expect(els).toHaveLength(1);
const el = els[0];
expect(el.type).toBe('line');
const dx = (el.properties.x2 as number) - (el.properties.x1 as number);
const dy = (el.properties.y2 as number) - (el.properties.y1 as number);
// Sehr lange: Länge >> Distanz der beiden Klicks (14.14)
expect(Math.hypot(dx, dy)).toBeGreaterThan(100000);
// Mittelpunkt der Linie = Basispunkt
expect((el.properties.x1 as number) + dx / 2).toBeCloseTo(0, 3);
expect((el.properties.y1 as number) + dy / 2).toBeCloseTo(0, 3);
});
it('Element auf defpoints-Layer mit construction:true', () => {
const { ctx, doc } = mkCtx();
xlineTool.handlers.down!(pe(0, 0), ctx);
xlineTool.handlers.down!(pe(5, 0), ctx);
const el = doc.getAllElements()[0];
expect(el.layerId).toBe('defpoints');
expect(el.properties.construction).toBe(true);
});
it('Preview bei move nach erstem Klick', () => {
const { ctx, previews } = mkCtx();
xlineTool.handlers.down!(pe(0, 0), ctx);
xlineTool.handlers.move!(pe(50, 50), ctx);
expect(previews.length).toBeGreaterThanOrEqual(1);
});
it('Erster Klick ohne zweiten erzeugt NICHTS (Session-State)', () => {
const { ctx, doc } = mkCtx();
xlineTool.handlers.down!(pe(0, 0), ctx);
expect(doc.getAllElements()).toHaveLength(0);
});
});
describe('D3: rayTool (Strahl, nur EINE Richtung)', () => {
it('2 Klicks erzeugen Linie ab Basispunkt NUR in Zugrichtung', () => {
const { ctx, doc } = mkCtx();
rayTool.handlers.down!(pe(0, 0), ctx);
rayTool.handlers.down!(pe(10, 0), ctx);
const el = doc.getAllElements()[0];
expect(el.type).toBe('line');
expect(el.properties.x1).toBe(0);
expect(el.properties.y1).toBe(0);
// Endpunkt weit in +x-Richtung
expect((el.properties.x2 as number)).toBeGreaterThanOrEqual(100000);
// NICHT in Gegenrichtung: x1 ist exakt der Basispunkt
expect(el.properties.x1).toBe(0);
});
it('construction:true + defpoints-Layer', () => {
const { ctx, doc } = mkCtx();
rayTool.handlers.down!(pe(0, 0), ctx);
rayTool.handlers.down!(pe(0, 10), ctx);
const el = doc.getAllElements()[0];
expect(el.layerId).toBe('defpoints');
expect(el.properties.construction).toBe(true);
});
});
describe('D3: Manifeste', () => {
it('ids/ribbonTab/tags korrekt', () => {
expect(pointTool.manifest.id).toBe('point');
expect(xlineTool.manifest.id).toBe('xline');
expect(rayTool.manifest.id).toBe('ray');
for (const t of [pointTool, xlineTool, rayTool]) {
expect(t.manifest.ribbonTab).toBe('canvas');
expect((t.manifest.tags ?? [])).toContain('basic');
}
});
});