/** * Integration tests: User management, project configuration, and webhooks. * * Tests users(), getProject(), updateProject(), and webhook CRUD against the real API. * * Run: MEM0_API_KEY=your-key npx jest management.test.ts --forceExit */ import { MemoryClient } from "../../mem0"; import { WebhookEvent } from "../../mem0.types"; import { randomUUID } from "crypto"; import { describeIntegration, createTestClient, suppressTelemetryNoise, seedTestMemories, cleanupTestUser, withRetry, } from "./helpers"; jest.setTimeout(120_000); const TEST_USER_ID = `integration-mgmt-${randomUUID()}`; describeIntegration("MemoryClient Integration — Users & Project", () => { let client: MemoryClient; let cleanup: () => void; beforeAll(async () => { cleanup = suppressTelemetryNoise(); client = createTestClient(); await seedTestMemories(client, TEST_USER_ID); }); afterAll(async () => { await cleanupTestUser(client, TEST_USER_ID); cleanup(); }); // ─── Users ──────────────────────────────────────────────── describe("user management", () => { test("lists users and finds test user", async () => { const allUsers = await client.users(); expect(typeof allUsers.count).toBe("number"); expect(Array.isArray(allUsers.results)).toBe(true); if (allUsers.results.length > 0) { const user = allUsers.results[0]; expect(typeof user.id).toBe("string"); expect(typeof user.name).toBe("string"); expect(typeof user.type).toBe("string"); } const testUser = allUsers.results.find((u) => u.name === TEST_USER_ID); expect(testUser).toBeDefined(); }); }); // ─── Project ────────────────────────────────────────────── describe("project management", () => { let originalInstructions: string | undefined; test("gets project with custom_instructions field", async () => { const project = await client.getProject({ fields: ["custom_instructions"], }); expect(project).toBeDefined(); expect(typeof project).toBe("object"); expect("custom_instructions" in project).toBe(true); originalInstructions = project.custom_instructions; }); test("updates project custom_instructions via updateProject()", async () => { const testInstruction = `integration-test-${randomUUID().slice(0, 8)}`; const result = await client.updateProject({ custom_instructions: testInstruction, }); expect(result).toBeDefined(); // Verify the update took effect const project = await client.getProject({ fields: ["custom_instructions"], }); expect(project.custom_instructions).toBe(testInstruction); // Restore original await client.updateProject({ custom_instructions: originalInstructions || "", }); }); }); // ─── Webhooks ────────────────────────────────────────────── describe("webhook management", () => { let createdWebhookId: string; const hookName = `test-hook-${randomUUID().slice(0, 8)}`; const hookUrl = `https://example.com/webhook/${randomUUID().slice(0, 8)}`; const updatedName = `updated-hook-${randomUUID().slice(0, 8)}`; afterAll(async () => { if (createdWebhookId) { try { await client.deleteWebhook({ webhookId: createdWebhookId }); } catch { // ignore — may already be deleted } } }); // ─── Create ──────────────────────────────────────────── test("createWebhook returns a webhook_id", async () => { const result = await withRetry(() => client.createWebhook({ name: hookName, url: hookUrl, eventTypes: [WebhookEvent.MEMORY_ADDED, WebhookEvent.MEMORY_UPDATED], }), ); createdWebhookId = result.webhook_id!; expect(result.webhook_id).toBeDefined(); }); test("createWebhook returns the correct name", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const wh = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(wh!.name).toBe(hookName); }); test("createWebhook returns the correct url", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const wh = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(wh!.url).toBe(hookUrl); }); test("createWebhook returns the correct event_types", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const wh = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(wh!.event_types?.sort()).toStrictEqual( [WebhookEvent.MEMORY_ADDED, WebhookEvent.MEMORY_UPDATED].sort(), ); }); // ─── List ────────────────────────────────────────────── test("getWebhooks returns an array", async () => { const webhooks = await withRetry(() => client.getWebhooks()); expect(Array.isArray(webhooks)).toBe(true); }); test("getWebhooks includes the created webhook", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const found = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(found).toBeDefined(); }); test("getWebhooks shows the webhook as active", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const found = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(found!.is_active).toBe(true); }); // ─── Update ──────────────────────────────────────────── test("updateWebhook returns a success message", async () => { const result = await withRetry(() => client.updateWebhook({ webhookId: createdWebhookId, name: updatedName, url: "https://example.com/updated", eventTypes: [WebhookEvent.MEMORY_DELETED], }), ); expect(result.message).toBeDefined(); }); test("updateWebhook persists the new name", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const updated = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(updated!.name).toBe(updatedName); }); test("updateWebhook persists the new event_types", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const updated = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(updated!.event_types?.sort()).toStrictEqual( [WebhookEvent.MEMORY_DELETED].sort(), ); }); // ─── Delete ──────────────────────────────────────────── test("deleteWebhook returns a response", async () => { const result = await withRetry(() => client.deleteWebhook({ webhookId: createdWebhookId }), ); expect(result).toBeDefined(); }); test("deleteWebhook removes the webhook from the list", async () => { const webhooks = await withRetry(() => client.getWebhooks()); const found = webhooks.find((w) => w.webhook_id === createdWebhookId); expect(found).toBeUndefined(); createdWebhookId = ""; }); }); });