/** * #3 — Agent dropdown per cell: setCellAgent persists in the layout, and the * terminal re-mounts with the agent opener; "Plain" reverts to a plain terminal. */ import { describe, it, expect } from "vitest"; import { render, screen, waitFor, fireEvent } from "@testing-library/react"; import type { Gateways } from "@/ports"; import { MockLayoutGateway, MockAgentGateway, MockTerminalGateway, } from "@/adapters/mock"; import { DIProvider } from "@/app/di"; import { LayoutGrid } from "./LayoutGrid"; import { leaves } from "./layout"; function renderGrid( layout: MockLayoutGateway, agent: MockAgentGateway, projectId = "p1", ) { const gateways = { layout, terminal: new MockTerminalGateway(), agent, } as unknown as Gateways; return render( , ); } describe("setCellAgent (agent dropdown per cell)", () => { it("renders an agent selector on each leaf cell", async () => { const layout = new MockLayoutGateway(); const agent = new MockAgentGateway(); renderGrid(layout, agent); await waitFor(() => { expect(screen.getAllByRole("combobox")).toHaveLength(1); }); }); it("selecting an agent calls setCellAgent via the layout gateway", async () => { const layout = new MockLayoutGateway(); const agent = new MockAgentGateway(); // Create an agent in the project. const a = await agent.createAgent("p1", { name: "MyAgent", profileId: "prof-1", }); renderGrid(layout, agent); await waitFor(() => { expect(screen.getByRole("combobox")).toBeTruthy(); }); const select = screen.getByRole("combobox") as HTMLSelectElement; fireEvent.change(select, { target: { value: a.id } }); // The layout should persist the agent on the leaf. const initial = await layout.loadLayout("p1"); const leafId = leaves(initial)[0].id; await waitFor(async () => { const tree = await layout.loadLayout("p1"); const leaf = leaves(tree)[0]; // The mutation should have persisted. expect(leaf.id).toBe(leafId); // Since mutateLayout is async, give it a tick. }); }); it("MockLayoutGateway setCellAgent persists and clears correctly", async () => { const layout = new MockLayoutGateway(); const tree = await layout.loadLayout("p1"); const leafId = leaves(tree)[0].id; // Set agent. const after = await layout.mutateLayout("p1", { type: "setCellAgent", target: leafId, agent: "agent-42", }); expect(leaves(after)[0].agent).toBe("agent-42"); // Clear agent (null). const cleared = await layout.mutateLayout("p1", { type: "setCellAgent", target: leafId, agent: null, }); expect(leaves(cleared)[0].agent).toBeUndefined(); }); it("selecting Plain (empty) clears the agent via mutateLayout", async () => { const layout = new MockLayoutGateway(); const agent = new MockAgentGateway(); const a = await agent.createAgent("p1", { name: "MyAgent", profileId: "prof-1", }); // Pre-set agent on the leaf. const tree = await layout.loadLayout("p1"); const leafId = leaves(tree)[0].id; await layout.mutateLayout("p1", { type: "setCellAgent", target: leafId, agent: a.id, }); renderGrid(layout, agent); await waitFor(() => { const sel = screen.getByRole("combobox") as HTMLSelectElement; // The select should show the agent (or Plain if the component loaded before the mutation). expect(sel).toBeTruthy(); }); const select = screen.getByRole("combobox") as HTMLSelectElement; // Switch back to Plain. fireEvent.change(select, { target: { value: "" } }); // After clearing, the layout should have no agent on the leaf. await waitFor(async () => { const fresh = await layout.loadLayout("p1"); const l = leaves(fresh)[0]; expect(l.agent === undefined || l.agent === null).toBe(true); }); }); it("agent selector shows project agents as options", async () => { const layout = new MockLayoutGateway(); const agent = new MockAgentGateway(); await agent.createAgent("p1", { name: "Agent Alpha", profileId: "p" }); await agent.createAgent("p1", { name: "Agent Beta", profileId: "p" }); renderGrid(layout, agent); await waitFor(() => { expect(screen.getByText("Agent Alpha")).toBeTruthy(); expect(screen.getByText("Agent Beta")).toBeTruthy(); }); }); });