Files
edentext/tests/unit/shapes.test.ts
T
Steffen Becker 4cda289272 feat: a shape can be a triangle, a star or a block arrow
Twelve presets beside the three rectangular ones. Each outline is one
polygon in utils/shapes.ts, given once: the node view draws it as an SVG
path, the ODF export scales the same points into draw:enhanced-path, and
Word gets the preset's name and draws its own geometry.

A gallery in the box toolbar and the ribbon renders its tiles from that
same table, so a new shape needs no icon. Verified through LibreOffice
from both formats; a preset we can't draw still imports as a warning.
2026-08-14 08:02:08 +02:00

66 lines
2.7 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
SHAPES, POLYGON_KINDS, shapePath, odfEnhancedGeometry, shapeFromOdfType, shapeFromPrst,
type ShapeKind,
} from '../../src/lib/utils/shapes';
describe('shape presets', () => {
it('names every kind once per format', () => {
const kinds = Object.keys(SHAPES) as ShapeKind[];
expect(new Set(kinds.map((k) => SHAPES[k].odf)).size).toBe(kinds.length);
expect(new Set(kinds.map((k) => SHAPES[k].prst)).size).toBe(kinds.length);
});
it('round-trips a kind through both formats', () => {
for (const k of Object.keys(SHAPES) as ShapeKind[]) {
expect(shapeFromOdfType(SHAPES[k].odf)).toBe(k);
expect(shapeFromPrst(SHAPES[k].prst)).toBe(k);
}
// A preset we can't draw stays unknown rather than flattening to a rectangle.
expect(shapeFromOdfType('bent-connector')).toBeNull();
expect(shapeFromPrst('bentConnector3')).toBeNull();
expect(shapeFromOdfType('circle')).toBe('ellipse');
});
it('keeps every polygon inside its box', () => {
for (const k of POLYGON_KINDS) {
const pts = SHAPES[k].points!;
expect(pts.length).toBeGreaterThanOrEqual(3);
for (const [x, y] of pts) {
expect(x).toBeGreaterThanOrEqual(0);
expect(x).toBeLessThanOrEqual(100);
expect(y).toBeGreaterThanOrEqual(0);
expect(y).toBeLessThanOrEqual(100);
}
// The outline has to touch all four edges, or the shape doesn't fill its frame.
expect(Math.min(...pts.map((p) => p[0]))).toBeCloseTo(0, 1);
expect(Math.max(...pts.map((p) => p[0]))).toBeCloseTo(100, 1);
expect(Math.min(...pts.map((p) => p[1]))).toBeCloseTo(0, 1);
expect(Math.max(...pts.map((p) => p[1]))).toBeCloseTo(100, 1);
}
});
it('keeps every text area inside its outline box', () => {
for (const k of POLYGON_KINDS) {
const [x0, y0, x1, y1] = SHAPES[k].textArea!;
expect(x0).toBeLessThan(x1);
expect(y0).toBeLessThan(y1);
expect(x0).toBeGreaterThanOrEqual(0);
expect(y1).toBeLessThanOrEqual(100);
}
});
it('derives the ODF geometry from the same points', () => {
expect(shapePath('diamond')).toBe('M 50,0 L 100,50 L 50,100 L 0,50 Z');
expect(odfEnhancedGeometry('diamond')).toBe(
'<draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="diamond"' +
' draw:text-areas="5400 5400 16200 16200"' +
' draw:enhanced-path="M 10800 0 L 21600 10800 10800 21600 0 10800 Z N"/>',
);
// The two rectangular kinds keep LibreOffice's own geometry, curves and all.
expect(odfEnhancedGeometry('ellipse')).toContain('U 10800 10800 10800 10800 0 360 Z N');
expect(odfEnhancedGeometry('textbox')).toBeNull();
expect(shapePath('textbox')).toBeNull();
});
});