Files
orca/tests/e2e/headless-serve-focused-terminal-create.spec.ts
T
Jinwoo HongandJinwoo-H aa64ac9606 fix(runtime): degrade focus-requested terminal create on headless serve (#12791)
`orca serve` publishes a ready graph under HEADLESS_RUNTIME_WINDOW_ID with no
BrowserWindow behind it. `shouldCreateInBackground` only degraded when the
create was renderer-backed, so any focus-requested create fell through to
getAuthoritativeWindow() and threw "No renderer window available" — leaving
`terminal create --focus` with no workaround on a remote server (#10333).

With a worktree selector and no renderer window, a background spawn is the only
usable path, so collapse the renderer-backed window check into a plain
"no window" check. That is the existing rendererBacked clause plus exactly the
missing focus case, and it drops the confusing `rendererWindow === null`
indirection (rendererWindow is already gated on rendererBacked).

Focus is not lost by the degrade: the spawned pane is still published to the
session-tab model and revealed with `activate: true`, which is how a paired
client learns about it. Mirrors the in-tree precedent in
runCreateMobileSessionTerminal.

Headed hosts are unaffected — the clause only fires when no window exists.

Co-authored-by: Jinwoo-H <Jinwoo-H@users.noreply.github.com>
2026-08-05 17:49:04 -07:00

58 lines
2.1 KiB
TypeScript

import { expect, test } from './helpers/orca-app'
import { launchHeadlessPairedRuntimeHost } from './helpers/headless-paired-runtime-host'
// Why (#10333): a windowless `orca serve` host answered every focus-requested
// create with "No renderer window available", so `terminal create --focus` had
// no workaround. Drive the real RPC a remote CLI sends, against a real serve
// process, so the degrade is proven on the topology that broke.
test('creates a focus-requested terminal against a headless serve host', async ({
testRepoPath
}) => {
test.setTimeout(180_000)
const host = await launchHeadlessPairedRuntimeHost()
try {
const added = await host.client.call<{ repo: { id: string } }>('repo.add', {
path: testRepoPath,
kind: 'git'
})
let worktreeId = ''
await expect
.poll(
async () => {
const listed = await host.client.call<{ worktrees: { id: string }[] }>('worktree.list', {
repo: `id:${added.result.repo.id}`
})
worktreeId = listed.result.worktrees[0]?.id ?? ''
return worktreeId
},
{ timeout: 30_000 }
)
.not.toBe('')
// Exactly what `orca --environment <remote> terminal create --worktree <wt>
// --command "echo test" --focus --json` puts on the wire.
const created = await host.client.call<{
terminal: { handle: string; worktreeId: string; ptyId?: string }
}>('terminal.create', {
worktree: `id:${worktreeId}`,
command: 'echo orca-10333-focus',
focus: true,
presentation: 'focused'
})
expect(created.result.terminal.handle).toMatch(/^term_/)
expect(created.result.terminal.worktreeId).toBe(worktreeId)
// Why: a handle the host cannot resolve back to a live PTY would be a
// hollow pass — confirm the degraded create really produced a terminal.
const listedTerminals = await host.client.call<{
terminals: { handle: string }[]
}>('terminal.list', { worktree: `id:${worktreeId}` })
expect(listedTerminals.result.terminals.map((terminal) => terminal.handle)).toContain(
created.result.terminal.handle
)
} finally {
await host.dispose()
}
})