Files
IdeA/frontend/src/adapters/mock/layout.test.ts
Blomios 307ae71857 feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
2026-06-06 01:27:01 +02:00

165 lines
5.9 KiB
TypeScript

/**
* L4 — behavioural tests for {@link MockLayoutGateway}: it defaults to a single
* empty leaf, applies mutations and returns the new tree, and keeps a separate
* in-memory tree per project.
*/
import { describe, it, expect } from "vitest";
import { leaves } from "@/features/layout/layout";
import { MockLayoutGateway } from "./index";
describe("MockLayoutGateway", () => {
it("loadLayout defaults to a single empty leaf", async () => {
const gw = new MockLayoutGateway();
const tree = await gw.loadLayout("p1");
expect(tree.root.type).toBe("leaf");
const ls = leaves(tree);
expect(ls).toHaveLength(1);
expect(ls[0].session ?? null).toBeNull();
});
it("loadLayout returns a stable tree for the same project", async () => {
const gw = new MockLayoutGateway();
const a = await gw.loadLayout("p1");
const b = await gw.loadLayout("p1");
expect(b).toEqual(a); // same persisted tree (id preserved)
});
it("mutateLayout applies the op and returns the mutated tree", async () => {
const gw = new MockLayoutGateway();
const initial = await gw.loadLayout("p1");
const leafId = leaves(initial)[0].id;
const next = await gw.mutateLayout("p1", {
type: "split",
target: leafId,
direction: "row",
newLeaf: "b",
container: "c",
});
expect(next.root.type).toBe("split");
expect(leaves(next)).toHaveLength(2);
});
it("persists the mutation in memory (next load reflects it)", async () => {
const gw = new MockLayoutGateway();
const initial = await gw.loadLayout("p1");
const leafId = leaves(initial)[0].id;
await gw.mutateLayout("p1", {
type: "setSession",
target: leafId,
session: "s9",
});
const reloaded = await gw.loadLayout("p1");
expect(leaves(reloaded)[0].session).toBe("s9");
});
it("keeps a separate tree per project", async () => {
const gw = new MockLayoutGateway();
const p1 = await gw.loadLayout("p1");
const p2 = await gw.loadLayout("p2");
await gw.mutateLayout("p1", {
type: "split",
target: leaves(p1)[0].id,
direction: "row",
newLeaf: "b",
container: "c",
});
// p2 is untouched.
const p2After = await gw.loadLayout("p2");
expect(p2After).toEqual(p2);
expect(leaves(p2After)).toHaveLength(1);
});
it("returns clones, so mutating a returned tree does not corrupt the store", async () => {
const gw = new MockLayoutGateway();
const tree = await gw.loadLayout("p1");
if (tree.root.type === "leaf") tree.root.node.session = "tampered";
const fresh = await gw.loadLayout("p1");
expect(leaves(fresh)[0].session ?? null).toBeNull();
});
// ── Multi-layout tests (#4) ────────────────────────────────────────────────
it("listLayouts returns a 'Default' layout on first call", async () => {
const gw = new MockLayoutGateway();
const { layouts, activeId } = await gw.listLayouts("p1");
expect(layouts).toHaveLength(1);
expect(layouts[0].name).toBe("Default");
expect(activeId).toBe(layouts[0].id);
});
it("createLayout adds a new named layout", async () => {
const gw = new MockLayoutGateway();
const { layoutId } = await gw.createLayout("p1", "Beta");
const { layouts } = await gw.listLayouts("p1");
expect(layouts).toHaveLength(2);
expect(layouts.some((l) => l.id === layoutId && l.name === "Beta")).toBe(true);
});
it("renameLayout changes the layout name", async () => {
const gw = new MockLayoutGateway();
const { layouts } = await gw.listLayouts("p1");
await gw.renameLayout("p1", layouts[0].id, "Renamed");
const { layouts: updated } = await gw.listLayouts("p1");
expect(updated[0].name).toBe("Renamed");
});
it("deleteLayout removes a layout and adjusts the active id", async () => {
const gw = new MockLayoutGateway();
const { layoutId: secondId } = await gw.createLayout("p1", "Second");
await gw.setActiveLayout("p1", secondId);
const { activeId } = await gw.deleteLayout("p1", secondId);
const { layouts, activeId: newActive } = await gw.listLayouts("p1");
expect(layouts).toHaveLength(1);
expect(layouts.some((l) => l.id === secondId)).toBe(false);
// active should have switched back to the Default.
expect(activeId).toBe(newActive);
});
it("setActiveLayout switches the active layout", async () => {
const gw = new MockLayoutGateway();
const { layoutId } = await gw.createLayout("p1", "Alt");
await gw.setActiveLayout("p1", layoutId);
const { activeId } = await gw.listLayouts("p1");
expect(activeId).toBe(layoutId);
});
it("loadLayout with a specific layoutId loads that layout's tree", async () => {
const gw = new MockLayoutGateway();
const { layoutId } = await gw.createLayout("p1", "Named");
// Mutate the named layout.
const tree = await gw.loadLayout("p1", layoutId);
const leafId = leaves(tree)[0].id;
await gw.mutateLayout("p1", { type: "setSession", target: leafId, session: "s-named" }, layoutId);
// The default (active) layout should be untouched.
const defaultTree = await gw.loadLayout("p1");
expect(leaves(defaultTree)[0].session ?? null).toBeNull();
// The named layout should have the session.
const namedTree = await gw.loadLayout("p1", layoutId);
expect(leaves(namedTree)[0].session).toBe("s-named");
});
it("setCellAgent persists and clears correctly in applyOperation", async () => {
const gw = new MockLayoutGateway();
const tree = await gw.loadLayout("p1");
const leafId = leaves(tree)[0].id;
const withAgent = await gw.mutateLayout("p1", {
type: "setCellAgent",
target: leafId,
agent: "agent-99",
});
expect(leaves(withAgent)[0].agent).toBe("agent-99");
const cleared = await gw.mutateLayout("p1", {
type: "setCellAgent",
target: leafId,
agent: null,
});
expect(leaves(cleared)[0].agent).toBeUndefined();
});
});