Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions test/helpers/coding-cli/real-session-contract-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,54 @@ export async function startCodexAppServer(
}
}

export async function startOpencodeServe(
workspace: ProbeWorkspace,
opencodePath: string,
runEnv: NodeJS.ProcessEnv,
healthPath: string,
): Promise<{
baseUrl: string
port: number
process: TrackedProcess
health: unknown
}> {
const endpoint = await allocateLocalhostPort()
const baseUrl = `http://${endpoint.hostname}:${endpoint.port}`
const processHandle = await workspace.spawnProcess(
opencodePath,
['serve', '--hostname', endpoint.hostname, '--port', String(endpoint.port)],
{
env: runEnv,
},
)

// Fail fast (with the serve process's own error) if it cannot bind the port,
// rather than silently attaching to a stranger already listening on it or
// waiting out the full health-check timeout.
const health = await waitFor(`OpenCode serve ${baseUrl}`, async () => {
const stderr = processHandle.stderr()
if (/ServeError|Failed to start server|EADDRINUSE/i.test(stderr)) {
throw new Error(`OpenCode serve could not start on ${baseUrl}: ${stderr.trim()}`)
}
try {
const response = await fetchWithTimeout(`${baseUrl}${healthPath}`)
if (!response.ok) {
return undefined
}
return await response.json()
} catch {
return undefined
}
}, 30_000, 200)

return {
baseUrl,
port: endpoint.port,
process: processHandle,
health,
}
}

export class CodexRpcProbeClient {
private readonly socket: WebSocket
private readonly pendingRequests = new Map<number, PendingRpcRequest>()
Expand Down
20 changes: 8 additions & 12 deletions test/integration/real/coding-cli-session-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import {
seedCodexHome,
seedOpencodeHomes,
startCodexAppServer,
startOpencodeServe,
waitForCodexSessionArtifact,
waitForCodexShellSnapshot,
waitForFileSizeIncrease,
waitForAnyHttpBusyStatus,
waitForHttpHealthy,
waitForJsonResponse,
waitForJsonLine,
waitForOpencodeDbSession,
Expand Down Expand Up @@ -528,18 +528,14 @@ describe.sequential('coding cli real provider session contract', () => {
const firstDbRow = await waitForOpencodeDbSession(homes.dbPath, firstSessionId)
expect(firstDbRow.id).toBe(firstSessionId)

const servePort = 46123
const serve = await workspace.spawnProcess(
opencodePath,
['serve', '--hostname', '127.0.0.1', '--port', String(servePort)],
{
env: runEnv,
},
const { baseUrl, process: serve, health } = await startOpencodeServe(
workspace,
opencodePath,
runEnv,
note.providers.opencode.globalHealthPath,
)

const healthUrl = `http://127.0.0.1:${servePort}${note.providers.opencode.globalHealthPath}`
const statusUrl = `http://127.0.0.1:${servePort}${note.providers.opencode.sessionStatusPath}`
const health = await waitForHttpHealthy(healthUrl)
const statusUrl = `${baseUrl}${note.providers.opencode.sessionStatusPath}`
expect(health).toEqual({
healthy: true,
version: opencodeBinary.version,
Expand All @@ -555,7 +551,7 @@ describe.sequential('coding cli real provider session contract', () => {
'json',
'--dangerously-skip-permissions',
'--attach',
`http://127.0.0.1:${servePort}`,
baseUrl,
],
{
env: runEnv,
Expand Down
4 changes: 2 additions & 2 deletions test/unit/client/components/TerminalView.osc52.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ describe('TerminalView OSC52 policy handling', () => {
messageHandler!({ type: 'terminal.output', terminalId, seqStart: 1, seqEnd: 1, data: `before${OSC52_COPY}after` })

await waitFor(() => {
expect(terminalInstances[0].write).toHaveBeenCalledWith('beforeafter', undefined)
expect(terminalInstances[0].write.mock.calls.some((call) => call[0] === 'beforeafter')).toBe(true)
})
expect(clipboardMocks.copyText).toHaveBeenCalledWith('copy')
expect(screen.queryByRole('dialog', { name: 'Clipboard access request' })).not.toBeInTheDocument()
Expand Down Expand Up @@ -398,7 +398,7 @@ describe('TerminalView OSC52 policy handling', () => {
messageHandler!({ type: 'terminal.output', terminalId, seqStart: 1, seqEnd: 1, data: `before${OSC52_COPY}after` })

await waitFor(() => {
expect(terminalInstances[0].write).toHaveBeenCalledWith('beforeafter', undefined)
expect(terminalInstances[0].write.mock.calls.some((call) => call[0] === 'beforeafter')).toBe(true)
})
expect(clipboardMocks.copyText).not.toHaveBeenCalled()
expect(screen.queryByRole('dialog', { name: 'Clipboard access request' })).not.toBeInTheDocument()
Expand Down
2 changes: 1 addition & 1 deletion test/unit/client/components/TerminalView.renderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ describe('TerminalView renderer mode', () => {
data: 'still works',
})
await waitFor(() => {
expect(terminalInstances[0].write).toHaveBeenCalledWith('still works', undefined)
expect(terminalInstances[0].write.mock.calls.some((call) => call[0] === 'still works')).toBe(true)
})
})
})
Loading