mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-24 03:09:48 -04:00
9e0d3976e1
Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: James Long <longster@gmail.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Jay <air@live.ca> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com>
100 lines
4.2 KiB
TypeScript
100 lines
4.2 KiB
TypeScript
import { expect, test } from "@playwright/test"
|
|
import {
|
|
assistantMessage,
|
|
partUpdated,
|
|
setupTimeline,
|
|
toolPart,
|
|
userMessage,
|
|
} from "../performance/timeline-stability/fixture"
|
|
|
|
test("renders every tool error outcome without leaking hidden tools", async ({ page }) => {
|
|
const ordinary = ["bash", "edit", "write", "apply_patch", "webfetch", "websearch", "task", "skill", "mcp_probe"]
|
|
const parts = ordinary.map((tool, index) =>
|
|
toolPart(`prt_error_${index}`, tool, "error", errorInput(tool), { error: `${tool} failed visibly` }),
|
|
)
|
|
parts.push(
|
|
toolPart("prt_question_dismissed", "question", "error", questionInput(), {
|
|
error: "The user dismissed this question",
|
|
}),
|
|
toolPart("prt_question_error", "question", "error", questionInput(), { error: "Question transport failed" }),
|
|
toolPart("prt_todo_error", "todowrite", "error", { todos: [] }, { error: "Hidden todo failure" }),
|
|
)
|
|
await setupTimeline(page, { messages: [userMessage(), assistantMessage(parts)] })
|
|
|
|
await expect(page.locator('[data-kind="tool-error-card"]')).toHaveCount(ordinary.length + 1)
|
|
await expect(page.getByText(/dismissed/i)).toBeVisible()
|
|
await expect(page.locator('[data-timeline-part-id="prt_todo_error"]')).toHaveCount(0)
|
|
for (let index = 0; index < ordinary.length; index++) {
|
|
await expect(page.locator(`[data-timeline-part-id="prt_error_${index}"]`)).toBeVisible()
|
|
}
|
|
})
|
|
|
|
test("transitions shell and question through running error outcomes", async ({ page }) => {
|
|
const shellID = "prt_transition_error_shell"
|
|
const questionID = "prt_transition_error_question"
|
|
const timeline = await setupTimeline(page, {
|
|
messages: [
|
|
userMessage(),
|
|
assistantMessage(
|
|
[
|
|
toolPart(shellID, "bash", "pending", { command: "exit 1" }),
|
|
toolPart(questionID, "question", "pending", questionInput()),
|
|
],
|
|
{ completed: false },
|
|
),
|
|
],
|
|
})
|
|
await timeline.waitForPart(shellID)
|
|
await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toHaveCount(0)
|
|
await timeline.send(partUpdated(toolPart(shellID, "bash", "running", { command: "exit 1" })), 120)
|
|
await timeline.send(partUpdated(toolPart(questionID, "question", "running", questionInput())), 180)
|
|
await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toHaveCount(0)
|
|
await timeline.send(
|
|
partUpdated(toolPart(shellID, "bash", "error", { command: "exit 1" }, { error: "Command exited 1" })),
|
|
180,
|
|
)
|
|
await timeline.send(
|
|
partUpdated(
|
|
toolPart(questionID, "question", "error", questionInput(), { error: "The user dismissed this question" }),
|
|
),
|
|
250,
|
|
)
|
|
|
|
await expect(page.locator(`[data-timeline-part-id="${shellID}"] [data-kind="tool-error-card"]`)).toBeVisible()
|
|
await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toContainText(/dismissed/i)
|
|
})
|
|
|
|
test("labels all web search provider variants", async ({ page }) => {
|
|
const parts = [
|
|
toolPart(
|
|
"prt_search_parallel",
|
|
"websearch",
|
|
"completed",
|
|
{ query: "parallel" },
|
|
{ metadata: { provider: "parallel" } },
|
|
),
|
|
toolPart("prt_search_exa", "websearch", "completed", { query: "exa" }, { metadata: { provider: "exa" } }),
|
|
toolPart("prt_search_generic", "websearch", "completed", { query: "generic" }),
|
|
]
|
|
await setupTimeline(page, { messages: [userMessage(), assistantMessage(parts)] })
|
|
|
|
await expect(page.getByRole("button", { name: /Parallel Web Search/ })).toBeVisible()
|
|
await expect(page.getByRole("button", { name: /Exa Web Search/ })).toBeVisible()
|
|
await expect(page.getByRole("button", { name: /^Web Search/ })).toBeVisible()
|
|
})
|
|
|
|
function questionInput() {
|
|
return { questions: [{ header: "Stability", question: "Keep it stable?", options: [] }] }
|
|
}
|
|
|
|
function errorInput(tool: string) {
|
|
if (tool === "bash") return { command: "exit 1" }
|
|
if (["edit", "write"].includes(tool)) return { filePath: "src/error.ts", content: "" }
|
|
if (tool === "apply_patch") return { files: ["src/error.ts"] }
|
|
if (tool === "webfetch") return { url: "https://example.com" }
|
|
if (tool === "websearch") return { query: "failure" }
|
|
if (tool === "task") return { description: "Fail task", subagent_type: "explore" }
|
|
if (tool === "skill") return { name: "failure" }
|
|
return { target: "failure" }
|
|
}
|