From 2ddf54730884e1508073216c9bb34671d918890f Mon Sep 17 00:00:00 2001 From: Hare Date: Thu, 1 Oct 2026 10:09:52 +0900 Subject: [PATCH] fix: remove composer footer error messages --- .../console/worker-console.ui.test.ts | 5 +-- .../workers/[workerRef]/console/+page.svelte | 27 ++++++++------- .../console/console-display.browser.spec.ts | 33 +++++++++++++++++++ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/web/workspace/src/lib/workspace/console/worker-console.ui.test.ts b/web/workspace/src/lib/workspace/console/worker-console.ui.test.ts index fb99edd9e..902c3ef29 100644 --- a/web/workspace/src/lib/workspace/console/worker-console.ui.test.ts +++ b/web/workspace/src/lib/workspace/console/worker-console.ui.test.ts @@ -957,8 +957,9 @@ Deno.test("Worker Console keeps Notify beside Submit without persistent notices" !consolePage.includes("composer-notice") && !consolePage.includes('class="composer-actions"') && !consolePage.includes("Sent through Worker protocol.") && - consolePage.includes('{#if sendError}{/if} diff --git a/web/workspace/src/routes/w/[workspaceId]/workers/[workerRef]/console/console-display.browser.spec.ts b/web/workspace/src/routes/w/[workspaceId]/workers/[workerRef]/console/console-display.browser.spec.ts index f652275cc..44e61f63a 100644 --- a/web/workspace/src/routes/w/[workspaceId]/workers/[workerRef]/console/console-display.browser.spec.ts +++ b/web/workspace/src/routes/w/[workspaceId]/workers/[workerRef]/console/console-display.browser.spec.ts @@ -16,6 +16,7 @@ import type { } from "$lib/generated/protocol"; import type { Worker } from "$lib/workspace/sidebar/types"; import { EditorView } from "@codemirror/view"; +import * as alerts from "$lib/workspace/alerts/store"; import ConsolePage from "./+page.svelte"; const multiplexer = vi.hoisted(() => { @@ -263,6 +264,38 @@ test.each(["live_protocol", "retained_snapshot"] as const)("overlapping history expect(view.container.querySelectorAll(".activity-summary")).toHaveLength(1); }); +test.each([ + { text: ":peer", message: "Invalid arguments. Usage: :peer ", transportFailure: false }, + { text: "keep this draft", message: "test transport failure", transportFailure: true }, +])("Composer keeps $text on failure without adding any footer message", async ({ text, message, transportFailure }) => { + const alert = vi.spyOn(alerts, "pushWorkspaceAlert"); + vi.stubGlobal("fetch", vi.fn(async () => Response.json({ availability: "live_protocol" }))); + const view = render(ConsolePage, { data: pageData() }); + await waitFor(() => expect(multiplexer.subscribe).toHaveBeenCalledOnce()); + latestListener().onFrame(subscribedFrame(emptySession())); + await screen.findByText("No conversation to display"); + const cm = EditorView.findFromDOM(view.container.querySelector(".cm-editor") as HTMLElement)!; + const form = view.container.querySelector(".console-composer") as HTMLFormElement; + cm.dispatch({ changes: { from: 0, insert: text }, selection: { anchor: text.length } }); + if (transportFailure) multiplexer.sendWorkerMethod.mockImplementationOnce(() => { throw new Error(message); }); + await fireEvent.submit(form); + await waitFor(() => expect(alert).toHaveBeenCalledWith("error", message, expect.any(Object))); + expect(cm.state.doc.toString()).toBe(text); + expect(multiplexer.sendWorkerMethod).toHaveBeenCalledTimes(transportFailure ? 1 : 0); + expect(form.children).toHaveLength(1); + expect(form.firstElementChild?.classList.contains("composer-input-shell")).toBe(true); + expect(form.querySelector('[role="alert"]')).toBeNull(); + expect(form.textContent).not.toContain(message); + + cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: ":peer teammate" } }); + await fireEvent.submit(form); + await waitFor(() => expect(multiplexer.sendWorkerMethod).toHaveBeenLastCalledWith({ + method: "register_peer", params: { name: "teammate" }, + })); + expect(cm.state.doc.toString()).toBe(""); + expect(form.children).toHaveLength(1); +}); + test("pending inputs show literal previews above Composer with revision-fenced icon actions", async () => { vi.stubGlobal("fetch", vi.fn(async () => Response.json({ availability: "live_protocol" }))); const view = render(ConsolePage, { data: pageData() });