Files
ttrpg-tools/src/components/md-deck/config.test.ts
T
hypercross 5fc2bc5262 feat(md-deck): add vertical alignment options to layers
Expand align from l/c/r to a 3x3 grid with vertical prefixes:
tl/tc/tr/bl/bc/br. Vertical position renders via flex
justify-content; compact layers strings and YAML both parse the
new values, and the layer editor dropdown gains corner/edge
options.
2026-09-03 10:17:44 +08:00

132 lines
3.9 KiB
TypeScript

import { layersToConfigs, normalizeDeckConfig } from "./config";
describe("layersToConfigs", () => {
test("parses compact string format (legacy)", () => {
const layers = layersToConfigs("title:1,1-5,1f8 body:1,5-8,8f3");
expect(layers).toHaveLength(2);
expect(layers[0]).toMatchObject({
prop: "title",
visible: true,
x1: 1,
y1: 1,
x2: 5,
y2: 1,
fontSize: 8,
});
expect(layers[1].prop).toBe("body");
});
test("parses structured list with prop layers", () => {
const layers = layersToConfigs([
{ prop: "name", pos: "1,1-5,2", font: 12 },
]);
expect(layers).toHaveLength(1);
expect(layers[0]).toMatchObject({
prop: "name",
template: undefined,
visible: true,
x1: 1,
y1: 1,
x2: 5,
y2: 2,
fontSize: 12,
});
});
test("parses structured list with template layers", () => {
const layers = layersToConfigs([
{ template: "**{{name}}**", pos: "1,3-5,8", align: "l" },
]);
expect(layers).toHaveLength(1);
expect(layers[0]).toMatchObject({
prop: undefined,
template: "**{{name}}**",
visible: true,
x1: 1,
y1: 3,
x2: 5,
y2: 8,
align: "l",
});
});
test("parses combined vertical+horizontal align", () => {
const layers = layersToConfigs([
{ prop: "a", pos: "1,1-2,2", align: "tl" },
{ prop: "b", pos: "1,1-2,2", align: "br" },
{ prop: "c", pos: "1,1-2,2", align: "tc" },
{ prop: "d", pos: "1,1-2,2", align: "bc" },
]);
expect(layers[0].align).toBe("tl");
expect(layers[1].align).toBe("br");
expect(layers[2].align).toBe("tc");
expect(layers[3].align).toBe("bc");
});
test("parses vertical+horizontal align in compact layers string", () => {
const layers = layersToConfigs("title:1,1-4,1tl body:1,2-5,8bc");
expect(layers[0].align).toBe("tl");
expect(layers[1].align).toBe("bc");
});
test("defaults placement when pos is missing or invalid", () => {
const layers = layersToConfigs([{ prop: "x" }, { prop: "y", pos: "bogus" }]);
expect(layers[0]).toMatchObject({ x1: 1, y1: 1, x2: 2, y2: 2 });
expect(layers[1]).toMatchObject({ x1: 1, y1: 1, x2: 2, y2: 2 });
});
test("returns [] for absent/empty input", () => {
expect(layersToConfigs()).toEqual([]);
expect(layersToConfigs("")).toEqual([]);
expect(layersToConfigs([])).toEqual([]);
});
});
describe("normalizeDeckConfig", () => {
test("parses string dimensions", () => {
const cfg = normalizeDeckConfig({ size: "54x86", grid: "5x8" });
expect(cfg.sizeW).toBe(54);
expect(cfg.sizeH).toBe(86);
expect(cfg.gridW).toBe(5);
expect(cfg.gridH).toBe(8);
});
test("parses array dimensions", () => {
const cfg = normalizeDeckConfig({ size: [63, 88] });
expect(cfg.sizeW).toBe(63);
expect(cfg.sizeH).toBe(88);
});
test("coerces numeric strings for bleed/padding", () => {
const cfg = normalizeDeckConfig({ bleed: "2", padding: "3" });
expect(cfg.bleed).toBe(2);
expect(cfg.padding).toBe(3);
});
test("normalizes layers and back_layers", () => {
const cfg = normalizeDeckConfig({
layers: [
{ prop: "name", pos: "1,1-5,1" },
{ template: "{{body}}", pos: "1,2-5,8" },
],
back_layers: "logo:1,1-2,2",
});
expect(cfg.frontLayers).toHaveLength(2);
expect(cfg.frontLayers[1].template).toBe("{{body}}");
expect(cfg.backLayers).toHaveLength(1);
expect(cfg.backLayers[0].prop).toBe("logo");
});
test("missing fields stay undefined", () => {
const cfg = normalizeDeckConfig({});
expect(cfg.sizeW).toBeUndefined();
expect(cfg.sizeH).toBeUndefined();
expect(cfg.gridW).toBeUndefined();
expect(cfg.gridH).toBeUndefined();
expect(cfg.bleed).toBeUndefined();
expect(cfg.padding).toBeUndefined();
expect(cfg.frontLayers).toEqual([]);
expect(cfg.backLayers).toEqual([]);
});
});