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

102 lines
3.9 KiB
TypeScript
Raw Normal View History

/**
* Task D4 MTEXT-Tool: Mehrzeiliger Text mit/ohne Rahmen.
*
* Klick platziert mehrzeiligen Text (Inhalt aus Options, Zeilen-
* umbrueche), fontSize-Option, optionale Rahmen-Option erzeugt ein
* rect-Element in derselben Transaktion (1 Undo-Schritt).
*/
import { describe, it, expect } from 'vitest';
import { mtextTool } from '../src/plugins/builtin/core-annotate';
import { CADDocument } from '../src/kernel/document/CADDocument';
import { createInMemoryDoc } from './helpers/inMemoryDoc';
import type { CADElement, Pt } from '../src/types/cad.types';
function mkCtx(options: Record<string, unknown> = {}) {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
const statuses: string[] = [];
const ctx: any = {
doc,
options,
setStatus: (m: string) => statuses.push(m),
setPreview: (_el: CADElement | null) => {},
};
return { ctx, doc, statuses };
}
function pe(x: number, y: number): { world: Pt } {
return { world: { x, y } } as never;
}
describe('D4: mtextTool', () => {
it('platziert mehrzeiligen Text mit Zeilenumbruechen aus den Options', () => {
const { ctx, doc } = mkCtx({ text: 'Zeile 1\nZeile 2\nZeile 3', fontSize: 14 });
mtextTool.handlers.down!(pe(100, 50), ctx);
const els = doc.getAllElements();
expect(els).toHaveLength(1);
const el = els[0];
expect(el.type).toBe('text');
expect(el.x).toBe(100);
expect(el.y).toBe(50);
expect(el.properties.text).toBe('Zeile 1\nZeile 2\nZeile 3');
expect(el.properties.fontSize).toBe(14);
expect(el.properties.mtext).toBe(true);
});
it('Rahmen-Option erzeugt zusaetzliches rect in derselben Transaktion (1 Undo)', () => {
const { ctx, doc } = mkCtx({ text: 'Mit Rahmen', frame: true });
mtextTool.handlers.down!(pe(0, 0), ctx);
const els = doc.getAllElements();
expect(els).toHaveLength(2);
const texts = els.filter((e) => e.type === 'text');
const rects = els.filter((e) => e.type === 'rect');
expect(texts).toHaveLength(1);
expect(rects).toHaveLength(1);
expect(rects[0].x).toBeCloseTo(0, 5);
expect(rects[0].y).toBeCloseTo(0, 5);
doc.undo();
expect(doc.getAllElements()).toHaveLength(0);
});
it('ohne frame-Option: nur Text, kein rect', () => {
const { ctx, doc } = mkCtx({ text: 'Ohne Rahmen' });
mtextTool.handlers.down!(pe(0, 0), ctx);
expect(doc.getAllElements().filter((e) => e.type === 'rect')).toHaveLength(0);
});
it('Standard-Text wenn Options leer: MTEXT-Platzhalter leer (Editor bearbeitet spaeter)', () => {
const { ctx, doc } = mkCtx({});
mtextTool.handlers.down!(pe(10, 10), ctx);
const el = doc.getAllElements()[0];
expect(el.properties.text).toBe('');
expect(el.properties.fontSize).toBe(12); // Default
});
it('OptionsSchema: text/number/checkbox-Felder', () => {
const schema = mtextTool.optionsSchema ?? [];
const keys = schema.map((f) => f.key);
expect(keys).toContain('text');
expect(keys).toContain('fontSize');
expect(keys).toContain('frame');
const textField = schema.find((f) => f.key === 'text');
expect(textField!.type).toBe('text');
const frameField = schema.find((f) => f.key === 'frame');
expect(frameField!.type).toBe('checkbox');
});
it('Rahmenhoehe waechst mit Zeilenzahl', () => {
const { ctx: ctx1, doc: doc1 } = mkCtx({ text: 'eine Zeile', frame: true });
mtextTool.handlers.down!(pe(0, 0), ctx1);
const { ctx: ctx3, doc: doc3 } = mkCtx({ text: 'eins\nzwei\ndrei', frame: true });
mtextTool.handlers.down!(pe(0, 0), ctx3);
const rect1 = doc1.getAllElements().find((e) => e.type === 'rect')!;
const rect3 = doc3.getAllElements().find((e) => e.type === 'rect')!;
expect(rect3.height).toBeGreaterThan(rect1.height);
});
it('Manifest: id=mtext, tags basic', () => {
expect(mtextTool.manifest.id).toBe('mtext');
expect((mtextTool.manifest.tags ?? [])).toContain('basic');
});
});