opencode-config/tests/test_draw_image_tool.ts
Sergey 56b67d2d5c
feat(draw-image): SVG template renderer for on-brand covers (#134)
* 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>
2026-07-29 23:42:50 +03:00

70 lines
No EOL
3 KiB
TypeScript

/**
* Tests for .opencode/tools/draw-image.ts — the draw-image custom tool.
*
* Mirror of tests/test_commit_tool.ts: the tool is a spawnSync wrapper
* around `node cli.ts render ...`. Runtime note: opencode ships a standalone
* binary with Bun bundled inside; there is no separate `bun` CLI on the host
* (CI runner uses node + pytest). The CI runs the equivalent Python tests in
* tests/test_draw_image_tool.py via the JS loader tests/_ts_loader.mjs
* (exec_stub_json mode for multi-arg tools). This file documents the intended
* TS-side test cases and is runnable under `bun test` once a bun runtime is
* available on the host.
*
* Test cases (mirror tests/test_draw_image_tool.py):
* - test_loader_can_load_tool — tool loads, declares args
* - test_valid_render — valid args + spawnSync exit 0 → JSON result
* - test_render_failure — spawnSync exit 1 → error string
* - test_execute_uses_cwd_from_context — cwd=context.worktree propagated
*/
import { describe, test, expect, mock } from "bun:test" with { type: "'bun-test'" }
import { spawnSync } from "child_process"
import path from "path"
const TOOL_SRC = path.resolve(import.meta.dir, "..", ".opencode", "tools", "draw-image.ts")
function ctx() {
return {
sessionID: "t", messageID: "t", agent: "t",
directory: ".", worktree: ".",
abort: new AbortController().signal,
metadata() {}, async ask() {},
}
}
describe("draw-image tool", () => {
test("test_valid_render — valid args + spawnSync exit 0 returns JSON", async () => {
const okResponse = '{"path":"/tmp/out.png","hash":"abc123","status":"rendered"}'
mock.module("child_process", () => ({
spawnSync: () => ({ status: 0, stdout: okResponse, stderr: "" }),
}))
const mod = await import(TOOL_SRC + "?t=" + Date.now())
const result = await mod.default.execute({ template: "cover", title: "Test" }, ctx())
expect(result).toContain("rendered")
expect(result).toContain("/tmp/out.png")
})
test("test_render_failure — spawnSync exit 1 returns error", async () => {
mock.module("child_process", () => ({
spawnSync: () => ({ status: 1, stdout: "", stderr: "render failed" }),
}))
const mod = await import(TOOL_SRC + "?t=" + Date.now())
const result = await mod.default.execute({ template: "cover", title: "Test" }, ctx())
expect(result).toContain("draw-image failed")
})
test("test_execute_uses_cwd_from_context — cwd propagated to spawnSync", async () => {
const okResponse = '{"path":"./out.png","hash":"abc","status":"rendered"}'
let capturedOpts: any = null
mock.module("child_process", () => ({
spawnSync: (_cmd: string, _args: string[], opts: any) => {
capturedOpts = opts
return { status: 0, stdout: okResponse, stderr: "" }
},
}))
const mod = await import(TOOL_SRC + "?t=" + Date.now())
await mod.default.execute({ template: "cover", title: "Test" }, ctx())
expect(capturedOpts).not.toBeNull()
expect(capturedOpts.cwd).toBe(".")
})
})