Files
nanobot/tui/src/skill-menu.test.ts
T

73 lines
2.5 KiB
TypeScript
Raw Normal View History

2026-08-25 19:15:59 +08:00
import { afterEach, describe, expect, test } from "bun:test"
import { createTestRenderer, type TestRendererSetup } from "@opentui/core/testing"
import { insertSkill, SkillMenu, skillQuery } from "./skill-menu"
import type { SkillCandidate } from "./protocol"
const skills: SkillCandidate[] = [
{ name: "simplify", description: "Simplify code", source: "workspace" },
{ name: "verify", description: "Verify public behavior", source: "builtin" },
]
describe("skill completion", () => {
let setup: TestRendererSetup | undefined
afterEach(() => {
if (setup && !setup.renderer.isDestroyed) setup.renderer.destroy()
setup = undefined
})
test("finds and replaces only the skill reference under the cursor", () => {
const value = "use $ver before release"
const query = skillQuery(value, 8)
expect(query).toEqual({ query: "ver", start: 4, end: 8 })
expect(insertSkill(value, skills[1]!, query!)).toEqual({
value: "use $verify before release",
cursor: 11,
})
})
test("matches backend token boundaries and replaces a whole token", () => {
expect(skillQuery("$", 1)).toEqual({ query: "", start: 0, end: 1 })
expect(skillQuery("run ($SIM", 9)).toEqual({ query: "sim", start: 5, end: 9 })
expect(skillQuery("price$ver", 9)).toBeNull()
expect(skillQuery("文$ver", 5)).toBeNull()
expect(skillQuery("$verify done", 12)).toBeNull()
const midToken = skillQuery("use $verify before release", 8)
expect(midToken).toEqual({ query: "ver", start: 4, end: 11 })
expect(insertSkill("use $verify before release", skills[1]!, midToken!).value)
.toBe("use $verify before release")
})
test("filters, navigates, and chooses available skills", async () => {
setup = await createTestRenderer({ width: 72, height: 16, screenMode: "alternate-screen" })
const menu = new SkillMenu(setup.renderer, {
text: "#FFFFFF",
muted: "#999999",
border: "#555555",
})
setup.renderer.root.add(menu.root)
menu.show(skills, "", 6)
await setup.renderOnce()
expect(setup.captureCharFrame()).toContain(" $simplify")
expect(setup.captureCharFrame()).toContain("$verify")
expect(menu.move(1)).toBe(true)
expect(menu.choose()).toEqual(skills[1]!)
menu.update("simp", 6)
expect(menu.choose()).toEqual(skills[0]!)
menu.show([
{ name: "alpha", description: "Verify workflow", source: "workspace" },
skills[1]!,
], "verify", 6)
expect(menu.choose()).toEqual(skills[1]!)
menu.show([skills[0]!], "verify", 6)
expect(menu.choose()).toBeNull()
})
})