mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-25 01:54:49 +00:00
fix(app): terminal cloning without retry (#17354)
This commit is contained in:
@@ -36,6 +36,22 @@ async function terminalID(term: Locator) {
|
||||
throw new Error(`Active terminal missing ${terminalAttr}`)
|
||||
}
|
||||
|
||||
export async function terminalConnects(page: Page, input?: { term?: Locator }) {
|
||||
const term = input?.term ?? page.locator(terminalSelector).first()
|
||||
const id = await terminalID(term)
|
||||
return page.evaluate((id) => {
|
||||
return (window as E2EWindow).__opencode_e2e?.terminal?.terminals?.[id]?.connects ?? 0
|
||||
}, id)
|
||||
}
|
||||
|
||||
export async function disconnectTerminal(page: Page, input?: { term?: Locator }) {
|
||||
const term = input?.term ?? page.locator(terminalSelector).first()
|
||||
const id = await terminalID(term)
|
||||
await page.evaluate((id) => {
|
||||
;(window as E2EWindow).__opencode_e2e?.terminal?.controls?.[id]?.disconnect?.()
|
||||
}, id)
|
||||
}
|
||||
|
||||
async function terminalReady(page: Page, term?: Locator) {
|
||||
const next = term ?? page.locator(terminalSelector).first()
|
||||
const id = await terminalID(next)
|
||||
@@ -588,12 +604,19 @@ export async function seedSessionTask(
|
||||
.flatMap((message) => message.parts)
|
||||
.find((part) => {
|
||||
if (part.type !== "tool" || part.tool !== "task") return false
|
||||
if (part.state.input?.description !== input.description) return false
|
||||
return typeof part.state.metadata?.sessionId === "string" && part.state.metadata.sessionId.length > 0
|
||||
if (!("state" in part) || !part.state || typeof part.state !== "object") return false
|
||||
if (!("input" in part.state) || !part.state.input || typeof part.state.input !== "object") return false
|
||||
if (!("description" in part.state.input) || part.state.input.description !== input.description) return false
|
||||
if (!("metadata" in part.state) || !part.state.metadata || typeof part.state.metadata !== "object")
|
||||
return false
|
||||
if (!("sessionId" in part.state.metadata)) return false
|
||||
return typeof part.state.metadata.sessionId === "string" && part.state.metadata.sessionId.length > 0
|
||||
})
|
||||
|
||||
if (!part) return
|
||||
const id = part.state.metadata?.sessionId
|
||||
if (!part || !("state" in part) || !part.state || typeof part.state !== "object") return
|
||||
if (!("metadata" in part.state) || !part.state.metadata || typeof part.state.metadata !== "object") return
|
||||
if (!("sessionId" in part.state.metadata)) return
|
||||
const id = part.state.metadata.sessionId
|
||||
if (typeof id !== "string" || !id) return
|
||||
const child = await sdk.session
|
||||
.get({ sessionID: id })
|
||||
|
||||
46
packages/app/e2e/terminal/terminal-reconnect.spec.ts
Normal file
46
packages/app/e2e/terminal/terminal-reconnect.spec.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { Page } from "@playwright/test"
|
||||
import { disconnectTerminal, runTerminal, terminalConnects, waitTerminalReady } from "../actions"
|
||||
import { test, expect } from "../fixtures"
|
||||
import { terminalSelector } from "../selectors"
|
||||
import { terminalToggleKey } from "../utils"
|
||||
|
||||
async function open(page: Page) {
|
||||
const term = page.locator(terminalSelector).first()
|
||||
const visible = await term.isVisible().catch(() => false)
|
||||
if (!visible) await page.keyboard.press(terminalToggleKey)
|
||||
await waitTerminalReady(page, { term })
|
||||
return term
|
||||
}
|
||||
|
||||
test("terminal reconnects without replacing the pty", async ({ page, withProject }) => {
|
||||
await withProject(async ({ gotoSession }) => {
|
||||
const name = `OPENCODE_E2E_RECONNECT_${Date.now()}`
|
||||
const token = `E2E_RECONNECT_${Date.now()}`
|
||||
|
||||
await gotoSession()
|
||||
|
||||
const term = await open(page)
|
||||
const id = await term.getAttribute("data-pty-id")
|
||||
if (!id) throw new Error("Active terminal missing data-pty-id")
|
||||
|
||||
const prev = await terminalConnects(page, { term })
|
||||
|
||||
await runTerminal(page, {
|
||||
term,
|
||||
cmd: `export ${name}=${token}; echo ${token}`,
|
||||
token,
|
||||
})
|
||||
|
||||
await disconnectTerminal(page, { term })
|
||||
|
||||
await expect.poll(() => terminalConnects(page, { term }), { timeout: 15_000 }).toBeGreaterThan(prev)
|
||||
await expect.poll(() => term.getAttribute("data-pty-id"), { timeout: 5_000 }).toBe(id)
|
||||
|
||||
await runTerminal(page, {
|
||||
term,
|
||||
cmd: `echo $${name}`,
|
||||
token,
|
||||
timeout: 15_000,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2,7 +2,8 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"rootDir": "..",
|
||||
"types": ["node", "bun"]
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
"include": ["./**/*.ts", "../src/testing/terminal.ts"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user