* feat(draw-image): add SVG template render engine * feat(draw-image): add opencode plugin and tool tests * test(draw-image): add vitest unit integration e2e suite * chore(draw-image): wire CI dependabot docs and ADR * docs(handoff): set PR number * docs(handoff): fix PR number placeholder in frontmatter * fix(ci): use tempfile and trailing newline in draw-image tests --------- Co-authored-by: opencode-agent <agent@opencode.local>
58 lines
No EOL
2.2 KiB
TypeScript
58 lines
No EOL
2.2 KiB
TypeScript
import { describe, test, expect } from "vitest"
|
|
import { parseSlots } from "../src/slot-parser"
|
|
|
|
describe("slot-parser — parseSlots", () => {
|
|
test("parses icon slot with all defaults", () => {
|
|
const svg = `<!-- slot: name=icon, x=312, y=200, w=400, h=400, fit=contain, recolor=accent -->`
|
|
const slots = parseSlots(svg)
|
|
expect(slots).toHaveLength(1)
|
|
expect(slots[0].name).toBe("icon")
|
|
expect(slots[0].x).toBe(312)
|
|
expect(slots[0].y).toBe(200)
|
|
expect(slots[0].w).toBe(400)
|
|
expect(slots[0].h).toBe(400)
|
|
expect(slots[0].fit).toBe("contain")
|
|
expect(slots[0].recolor).toBe("accent")
|
|
expect(slots[0].bg).toBe("none")
|
|
expect(slots[0].border).toBe("none")
|
|
expect(slots[0].radius).toBe(0)
|
|
})
|
|
|
|
test("parses badge slot with bg+border+radius", () => {
|
|
const svg = `<!-- slot: name=badge, x=780, y=780, w=180, h=180, fit=contain, recolor=none, bg=surface, border=accent, radius=0.5 -->`
|
|
const slots = parseSlots(svg)
|
|
expect(slots).toHaveLength(1)
|
|
expect(slots[0].name).toBe("badge")
|
|
expect(slots[0].recolor).toBe("none")
|
|
expect(slots[0].bg).toBe("surface")
|
|
expect(slots[0].border).toBe("accent")
|
|
expect(slots[0].radius).toBe(0.5)
|
|
})
|
|
|
|
test("parses multiple slots", () => {
|
|
const svg = `
|
|
<!-- slot: name=icon, x=312, y=180, w=400, h=400, fit=contain, recolor=accent -->
|
|
<!-- slot: name=sub-icon, x=412, y=600, w=200, h=200, fit=contain, recolor=accent -->
|
|
<!-- slot: name=badge, x=780, y=780, w=180, h=180, fit=contain, recolor=none, bg=surface, border=accent, radius=0.5 -->
|
|
`
|
|
const slots = parseSlots(svg)
|
|
expect(slots).toHaveLength(3)
|
|
expect(slots.map((s) => s.name)).toEqual(["icon", "sub-icon", "badge"])
|
|
})
|
|
|
|
test("defaults fit to contain when omitted", () => {
|
|
const svg = `<!-- slot: name=icon, x=0, y=0, w=100, h=100 -->`
|
|
const slots = parseSlots(svg)
|
|
expect(slots[0].fit).toBe("contain")
|
|
expect(slots[0].recolor).toBe("none")
|
|
})
|
|
|
|
test("returns empty for no slots", () => {
|
|
expect(parseSlots("<svg></svg>")).toEqual([])
|
|
})
|
|
|
|
test("skips slot without name", () => {
|
|
const svg = `<!-- slot: x=0, y=0, w=100, h=100 -->`
|
|
expect(parseSlots(svg)).toEqual([])
|
|
})
|
|
}) |