From 725350f9d1d0201a40254763cc988d1adfa8524b Mon Sep 17 00:00:00 2001 From: probe Date: Sat, 24 Oct 2026 02:12:33 +0800 Subject: [PATCH] test(webui): wait for the fork title's suggestion before typing it The forked session's title came out as the suggested title with the typed name appended to it: "1 - Message actions before refresh.synthetic-message-fork" instead of "synthetic-message-fork". Playwright's fill() is not one assignment on a text input. The injected fill() falls through to selectText() and answers "needsinput", and the server then inserts the text with keyboard.insertText() in a second round trip. The suggested title arrives with the fork options, so it can land between those two steps. The HTML value setter moves the text entry cursor position to the end of the control, so the selection collapses and the insert appends to the suggestion instead of replacing it. The client is right to keep a name a person typed: the late reply is skipped once the field has been edited. But this case typed nothing until the suggestion had already landed, and it typed through fill()'s two steps, so the suggestion was still unwritten when the guard looked at it. Wait for the fork options' reply, and for the suggestion to be in the field, before typing. The assertion is unchanged: the fork request must carry the typed name and must not carry the suggestion. --- .../webui/test/integration/agent-transcript.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/webui/test/integration/agent-transcript.test.ts b/packages/webui/test/integration/agent-transcript.test.ts index b76a84751..2de9b6039 100644 --- a/packages/webui/test/integration/agent-transcript.test.ts +++ b/packages/webui/test/integration/agent-transcript.test.ts @@ -709,6 +709,18 @@ it("a real agent turn resumes after refresh and drains a queued message in order await browserExpect(forkDialog).toBeVisible(); await browserExpect.poll(() => requests.some((request) => request.operation === "getSessionForkOptions")) .toBe(true); + // The suggested title arrives with the fork options and is written into the + // field. Wait for that write to land before typing. Playwright's fill + // selects the field and then inserts the text in a second round trip, and + // a suggestion landing between the two moves the caret to the end of the + // suggestion, so the typed name would be appended to it instead of + // replacing it. + const forkOptionsRequest = requests.find((request) => request.operation === "getSessionForkOptions"); + await browserExpect.poll(() => received.some((response) => + response.requestId === forkOptionsRequest?.requestId && response.kind === "response", + )).toBe(true); + await browserExpect.poll(() => forkDialog.getByLabel("会话名称").inputValue(), { timeout: 20_000 }) + .not.toBe(""); await forkDialog.getByLabel("会话名称").fill("synthetic-message-fork"); await forkDialog.getByRole("button", { name: "复制并进入" }).click(); await browserExpect.poll(() => requests.some((request) => request.operation === "forkSession"))