129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { blockRegistry, resolveBlock, validatePageBlocks } from "./registry";
|
|
|
|
const id = "7d9be7bb-185f-43e8-a5c1-43a05acdebec";
|
|
|
|
describe("block registry", () => {
|
|
it("provides validation and migration for every schema", () => {
|
|
for (const definition of Object.values(blockRegistry)) {
|
|
expect(definition.currentVersion).toBe(1);
|
|
expect(definition.migrations[0]).toBeTypeOf("function");
|
|
}
|
|
});
|
|
|
|
it("migrates and validates a legacy block", () => {
|
|
const resolution = resolveBlock({
|
|
id,
|
|
type: "callout",
|
|
schemaVersion: 0,
|
|
sortOrder: 0,
|
|
config: { body: "จังหวะนี้ควรเก็บพลังงานไว้", tone: "tip" },
|
|
});
|
|
|
|
expect(resolution.kind).toBe("ready");
|
|
if (resolution.kind === "ready") {
|
|
expect(resolution.block.schemaVersion).toBe(1);
|
|
expect(resolution.block.responsiveLayout).toMatchObject({
|
|
width: "content",
|
|
});
|
|
}
|
|
});
|
|
|
|
it("keeps unknown and future blocks safe", () => {
|
|
expect(
|
|
resolveBlock({ id, type: "future-widget", schemaVersion: 1, config: {}, sortOrder: 0 }),
|
|
).toMatchObject({ kind: "unsupported", reason: "unknown-type" });
|
|
expect(
|
|
resolveBlock({ id, type: "callout", schemaVersion: 99, config: {}, sortOrder: 0 }),
|
|
).toMatchObject({ kind: "unsupported", reason: "future-version" });
|
|
});
|
|
|
|
it("rejects unsafe or malformed configuration without throwing", () => {
|
|
const resolution = resolveBlock({
|
|
id,
|
|
type: "links",
|
|
schemaVersion: 1,
|
|
sortOrder: 0,
|
|
config: {
|
|
links: [
|
|
{
|
|
id: "2b21ac85-eb39-4f4d-89ce-a26929417981",
|
|
label: "ไม่ปลอดภัย",
|
|
href: "javascript:alert(1)",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
expect(resolution.kind).toBe("invalid");
|
|
});
|
|
|
|
it("enforces chart series and an immutable accessible table fallback", () => {
|
|
const base = {
|
|
id,
|
|
type: "comparison-chart",
|
|
schemaVersion: 1,
|
|
sortOrder: 0,
|
|
config: {
|
|
dataSourceId: "495248af-d20a-4e59-be25-a982398df917",
|
|
categoryField: "name",
|
|
series: [{ field: "damage", label: "ดาเมจ", color: "chart-1" }],
|
|
presentation: "horizontal-bar",
|
|
normalization: "raw",
|
|
sort: "authored",
|
|
showValues: true,
|
|
showLegend: false,
|
|
},
|
|
} as const;
|
|
|
|
const valid = resolveBlock(base);
|
|
expect(valid.kind).toBe("ready");
|
|
if (valid.kind === "ready") {
|
|
expect(valid.block.config.tableFallback).toBe(true);
|
|
}
|
|
|
|
expect(
|
|
resolveBlock({
|
|
...base,
|
|
config: { ...base.config, tableFallback: false },
|
|
}).kind,
|
|
).toBe("invalid");
|
|
expect(
|
|
resolveBlock({
|
|
...base,
|
|
config: {
|
|
...base.config,
|
|
series: Array.from({ length: 7 }, (_, index) => ({
|
|
field: `value_${index}`,
|
|
label: `Series ${index}`,
|
|
color: "chart-1",
|
|
})),
|
|
},
|
|
}).kind,
|
|
).toBe("invalid");
|
|
});
|
|
|
|
it("detects duplicate stable ids while preserving author order", () => {
|
|
const results = validatePageBlocks([
|
|
{
|
|
id,
|
|
type: "separator",
|
|
schemaVersion: 1,
|
|
config: {},
|
|
sortOrder: 2,
|
|
},
|
|
{
|
|
id,
|
|
type: "separator",
|
|
schemaVersion: 1,
|
|
config: {},
|
|
sortOrder: 1,
|
|
},
|
|
]);
|
|
|
|
expect(results[0].kind).toBe("ready");
|
|
expect(results[1].kind).toBe("invalid");
|
|
});
|
|
});
|