Download packages/tui/test/app-lifecycle.test.tsx from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 6.04 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/tui/test/app-lifecycle.test.tsx
- Command line
-
hf download hf://SaylorTwift/opencode/packages/tui/test/app-lifecycle.test.tsx
-
curl -L -o app-lifecycle.test.tsx https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/tui/test/app-lifecycle.test.tsx
6.04 kB
| import { expect, mock, test } from "bun:test" | |
| import type { TuiPluginApi } from "@opencode-ai/plugin/tui" | |
| import { createTestRenderer } from "@opentui/core/testing" | |
| import { Effect } from "effect" | |
| import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" | |
| import { Global } from "@opencode-ai/core/global" | |
| import { createTuiResolvedConfig } from "./fixture/tui-runtime" | |
| import { createEventSource, createFetch, directory, json } from "./fixture/tui-sdk" | |
| test("SIGHUP clears title and disposes scoped resources once", async () => { | |
| const setup = await createTestRenderer({ width: 80, height: 24, useThread: false }) | |
| const core = await import("@opentui/core") | |
| mock.module("@opentui/core", () => ({ ...core, createCliRenderer: async () => setup.renderer })) | |
| const titles: string[] = [] | |
| const setTitle = setup.renderer.setTerminalTitle.bind(setup.renderer) | |
| setup.renderer.setTerminalTitle = (title) => { | |
| titles.push(title) | |
| setTitle(title) | |
| } | |
| const listeners = new Set(process.listeners("SIGHUP")) | |
| const events = createEventSource() | |
| const calls = createFetch() | |
| let started!: () => void | |
| const ready = new Promise<void>((resolve) => { | |
| started = resolve | |
| }) | |
| let disposes = 0 | |
| try { | |
| const { run } = await import("../src/app") | |
| const task = Effect.runPromise( | |
| run({ | |
| url: "http://test", | |
| directory, | |
| config: createTuiResolvedConfig({ plugin_enabled: {} }), | |
| fetch: calls.fetch, | |
| events: events.source, | |
| args: {}, | |
| pluginHost: { | |
| async start() { | |
| started() | |
| }, | |
| async dispose() { | |
| disposes++ | |
| }, | |
| }, | |
| }).pipe(Effect.provide(AppNodeBuilder.build(Global.node))), | |
| ) | |
| await ready | |
| process.emit("SIGHUP") | |
| await task | |
| expect(setup.renderer.isDestroyed).toBe(true) | |
| expect(titles.at(-1)).toBe("") | |
| expect(disposes).toBe(1) | |
| expect(process.listeners("SIGHUP").every((listener) => listeners.has(listener))).toBe(true) | |
| } finally { | |
| if (!setup.renderer.isDestroyed) setup.renderer.destroy() | |
| mock.restore() | |
| } | |
| }) | |
| test("app.exit prints the session epilogue after scoped cleanup", async () => { | |
| const setup = await createTestRenderer({ width: 80, height: 24, useThread: false }) | |
| const core = await import("@opentui/core") | |
| mock.module("@opentui/core", () => ({ ...core, createCliRenderer: async () => setup.renderer })) | |
| const events = createEventSource() | |
| const calls = createFetch((url) => { | |
| if (url.pathname === "/session") | |
| return json([ | |
| { | |
| id: "dummy", | |
| title: "Demo session", | |
| slug: "dummy", | |
| projectID: "project", | |
| directory, | |
| version: "0.0.0-test", | |
| time: { created: 0, updated: 0 }, | |
| }, | |
| ]) | |
| }) | |
| const originalWrite = process.stdout.write.bind(process.stdout) | |
| let stdout = "" | |
| let api: TuiPluginApi | undefined | |
| let started!: () => void | |
| const ready = new Promise<void>((resolve) => { | |
| started = resolve | |
| }) | |
| process.stdout.write = ((chunk: string | Uint8Array) => { | |
| stdout += String(chunk) | |
| return true | |
| }) as typeof process.stdout.write | |
| try { | |
| const { run } = await import("../src/app") | |
| const task = Effect.runPromise( | |
| run({ | |
| url: "http://test", | |
| directory, | |
| config: createTuiResolvedConfig({ plugin_enabled: {} }), | |
| fetch: calls.fetch, | |
| events: events.source, | |
| args: { continue: true }, | |
| pluginHost: { | |
| async start(input) { | |
| api = input.api | |
| started() | |
| }, | |
| async dispose() {}, | |
| }, | |
| }).pipe(Effect.provide(AppNodeBuilder.build(Global.node))), | |
| ) | |
| await ready | |
| await setup.renderOnce() | |
| await setup.renderOnce() | |
| api?.keymap.dispatchCommand("app.exit") | |
| await task | |
| expect(stdout).toContain("Demo session") | |
| expect(stdout).toContain("opencode -s dummy") | |
| } finally { | |
| process.stdout.write = originalWrite | |
| if (!setup.renderer.isDestroyed) setup.renderer.destroy() | |
| mock.restore() | |
| } | |
| }) | |
| test("fatal startup errors set a nonzero exit after scoped cleanup", async () => { | |
| const setup = await createTestRenderer({ width: 80, height: 24, useThread: false }) | |
| const core = await import("@opentui/core") | |
| await mock.module("@opentui/core", () => ({ ...core, createCliRenderer: async () => setup.renderer })) | |
| const events = createEventSource() | |
| const calls = createFetch((url) => { | |
| if (url.pathname === "/config") | |
| return json( | |
| { | |
| name: "ConfigRemoteAuthError", | |
| data: { | |
| url: "https://example.com", | |
| remote: "https://config.example.com/opencode.json", | |
| }, | |
| }, | |
| { status: 400 }, | |
| ) | |
| return undefined | |
| }) | |
| let disposes = 0 | |
| const originalWrite = process.stderr.write.bind(process.stderr) | |
| const originalExitCode = process.exitCode ?? 0 | |
| let stderr = "" | |
| process.stderr.write = ((chunk: string | Uint8Array) => { | |
| stderr += String(chunk) | |
| return true | |
| }) as typeof process.stderr.write | |
| try { | |
| const { run } = await import("../src/app") | |
| const task = Effect.runPromise( | |
| run({ | |
| url: "http://test", | |
| directory, | |
| config: createTuiResolvedConfig({ plugin_enabled: {} }), | |
| fetch: calls.fetch, | |
| events: events.source, | |
| args: {}, | |
| pluginHost: { | |
| async start() {}, | |
| async dispose() { | |
| disposes++ | |
| }, | |
| }, | |
| }).pipe(Effect.provide(AppNodeBuilder.build(Global.node))), | |
| ) | |
| await task | |
| expect(stderr).toContain("Run `opencode auth login https://example.com` to re-authenticate.") | |
| expect(stderr).not.toContain("Unexpected server error") | |
| expect(process.exitCode).toBe(1) | |
| expect(setup.renderer.isDestroyed).toBe(true) | |
| expect(disposes).toBe(1) | |
| } finally { | |
| process.stderr.write = originalWrite | |
| process.exitCode = originalExitCode | |
| if (!setup.renderer.isDestroyed) setup.renderer.destroy() | |
| mock.restore() | |
| } | |
| }) | |