floor-planner/tests/cut-preview.test.ts
2026-09-11 16:09:28 +01:00

124 lines
4.2 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.

import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { describe, expect, it } from 'vitest';
import { FlooringPreview, SkirtingPreview } from '../src/components/CutPreview';
import { exactMm, flooringTemplate, skirtingEndBoxes } from '../src/lib/cut-preview';
import type { FlooringPiece, Point, SkirtingPiece } from '../src/lib/types';
const floor: FlooringPiece = {
id: 'F1',
roomId: 'room-1',
row: 1,
column: 1,
polygon: [],
length: 600.001,
width: 190,
stockId: 'B1',
reused: false,
cut: true,
shaped: false,
template: [],
};
const template: Point[] = [
{ x: 18, y: 0 },
{ x: 1182, y: 0 },
{ x: 1200, y: 18 },
{ x: 0, y: 18 },
];
const skirt: SkirtingPiece = {
id: 'A1',
roomId: 'room-1',
wallId: 'w1',
wallIndex: 0,
start: { x: 0, y: 0 },
end: { x: 1164, y: 0 },
length: 1200,
backLength: 1164,
leftMitre: 45,
rightMitre: 45,
leftType: 'external',
rightType: 'external',
stockId: 'S1',
template,
};
describe('cut shape previews', () => {
it('draws rectangular floor cuts too, keeping their precise measured dimensions', () => {
const points = flooringTemplate(floor);
expect(points).toEqual([
{ x: 0, y: 0 },
{ x: 600.001, y: 0 },
{ x: 600.001, y: 190 },
{ x: 0, y: 190 },
]);
const markup = renderToStaticMarkup(createElement(FlooringPreview, { piece: floor }));
expect(markup).toContain('aria-label="Flooring shape F1"');
expect(markup).toContain('preserveAspectRatio="xMidYMid meet"');
expect(markup).toContain('Length 600.001 mm × width 190 mm');
expect(exactMm(600.001)).toBe('600.001');
});
it('keeps skirting endpoints in original coordinates and gives both ends equal square windows', () => {
const original = structuredClone(template);
const boxes = skirtingEndBoxes(template, 18);
expect(boxes.left.width).toBe(boxes.left.height);
expect(boxes.right.width).toBe(boxes.right.height);
expect(boxes.left.width).toBe(boxes.right.width);
// Equal x/y scales preserve the measured 18-by-18 mm, 45-degree cut.
const scaleX = 120 / boxes.left.width,
scaleY = 120 / boxes.left.height;
const angle =
(Math.atan2(
Math.abs(template[3].y - template[0].y) * scaleY,
Math.abs(template[3].x - template[0].x) * scaleX,
) *
180) /
Math.PI;
expect(angle).toBeCloseTo(45, 8);
expect(template).toEqual(original);
const markup = renderToStaticMarkup(
createElement(SkirtingPreview, { piece: skirt, thickness: 18 }),
);
expect(markup).toContain('points="18,0 1182,0 1200,18 0,18"');
expect(markup.match(/preserveAspectRatio="xMidYMid meet"/g)).toHaveLength(3);
expect(markup).toContain('Full length 1,200 mm × thickness 18 mm');
expect(markup).not.toContain('exaggerat');
});
it('keeps the complete end cut visible even at shallow mitre angles', () => {
const shallow = [
{ x: 0, y: 0 },
{ x: 2000, y: 0 },
{ x: 2100, y: 18 },
{ x: 1000, y: 18 },
];
const boxes = skirtingEndBoxes(shallow, 18);
for (const [name, indices] of [
['left', [0, 3]],
['right', [1, 2]],
] as const) {
const box = boxes[name];
for (const index of indices) {
expect(shallow[index].x).toBeGreaterThan(box.x);
expect(shallow[index].x).toBeLessThan(box.x + box.width);
expect(shallow[index].y).toBeGreaterThan(box.y);
expect(shallow[index].y).toBeLessThan(box.y + box.height);
}
}
});
it('makes thumbnails decorative while retaining true-scale SVGs and visible end breaks', () => {
const floorMarkup = renderToStaticMarkup(
createElement(FlooringPreview, { piece: floor, compact: true }),
);
const skirtMarkup = renderToStaticMarkup(
createElement(SkirtingPreview, { piece: skirt, thickness: 18, compact: true }),
);
expect(floorMarkup).toContain('aria-hidden="true"');
expect(skirtMarkup.match(/aria-hidden="true"/g)).toHaveLength(3);
expect(skirtMarkup).toContain('>//</span>');
expect(skirtMarkup.match(/preserveAspectRatio="xMidYMid meet"/g)).toHaveLength(2);
expect(floorMarkup).not.toContain('<figure');
expect(skirtMarkup).not.toContain('<figure');
});
});