feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
150
frontend/src/features/layout/setCellAgent.test.tsx
Normal file
150
frontend/src/features/layout/setCellAgent.test.tsx
Normal file
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* #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(
|
||||
<DIProvider gateways={gateways}>
|
||||
<LayoutGrid projectId={projectId} cwd="/home/me/proj" />
|
||||
</DIProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user