opencode/packages/simulation/test/protocol.test.ts

123 lines
3.7 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { Effect } from "effect"
import { Backend, Frontend, Handshake } from "../src/protocol"
test("decodes ui.matches text params", () => {
expect(
Frontend.decodeRequest({
jsonrpc: "2.0",
id: 1,
method: "ui.matches",
params: { text: "OpenCode [ready].*" },
}),
).toMatchObject({ method: "ui.matches", params: { text: "OpenCode [ready].*" } })
expect(() =>
Frontend.decodeRequest({
jsonrpc: "2.0",
id: 1,
method: "ui.matches",
params: { pattern: "OpenCode.*" },
}),
).toThrow()
})
const params: Handshake.Params = {
client: { name: "opencode-drive", version: "test" },
expectedRole: "ui",
offeredVersions: [1],
requiredCapabilities: ["ui.state"],
optionalCapabilities: ["ui.capture", "future.capability"],
}
const ui: Handshake.DispatchAction = {
role: "ui",
server: { name: "opencode", version: "test" },
capabilities: Frontend.Capabilities,
}
describe("simulation.handshake", () => {
test("decodes through both endpoint request protocols", () => {
const request = {
jsonrpc: "2.0" as const,
id: 1,
method: "simulation.handshake" as const,
params,
}
expect(Frontend.decodeRequest(request)).toEqual(request)
expect(Backend.decodeRequest({ ...request, params: { ...params, expectedRole: "backend" } })).toMatchObject({
method: "simulation.handshake",
params: { expectedRole: "backend" },
})
})
test("rejects invalid version and capability declarations", () => {
const request = {
jsonrpc: "2.0" as const,
id: 1,
method: "simulation.handshake" as const,
params,
}
expect(() =>
Frontend.decodeRequest({
...request,
params: { ...params, offeredVersions: [] },
}),
).toThrow()
expect(() =>
Frontend.decodeRequest({
...request,
params: { ...params, requiredCapabilities: ["ui.state", "ui.state"] },
}),
).toThrow()
expect(() =>
Frontend.decodeRequest({
...request,
params: { ...params, optionalCapabilities: [""] },
}),
).toThrow()
})
test("selects the protocol and advertises only installed capabilities", async () => {
await expect(Effect.runPromise(Handshake.dispatch(ui, params))).resolves.toEqual({
protocolVersion: 1,
role: "ui",
server: { name: "opencode", version: "test" },
capabilities: [...Frontend.Capabilities],
})
})
test("rejects a role mismatch", async () => {
await expect(
Effect.runPromise(Handshake.dispatch(ui, { ...params, expectedRole: "backend" })),
).rejects.toMatchObject({ _tag: "SimulationHandshake.RoleMismatchError", expected: "backend", actual: "ui" })
})
test("rejects unsupported protocol versions", async () => {
await expect(Effect.runPromise(Handshake.dispatch(ui, { ...params, offeredVersions: [2] }))).rejects.toMatchObject({
_tag: "SimulationHandshake.UnsupportedProtocolError",
offered: [2],
supported: [1],
})
})
test("rejects a missing required capability but ignores missing optional capabilities", async () => {
await expect(
Effect.runPromise(
Handshake.dispatch(ui, {
...params,
requiredCapabilities: ["ui.state", "ui.future"],
}),
),
).rejects.toMatchObject({ _tag: "SimulationHandshake.MissingCapabilityError", missing: ["ui.future"] })
await expect(
Effect.runPromise(
Handshake.dispatch(ui, {
...params,
requiredCapabilities: [],
optionalCapabilities: ["ui.future"],
}),
),
).resolves.toMatchObject({ capabilities: Frontend.Capabilities })
})
})