learning_ai_notes/web/src/lib/palace-client.test.ts

132 lines
4.4 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
const mockFetch = vi.fn();
vi.mock("@/lib/api-helpers", () => ({
createNotesApiClient: () => ({ fetch: mockFetch }),
}));
import {
searchPalace,
listWings,
getWingSummary,
deleteWing,
listRooms,
storeMemory,
listMemories,
deleteMemory,
queryEntity,
getEntityTimeline,
getKGContradictions,
getWakeUpContext,
getPalaceStats,
backfillEmbeddings,
pruneMemories,
getPalaceHealth,
} from "./palace-client";
beforeEach(() => {
mockFetch.mockReset();
});
describe("palace-client", () => {
it("searchPalace calls /palace/search with query params", async () => {
mockFetch.mockResolvedValue([{ id: "m1", content: "JWT" }]);
const result = await searchPalace("JWT", "wing-1", 5);
expect(mockFetch).toHaveBeenCalledWith("/palace/search?q=JWT&limit=5&wingId=wing-1");
expect(result).toHaveLength(1);
});
it("listWings calls /palace/wings", async () => {
mockFetch.mockResolvedValue([]);
await listWings();
expect(mockFetch).toHaveBeenCalledWith("/palace/wings");
});
it("getWingSummary calls /palace/wings/:wingId", async () => {
mockFetch.mockResolvedValue({ wing: { id: "w1" }, rooms: [], totalMemories: 0 });
await getWingSummary("w1");
expect(mockFetch).toHaveBeenCalledWith("/palace/wings/w1");
});
it("deleteWing calls DELETE /palace/wings/:wingId", async () => {
mockFetch.mockResolvedValue(undefined);
await deleteWing("w1");
expect(mockFetch).toHaveBeenCalledWith("/palace/wings/w1", { method: "DELETE" });
});
it("listRooms calls /palace/wings/:wingId/rooms", async () => {
mockFetch.mockResolvedValue([]);
await listRooms("w1");
expect(mockFetch).toHaveBeenCalledWith("/palace/wings/w1/rooms");
});
it("storeMemory calls POST /palace/memories", async () => {
mockFetch.mockResolvedValue({ stored: true });
const result = await storeMemory({
wingId: "w1", roomId: "r1", hall: "decisions", content: "test",
});
expect(result.stored).toBe(true);
expect(mockFetch).toHaveBeenCalledWith("/palace/memories", expect.objectContaining({ method: "POST" }));
});
it("listMemories builds query string correctly", async () => {
mockFetch.mockResolvedValue([]);
await listMemories({ wingId: "w1", hall: "decisions", limit: 5 });
expect(mockFetch).toHaveBeenCalledWith("/palace/memories?wingId=w1&hall=decisions&limit=5");
});
it("deleteMemory calls DELETE /palace/memories/:id", async () => {
mockFetch.mockResolvedValue(undefined);
await deleteMemory("m1");
expect(mockFetch).toHaveBeenCalledWith("/palace/memories/m1", { method: "DELETE" });
});
it("queryEntity calls /palace/kg/entity/:entity", async () => {
mockFetch.mockResolvedValue([]);
await queryEntity("React");
expect(mockFetch).toHaveBeenCalledWith("/palace/kg/entity/React");
});
it("getEntityTimeline calls /palace/kg/timeline/:entity", async () => {
mockFetch.mockResolvedValue([]);
await getEntityTimeline("React");
expect(mockFetch).toHaveBeenCalledWith("/palace/kg/timeline/React");
});
it("getKGContradictions with wingId", async () => {
mockFetch.mockResolvedValue([]);
await getKGContradictions("w1");
expect(mockFetch).toHaveBeenCalledWith("/palace/kg/contradictions?wingId=w1");
});
it("getWakeUpContext with task", async () => {
mockFetch.mockResolvedValue({ text: "context", wingName: "Work" });
await getWakeUpContext("w1", "auth migration");
expect(mockFetch).toHaveBeenCalledWith("/palace/wake-up/w1?task=auth%20migration");
});
it("getPalaceStats calls /palace/stats", async () => {
mockFetch.mockResolvedValue({ wings: 1, rooms: 2, memories: 5, kgTriples: 3, tunnels: 0, diaries: 0 });
const stats = await getPalaceStats();
expect(stats.memories).toBe(5);
});
it("backfillEmbeddings calls POST /palace/backfill-embeddings", async () => {
mockFetch.mockResolvedValue({ backfilled: 3 });
const result = await backfillEmbeddings();
expect(result.backfilled).toBe(3);
});
it("pruneMemories calls POST /palace/prune", async () => {
mockFetch.mockResolvedValue({ pruned: 2 });
const result = await pruneMemories({ olderThanDays: 180, minRelevance: 0.1 });
expect(result.pruned).toBe(2);
});
it("getPalaceHealth calls /palace/health", async () => {
mockFetch.mockResolvedValue({ cosmos: true, llm: true });
const health = await getPalaceHealth();
expect(health.cosmos).toBe(true);
});
});