[verified] feat: add diagram toolbox capabilities
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import type { DiagramIRV2 } from "../../model/diagram-ir.js";
|
||||
import { applyMetricsHeatmap } from "./heatmap.js";
|
||||
import { contrastRatio } from "../themes/theme-service.js";
|
||||
|
||||
const IR: DiagramIRV2 = {
|
||||
version: 2,
|
||||
pages: [{ id: "p", title: "Page", nodes: [
|
||||
{ id: "low", label: "Low", style: "shape=hexagon;strokeColor=#000000;", geometry: { x: 0, y: 0, width: 100, height: 60 } },
|
||||
{ id: "high", label: "High", style: "shape=ellipse;", geometry: { x: 200, y: 0, width: 100, height: 60 } },
|
||||
], edges: [{ id: "flow", source: "low", target: "high", waypoints: [{ x: 150, y: 30 }] }] }],
|
||||
};
|
||||
|
||||
test("metrics heatmap is deterministic with legend metadata and preserves topology", () => {
|
||||
const request = { metric: "latency_ms", min: 0, max: 100, values: { "p/low": 0, "p/high": 100 } };
|
||||
const snapshot = structuredClone(IR);
|
||||
const first = applyMetricsHeatmap(IR, request);
|
||||
assert.deepEqual(first, applyMetricsHeatmap(IR, request));
|
||||
assert.deepEqual(IR, snapshot);
|
||||
assert.deepEqual(first.legend, {
|
||||
metric: "latency_ms", min: 0, max: 100,
|
||||
stops: [
|
||||
{ value: 0, color: "#440154", fontColor: "#FFFFFF" },
|
||||
{ value: 25, color: "#3B528B", fontColor: "#FFFFFF" },
|
||||
{ value: 50, color: "#21918C", fontColor: "#1A1A1A" },
|
||||
{ value: 75, color: "#5EC962", fontColor: "#1A1A1A" },
|
||||
{ value: 100, color: "#FDE725", fontColor: "#1A1A1A" },
|
||||
],
|
||||
});
|
||||
assert.match(first.diagram.pages[0].nodes[0].style!, /shape=hexagon/);
|
||||
assert.match(first.diagram.pages[0].nodes[0].style!, /fillColor=#440154/);
|
||||
assert.match(first.diagram.pages[0].nodes[1].style!, /fillColor=#FDE725/);
|
||||
assert.deepEqual(first.diagram.pages[0].edges, IR.pages[0].edges);
|
||||
assert.deepEqual(first.diagram.pages[0].nodes.map(({ id, geometry }) => ({ id, geometry })), IR.pages[0].nodes.map(({ id, geometry }) => ({ id, geometry })));
|
||||
});
|
||||
|
||||
test("metrics heatmap sets readable text for every palette stop", () => {
|
||||
const result = applyMetricsHeatmap(IR, {
|
||||
metric: "latency_ms", min: 0, max: 100,
|
||||
values: { "p/low": 0, "p/high": 100 },
|
||||
});
|
||||
|
||||
for (const stop of result.legend.stops) {
|
||||
assert.ok(contrastRatio(stop.fontColor, stop.color) >= 4.5, `${stop.fontColor} on ${stop.color}`);
|
||||
}
|
||||
assert.match(result.diagram.pages[0].nodes[0].style!, /fontColor=#FFFFFF/);
|
||||
assert.match(result.diagram.pages[0].nodes[1].style!, /fontColor=#1A1A1A/);
|
||||
});
|
||||
|
||||
test("metrics heatmap switches colors at the legend stop boundaries", () => {
|
||||
const colorsAt = (low: number, high: number): string[] => applyMetricsHeatmap(IR, {
|
||||
metric: "latency_ms", min: 0, max: 100, values: { "p/low": low, "p/high": high },
|
||||
}).diagram.pages[0].nodes.map((node) => /fillColor=(#[0-9A-F]{6})/i.exec(node.style!)?.[1] ?? "");
|
||||
|
||||
assert.deepEqual(colorsAt(24.999, 25), ["#440154", "#3B528B"]);
|
||||
assert.deepEqual(colorsAt(49.999, 50), ["#3B528B", "#21918C"]);
|
||||
assert.deepEqual(colorsAt(74.999, 75), ["#21918C", "#5EC962"]);
|
||||
assert.deepEqual(colorsAt(99.999, 100), ["#5EC962", "#FDE725"]);
|
||||
});
|
||||
|
||||
test("metrics heatmap rejects palettes without a readable text color", () => {
|
||||
assert.throws(() => applyMetricsHeatmap(IR, {
|
||||
metric: "x", min: 0, max: 1, values: {}, colors: ["#777777", "#777777"],
|
||||
}), /no readable font color/i);
|
||||
});
|
||||
|
||||
test("metrics heatmap rejects invalid bounds, colors, keys, and out-of-range values", () => {
|
||||
assert.throws(() => applyMetricsHeatmap(IR, { metric: "x", min: 1, max: 1, values: {} }), /min.*max/i);
|
||||
assert.throws(() => applyMetricsHeatmap(IR, { metric: "x", min: 0, max: 1, values: { "p/low": 2 } }), /bounded/i);
|
||||
assert.throws(() => applyMetricsHeatmap(IR, { metric: "x", min: 0, max: 1, values: { missing: 0 } }), /unknown/i);
|
||||
assert.throws(() => applyMetricsHeatmap(IR, { metric: "x", min: 0, max: 1, values: {}, colors: ["red"] }), /color/i);
|
||||
});
|
||||
Reference in New Issue
Block a user