- Tauri : commande change_agent_profile + ChangeAgentProfileRequestDto/Dto (camelCase, relaunchedSession omis si None), câblage state.rs par composition. - Front : gateway changeAgentProfile (adapters Tauri+mock), sélecteur de profil par agent, dialog de confirmation FR (« Changer le moteur abandonne l'historique de conversation… »), refresh sur event agentProfileChanged. Tests : app-tauri dto 5/5 ; vitest 314/314 (mapping, payload, dialog gating, libellé FR, refresh). 0 régression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
122 lines
3.8 KiB
TypeScript
122 lines
3.8 KiB
TypeScript
/**
|
|
* Contract tests for `TauriAgentGateway`: they assert the exact `invoke()`
|
|
* payload shape, which the mock gateway (used by feature tests) does NOT
|
|
* exercise. This guards the class of "works in mock, broken in the real app"
|
|
* bugs — e.g. forgetting to nest `projectId` inside the command's `request` DTO.
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
const invoke = vi.fn();
|
|
vi.mock("@tauri-apps/api/core", () => ({
|
|
invoke: (...args: unknown[]) => invoke(...args),
|
|
Channel: class {
|
|
onmessage: ((c: number[]) => void) | null = null;
|
|
},
|
|
}));
|
|
|
|
import { TauriAgentGateway } from "./agent";
|
|
|
|
describe("TauriAgentGateway invoke payloads", () => {
|
|
beforeEach(() => invoke.mockReset().mockResolvedValue({}));
|
|
|
|
it("create_agent nests projectId inside the request DTO", async () => {
|
|
await new TauriAgentGateway().createAgent("proj-1", {
|
|
name: "Backend",
|
|
profileId: "prof-9",
|
|
});
|
|
expect(invoke).toHaveBeenCalledWith("create_agent", {
|
|
request: {
|
|
projectId: "proj-1",
|
|
name: "Backend",
|
|
profileId: "prof-9",
|
|
initialContent: null,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("update_agent_context wraps fields in the request DTO", async () => {
|
|
await new TauriAgentGateway().updateContext("proj-1", "agent-2", "# ctx");
|
|
expect(invoke).toHaveBeenCalledWith("update_agent_context", {
|
|
request: { projectId: "proj-1", agentId: "agent-2", content: "# ctx" },
|
|
});
|
|
});
|
|
|
|
it("list_agents / read / delete pass top-level args (no request wrapper)", async () => {
|
|
const gw = new TauriAgentGateway();
|
|
await gw.listAgents("p");
|
|
expect(invoke).toHaveBeenCalledWith("list_agents", { projectId: "p" });
|
|
|
|
await gw.readContext("p", "a");
|
|
expect(invoke).toHaveBeenCalledWith("read_agent_context", {
|
|
projectId: "p",
|
|
agentId: "a",
|
|
});
|
|
|
|
await gw.deleteAgent("p", "a");
|
|
expect(invoke).toHaveBeenCalledWith("delete_agent", {
|
|
projectId: "p",
|
|
agentId: "a",
|
|
});
|
|
});
|
|
|
|
it("attach_live_agent wraps project, agent and target node in the request DTO", async () => {
|
|
invoke.mockResolvedValueOnce([
|
|
{ agentId: "agent-2", nodeId: "node-3", sessionId: "session-4" },
|
|
]);
|
|
await new TauriAgentGateway().attachLiveAgent("proj-1", "agent-2", "node-3");
|
|
expect(invoke).toHaveBeenCalledWith("attach_live_agent", {
|
|
request: { projectId: "proj-1", agentId: "agent-2", nodeId: "node-3" },
|
|
});
|
|
});
|
|
|
|
it("change_agent_profile wraps all five fields in the request DTO (camelCase)", async () => {
|
|
invoke.mockResolvedValueOnce({ agent: { id: "agent-2" } });
|
|
await new TauriAgentGateway().changeAgentProfile(
|
|
"proj-1",
|
|
"agent-2",
|
|
"prof-9",
|
|
30,
|
|
120,
|
|
);
|
|
expect(invoke).toHaveBeenCalledWith("change_agent_profile", {
|
|
request: {
|
|
projectId: "proj-1",
|
|
agentId: "agent-2",
|
|
profileId: "prof-9",
|
|
rows: 30,
|
|
cols: 120,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("change_agent_profile returns the mutated agent and the relaunched session", async () => {
|
|
const response = {
|
|
agent: { id: "agent-2", profileId: "prof-9" },
|
|
relaunchedSession: { sessionId: "sess-7", cwd: "/p", rows: 30, cols: 120 },
|
|
};
|
|
invoke.mockResolvedValueOnce(response);
|
|
const out = await new TauriAgentGateway().changeAgentProfile(
|
|
"proj-1",
|
|
"agent-2",
|
|
"prof-9",
|
|
30,
|
|
120,
|
|
);
|
|
expect(out.agent.profileId).toBe("prof-9");
|
|
expect(out.relaunchedSession?.sessionId).toBe("sess-7");
|
|
});
|
|
|
|
it("change_agent_profile leaves relaunchedSession undefined when the backend omits it", async () => {
|
|
invoke.mockResolvedValueOnce({ agent: { id: "agent-2" } });
|
|
const out = await new TauriAgentGateway().changeAgentProfile(
|
|
"proj-1",
|
|
"agent-2",
|
|
"prof-9",
|
|
30,
|
|
120,
|
|
);
|
|
expect(out.relaunchedSession).toBeUndefined();
|
|
});
|
|
});
|