From f07104dacc996ba4ba182e4190d2d6f39a574fc7 Mon Sep 17 00:00:00 2001 From: yyovil Date: Thu, 11 Jun 2026 16:39:13 +0530 Subject: [PATCH] fix(spawn): keep worker modal open on errors --- .../components/SpawnWorkerModal.test.tsx | 59 +++++++++++++++++++ .../renderer/components/SpawnWorkerModal.tsx | 6 +- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 frontend/src/renderer/components/SpawnWorkerModal.test.tsx diff --git a/frontend/src/renderer/components/SpawnWorkerModal.test.tsx b/frontend/src/renderer/components/SpawnWorkerModal.test.tsx new file mode 100644 index 000000000..38d6f68f4 --- /dev/null +++ b/frontend/src/renderer/components/SpawnWorkerModal.test.tsx @@ -0,0 +1,59 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; +import { SpawnWorkerModal } from "./SpawnWorkerModal"; +import { TooltipProvider } from "./ui/tooltip"; +import type { WorkspaceSummary } from "../types/workspace"; + +const workspaces: WorkspaceSummary[] = [{ id: "proj-1", name: "my-app", path: "/p", type: "main", sessions: [] }]; + +function renderModal(onCreateTask = vi.fn().mockResolvedValue(undefined), onOpenChange = () => undefined) { + render( + + + , + ); + return onCreateTask; +} + +describe("SpawnWorkerModal", () => { + it("requires a non-empty prompt before it can spawn", () => { + const onCreateTask = renderModal(); + expect(screen.getByRole("button", { name: /Spawn worker/ })).toBeDisabled(); + expect(onCreateTask).not.toHaveBeenCalled(); + }); + + it("keeps the modal open and shows the daemon error when the spawn fails", async () => { + const user = userEvent.setup(); + const onOpenChange = vi.fn(); + let rejectSpawn!: (reason: Error) => void; + const onCreateTask = vi.fn( + () => + new Promise((_, reject) => { + rejectSpawn = reject; + }), + ); + renderModal(onCreateTask, onOpenChange); + + await user.type(await screen.findByLabelText("Prompt"), "do the thing"); + await user.click(screen.getByRole("button", { name: /Spawn worker/ })); + expect(screen.getByRole("button", { name: /Spawn worker/ })).toBeDisabled(); + + rejectSpawn(new Error("branch already checked out at ~/Projects/skills")); + + expect(await screen.findByRole("alert")).toHaveTextContent("branch already checked out at ~/Projects/skills"); + expect(onOpenChange).not.toHaveBeenCalled(); + expect(screen.getByLabelText("Prompt")).toHaveValue("do the thing"); + + onCreateTask.mockResolvedValueOnce(undefined); + await user.click(screen.getByRole("button", { name: /Spawn worker/ })); + await waitFor(() => expect(onOpenChange).toHaveBeenCalledWith(false)); + expect(onCreateTask).toHaveBeenCalledTimes(2); + }); +}); diff --git a/frontend/src/renderer/components/SpawnWorkerModal.tsx b/frontend/src/renderer/components/SpawnWorkerModal.tsx index b09e46738..02c7311da 100644 --- a/frontend/src/renderer/components/SpawnWorkerModal.tsx +++ b/frontend/src/renderer/components/SpawnWorkerModal.tsx @@ -202,7 +202,11 @@ export function SpawnWorkerModal({ )} - {error &&

{error}

} + {error && ( +

+ {error} +

+ )}