feat: introduce local-first SVG workbench
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
accessibilityFixPatch,
|
||||
auditAccessibility,
|
||||
} from "../../src/accessibility/audit";
|
||||
import { parseSvgSource } from "../../src/document/source-parser";
|
||||
import { applySourcePatches } from "../../src/document/source-patcher";
|
||||
import {
|
||||
buildReferenceIndex,
|
||||
previewIdRename,
|
||||
} from "../../src/structure/reference-index";
|
||||
|
||||
function semantic(source: string) {
|
||||
return parseSvgSource(source, 1).semantic!;
|
||||
}
|
||||
|
||||
describe("references and accessibility", () => {
|
||||
it("indexes resolved, missing and cyclic local references", () => {
|
||||
const document = semantic(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="paint" href="#paint"/></defs><rect id="shape" fill="url(#paint)" aria-labelledby="missing"/></svg>`,
|
||||
);
|
||||
const index = buildReferenceIndex(document);
|
||||
expect(index.edges).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ targetId: "paint", status: "cyclic" }),
|
||||
expect.objectContaining({ targetId: "missing", status: "missing" }),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("marks cycle members without mislabelling an upstream reference", () => {
|
||||
const document = semantic(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="upstream" href="#left"/><linearGradient id="left" href="#right"/><linearGradient id="right" href="#left"/></defs></svg>',
|
||||
);
|
||||
const edges = buildReferenceIndex(document).edges;
|
||||
|
||||
expect(
|
||||
edges.find(
|
||||
(edge) =>
|
||||
edge.sourceKey === "id:upstream" &&
|
||||
edge.targetId === "left" &&
|
||||
edge.status === "resolved",
|
||||
),
|
||||
).toBeDefined();
|
||||
expect(
|
||||
edges
|
||||
.filter((edge) => edge.status === "cyclic")
|
||||
.map((edge) => edge.targetId),
|
||||
).toEqual(expect.arrayContaining(["left", "right"]));
|
||||
});
|
||||
|
||||
it("renames an ID and its typed references without unsafe global replacement", () => {
|
||||
const source =
|
||||
'<svg xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="old"/><linearGradient id="oldish"/></defs><rect fill="url( #old )" stroke="url(#oldish)" aria-describedby="old oldish old"/></svg>';
|
||||
const document = semantic(source);
|
||||
const target = [...document.nodes.values()].find(
|
||||
(node) => node.id === "old",
|
||||
)!;
|
||||
const preview = previewIdRename(document, target.key, "newPaint");
|
||||
const result = applySourcePatches(source, preview.patches);
|
||||
expect(result).toContain('id="newPaint"');
|
||||
expect(result).toContain("url( #newPaint )");
|
||||
expect(result).toContain("url(#oldish)");
|
||||
expect(result).toContain('aria-describedby="newPaint oldish newPaint"');
|
||||
});
|
||||
|
||||
it("reports missing root naming and provides an exact title patch", () => {
|
||||
const source =
|
||||
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="4" height="4"/></svg>';
|
||||
const document = semantic(source);
|
||||
const findings = auditAccessibility(document);
|
||||
expect(findings).toContainEqual(
|
||||
expect.objectContaining({
|
||||
rule: "svg-accessible-name",
|
||||
automaticFix: "add-title",
|
||||
}),
|
||||
);
|
||||
const fixed = applySourcePatches(source, [
|
||||
accessibilityFixPatch(document, "add-title", "Small square"),
|
||||
]);
|
||||
expect(fixed).toContain("<title>Small square</title>");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user