test(cli): cover TUI startup outside package (#12417)

* test(cli): cover TUI startup outside package

* fix(cli): use native preload path in TUI test

---------

Co-authored-by: Johnny Eric Amancio <johnnyeric@gmail.com>
This commit is contained in:
Josh Holmer
2026-07-27 15:14:31 +02:00
committed by GitHub
co-authored by Johnny Eric Amancio
parent 1f3383cf3d
commit c12a567f2a
3 changed files with 80 additions and 0 deletions
@@ -1,6 +1,9 @@
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"
import fs from "fs/promises"
import path from "path"
import { fileURLToPath } from "node:url"
import { spawn, type Exit } from "@opencode-ai/core/pty/driver"
import { sanitizedProcessEnv } from "@opencode-ai/core/util/opencode-process"
import { tmpdir } from "../../../fixture/fixture"
import {
embeddedRemoteExitClient,
@@ -41,6 +44,81 @@ describe("kilo tui thread", () => {
expect(calls).toBe(1)
})
test(
"starts the TUI from a directory without OpenTUI dependencies",
async () => {
await using root = await tmpdir()
const state = { text: "", exit: undefined as Exit | undefined }
const ready = Promise.withResolvers<void>()
const stopped = Promise.withResolvers<void>()
const proc = spawn(
process.execPath,
[
"--conditions=browser",
`--preload=${fileURLToPath(import.meta.resolve("@opentui/solid/preload"))}`,
path.resolve(import.meta.dir, "../../../../src/index.ts"),
],
{
name: "xterm-256color",
cols: 120,
rows: 40,
cwd: root.path,
env: sanitizedProcessEnv({
HOME: root.path,
XDG_CONFIG_HOME: path.join(root.path, ".config"),
XDG_DATA_HOME: path.join(root.path, ".local/share"),
XDG_STATE_HOME: path.join(root.path, ".local/state"),
XDG_CACHE_HOME: path.join(root.path, ".cache"),
KILO_TEST_HOME: root.path,
KILO_CONFIG_CONTENT: "{}",
KILO_AUTH_CONTENT: "{}",
KILO_DISABLE_PROJECT_CONFIG: "1",
KILO_DISABLE_AUTOUPDATE: "1",
KILO_DISABLE_MODELS_FETCH: "1",
KILO_DISABLE_TERMINAL_TITLE: "0",
KILO_DEV_CWD: "",
KILO_PURE: "1",
KILO_NO_DAEMON: "1",
TERM: "xterm-256color",
}),
},
)
const data = proc.onData((chunk) => {
state.text = (state.text + chunk).slice(-20_000)
if (state.text.includes("TUI worker error")) {
ready.reject(new Error(`TUI worker failed during startup:\n${state.text}`))
return
}
// The title is emitted only after the worker-backed TUI reaches its rendered app.
if (state.text.includes("Kilo CLI")) ready.resolve()
})
const exit = proc.onExit((event) => {
state.exit = event
stopped.resolve()
ready.reject(
new Error(
`TUI exited before rendering (code ${event.exitCode}, signal ${event.signal ?? "none"}):\n${state.text}`,
),
)
})
const timer = setTimeout(() => {
ready.reject(new Error(`Timed out waiting for the TUI to render:\n${state.text}`))
}, 30_000)
try {
await ready.promise
expect(state.text).toContain("Kilo CLI")
} finally {
clearTimeout(timer)
data.dispose()
if (!state.exit) proc.kill()
await stopped.promise
exit.dispose()
}
},
45_000,
)
test("ignores stale PWD after cwd is changed by a process wrapper", async () => {
await using root = await tmpdir()
const pkg = path.join(root.path, "packages", "opencode")
@@ -14,6 +14,7 @@ describe("test profiles", () => {
expect(result.files.length).toBeGreaterThan(20)
expect(result.files).toContain("pty/pty-shell.test.ts")
expect(result.files).toContain("kilocode/cli/install-artifact.test.ts")
expect(result.files).toContain("kilocode/cli/tui/thread.test.ts")
expect(result.files).toContain("kilocode/sandbox/macos-confinement.test.ts")
expect(result.files).toContain("kilocode/core-watcher.test.ts")
expect(result.files).toContain("kilocode/background-process.test.ts")