opencode/packages/app/e2e/prompt/prompt-async.spec.ts

83 lines
2.7 KiB
TypeScript

import { test, expect } from "../fixtures"
import { promptSelector } from "../selectors"
import { assistantText, sessionIDFromUrl, withSession } from "../actions"
import { openaiModel, promptMatch, withMockOpenAI } from "./mock"
const text = (value: string | null) => (value ?? "").replace(/\u200B/g, "").trim()
// Regression test for Issue #12453: the synchronous POST /message endpoint holds
// the connection open while the agent works, causing "Failed to fetch" over
// VPN/Tailscale. The fix switches to POST /prompt_async which returns immediately.
test("prompt succeeds when sync message endpoint is unreachable", async ({
page,
llm,
backend,
withBackendProject,
}) => {
test.setTimeout(120_000)
// Simulate Tailscale/VPN killing the long-lived sync connection
await page.route("**/session/*/message", (route) => route.abort("connectionfailed"))
await withMockOpenAI({
serverUrl: backend.url,
llmUrl: llm.url,
fn: async () => {
const token = `E2E_ASYNC_${Date.now()}`
await llm.textMatch(promptMatch(token), token)
await withBackendProject(
async (project) => {
await page.locator(promptSelector).click()
await page.keyboard.type(`Reply with exactly: ${token}`)
await page.keyboard.press("Enter")
await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 })
const sessionID = sessionIDFromUrl(page.url())!
project.trackSession(sessionID)
await expect.poll(() => llm.calls()).toBeGreaterThanOrEqual(1)
await expect
.poll(() => assistantText(project.sdk, sessionID), { timeout: 90_000 })
.toContain(token)
},
{
model: openaiModel,
},
)
},
})
})
test("failed prompt send restores the composer input", async ({ page, sdk, gotoSession }) => {
await withSession(sdk, `e2e prompt failure ${Date.now()}`, async (session) => {
const prompt = page.locator(promptSelector)
const value = `restore ${Date.now()}`
await page.route(`**/session/${session.id}/prompt_async`, (route) =>
route.fulfill({
status: 500,
contentType: "application/json",
body: JSON.stringify({ message: "e2e prompt failure" }),
}),
)
await gotoSession(session.id)
await prompt.click()
await page.keyboard.type(value)
await page.keyboard.press("Enter")
await expect.poll(async () => text(await prompt.textContent())).toBe(value)
await expect
.poll(
async () => {
const messages = await sdk.session.messages({ sessionID: session.id, limit: 50 }).then((r) => r.data ?? [])
return messages.length
},
{ timeout: 15_000 },
)
.toBe(0)
})
})