/** * MemoryClient unit tests — getProject, updateProject, exports, feedback. * Tests verify request construction and validation behavior. */ import { MemoryClient } from "../mem0"; import { Feedback } from "../mem0.types"; import { createMockFetch, TEST_API_KEY, TEST_ORG_ID, TEST_PROJECT_ID, } from "./helpers"; import { setupMockFetch, findFetchCall, getFetchBody, installConsoleSuppression, } from "./setup"; installConsoleSuppression(); // ─── getProject() ─────────────────────────────────────── describe("MemoryClient - getProject()", () => { test("throws when organizationId and projectId not set", async () => { const responses = new Map(); responses.set("/v1/ping/", { status: 200, body: { status: "ok" } }); global.fetch = createMockFetch(responses); const client = new MemoryClient({ apiKey: TEST_API_KEY }); try { await client.ping(); } catch { // ping might throw — but orgId stays null } await expect( client.getProject({ fields: ["custom_instructions"] }), ).rejects.toThrow("organizationId and projectId must be set"); }); test("sends GET to /api/v1/orgs/organizations/:orgId/projects/:projId/", async () => { const extra = new Map(); extra.set("/api/v1/orgs/organizations/", { status: 200, body: { custom_instructions: "Be helpful" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.getProject({ fields: ["custom_instructions"] }); const call = mock.mock.calls.find( (c: [string, RequestInit]) => c[0].includes("/api/v1/orgs/organizations/") && !c[1]?.method, ); expect(call).toBeDefined(); expect(call![0]).toContain("fields=custom_instructions"); }); }); // ─── updateProject() ──────────────────────────────────── describe("MemoryClient - updateProject()", () => { test("sends PATCH to /api/v1/orgs/organizations/:orgId/projects/:projId/", async () => { const extra = new Map(); extra.set("/api/v1/orgs/organizations/", { status: 200, body: { custom_instructions: "Updated" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.updateProject({ custom_instructions: "Updated instructions", }); const call = findFetchCall(mock, "/api/v1/orgs/organizations/", "PATCH"); expect(call).toBeDefined(); }); test("includes custom_instructions in PATCH body", async () => { const extra = new Map(); extra.set("/api/v1/orgs/organizations/", { status: 200, body: { custom_instructions: "Updated" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.updateProject({ custom_instructions: "Updated instructions", }); const call = findFetchCall(mock, "/api/v1/orgs/organizations/", "PATCH"); expect(getFetchBody(call!).custom_instructions).toBe( "Updated instructions", ); }); }); // ─── feedback() ───────────────────────────────────────── describe("MemoryClient - feedback()", () => { test("sends POST to /v1/feedback/ with payload", async () => { const extra = new Map(); extra.set("/v1/feedback/", { status: 200, body: { message: "Feedback recorded" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY }); await client.feedback({ memory_id: "mem_123", feedback: Feedback.POSITIVE, feedback_reason: "Very helpful", }); const call = findFetchCall(mock, "/v1/feedback/", "POST"); expect(call).toBeDefined(); }); test("includes memory_id, feedback, and reason in body", async () => { const extra = new Map(); extra.set("/v1/feedback/", { status: 200, body: { message: "Feedback recorded" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY }); await client.feedback({ memory_id: "mem_123", feedback: Feedback.POSITIVE, feedback_reason: "Very helpful", }); const call = findFetchCall(mock, "/v1/feedback/", "POST"); const body = getFetchBody(call!); expect(body.memory_id).toBe("mem_123"); expect(body.feedback).toBe("POSITIVE"); expect(body.feedback_reason).toBe("Very helpful"); }); }); // ─── Memory Exports ───────────────────────────────────── describe("MemoryClient - Memory Exports", () => { test("createMemoryExport throws when missing filters or schema", async () => { setupMockFetch(); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await expect( client.createMemoryExport({ filters: null as never, schema: null as never, }), ).rejects.toThrow("Missing filters or schema"); }); test("createMemoryExport sends POST to /v1/exports/", async () => { const extra = new Map(); extra.set("/v1/exports/", { status: 200, body: { message: "Export created", id: "exp_123" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.createMemoryExport({ schema: { fields: ["memory", "user_id"] }, filters: { user_id: "u1" }, }); expect(findFetchCall(mock, "/v1/exports/", "POST")).toBeDefined(); }); test("createMemoryExport attaches org_id and project_id to body", async () => { const extra = new Map(); extra.set("/v1/exports/", { status: 200, body: { message: "Created", id: "exp_1" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.createMemoryExport({ schema: { fields: ["memory"] }, filters: { user_id: "u1" }, }); const call = findFetchCall(mock, "/v1/exports/", "POST"); const body = getFetchBody(call!); expect(body.org_id).toBe(TEST_ORG_ID); expect(body.project_id).toBe(TEST_PROJECT_ID); }); test("getMemoryExport throws when missing both id and filters", async () => { setupMockFetch(); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await expect(client.getMemoryExport({} as never)).rejects.toThrow( "Missing memory_export_id or filters", ); }); test("getMemoryExport sends POST to /v1/exports/get/", async () => { const extra = new Map(); extra.set("/v1/exports/get/", { status: 200, body: { message: "Export data", id: "exp_123" }, }); const mock = setupMockFetch(extra); const client = new MemoryClient({ apiKey: TEST_API_KEY, organizationId: TEST_ORG_ID, projectId: TEST_PROJECT_ID, }); await client.getMemoryExport({ memory_export_id: "exp_123" }); expect(findFetchCall(mock, "/v1/exports/get/", "POST")).toBeDefined(); }); });