mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-15 12:41:37 +03:00
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
import { expect, test } from "bun:test"
|
|
import { createTestRenderer } from "@opentui/core/testing"
|
|
import { Effect, FileSystem } from "effect"
|
|
import { Global } from "@opencode/util/global"
|
|
import { createEventStream, createFetch, directory, json } from "./fixture/tui-client"
|
|
import { tmpdir } from "./fixture/fixture"
|
|
|
|
// Each case uses its own session so a prompt draft left by one case cannot satisfy another.
|
|
test.each([
|
|
{ id: "ses_terminal_reported", reported: true, offered: true },
|
|
{ id: "ses_terminal_unsupported", reported: false, offered: false },
|
|
{ id: "ses_terminal_unreported", reported: undefined, offered: true },
|
|
])("offers persistent terminals when the server reports $reported", async (input) => {
|
|
await using state = await tmpdir()
|
|
const setup = await createTestRenderer({ width: 120, height: 36, kittyKeyboard: true })
|
|
await setup.renderer.setupTerminal()
|
|
setup.renderer.start()
|
|
const session = {
|
|
id: input.id,
|
|
title: "Terminal support fixture",
|
|
projectID: "project",
|
|
location: { directory },
|
|
cost: 0,
|
|
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
time: { created: 0, updated: 0 },
|
|
}
|
|
const message = { id: "message-0", type: "user", text: "Terminal support message", time: { created: 0 } }
|
|
const requests: string[] = []
|
|
const calls = createFetch((url) => {
|
|
requests.push(url.pathname)
|
|
if (url.pathname === "/api/info")
|
|
return json({
|
|
version: "test",
|
|
pid: 0,
|
|
urls: [],
|
|
paths: { tmp: "/tmp" },
|
|
// Servers that predate capabilities omit the whole object.
|
|
capabilities: input.reported === undefined ? undefined : { persistentPty: input.reported },
|
|
})
|
|
if (url.pathname === "/api/session") return json({ data: [session], cursor: {} })
|
|
if (url.pathname === `/api/session/${session.id}`) return json({ data: session })
|
|
if (url.pathname === `/api/session/${session.id}/message`) return json({ data: [message], cursor: {} })
|
|
if (url.pathname === `/api/session/${session.id}/inbox`) return json({ data: [] })
|
|
if (url.pathname === `/api/session/${session.id}/permission`) return json({ data: [] })
|
|
return undefined
|
|
}, createEventStream())
|
|
const server = Bun.serve({ port: 0, fetch: (request) => calls.fetch(request) })
|
|
const { run } = await import("../src/app")
|
|
const task = Effect.runPromise(
|
|
run({
|
|
app: { name: "test", version: "test", channel: "test" },
|
|
server: { endpoint: { url: server.url.toString() } },
|
|
config: {
|
|
get: async () => ({ animations: false, tabs: { mode: "off" } }),
|
|
update: async () => ({}),
|
|
},
|
|
packages: { prepare: async () => ({ directory: "" }) },
|
|
args: { sessionID: session.id },
|
|
terminalHandoff: async () => ({ renderer: setup.renderer, mode: "dark", complete: () => {} }),
|
|
log: () => {},
|
|
}).pipe(Effect.provide(Global.layerWith({ state: state.path })), Effect.provide(FileSystem.layerNoop({}))),
|
|
)
|
|
try {
|
|
await setup.waitForFrame((frame) => frame.includes("Terminal support message"))
|
|
await setup.waitFor(() => requests.includes("/api/info"))
|
|
await setup.waitForVisualIdle()
|
|
await setup.mockInput.typeText("/terminal")
|
|
if (input.offered) {
|
|
await setup.waitForFrame((frame) => frame.includes("New terminal"))
|
|
return
|
|
}
|
|
await setup.waitForVisualIdle()
|
|
expect(setup.captureCharFrame()).not.toContain("New terminal")
|
|
expect(requests).not.toContain(`/api/experimental/session/${session.id}/terminal`)
|
|
} finally {
|
|
setup.renderer.destroy()
|
|
await task
|
|
await server.stop()
|
|
}
|
|
})
|