diff options
| author | Fuwn <[email protected]> | 2026-02-03 22:04:13 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-03 22:04:13 -0800 |
| commit | 3119964df660e9fc58c5003793711b05f217e01a (patch) | |
| tree | 73738aad2484a7dcea2c2bdf34ea29ef67ed142f /packages | |
| parent | test(mcp): Add comprehensive server tests (diff) | |
| download | archived-imemio-3119964df660e9fc58c5003793711b05f217e01a.tar.xz archived-imemio-3119964df660e9fc58c5003793711b05f217e01a.zip | |
test(sdk): Add Supabase store integration tests
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/sdk/src/supabase-store.test.ts | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/packages/sdk/src/supabase-store.test.ts b/packages/sdk/src/supabase-store.test.ts new file mode 100644 index 0000000..32e1add --- /dev/null +++ b/packages/sdk/src/supabase-store.test.ts @@ -0,0 +1,825 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import type { SupabaseClient } from "@supabase/supabase-js"; +import { SupabaseStore } from "./supabase-store.js"; +import type { Tag } from "./types.js"; + +function createMockSupabaseClient() { + const mockSingle = vi.fn(); + const mockSelect = vi.fn(() => ({ single: mockSingle })); + const mockEq = vi.fn(() => ({ + eq: mockEq, + select: mockSelect, + single: mockSingle, + })); + const mockContains = vi.fn(() => ({ data: [], error: null })); + const mockDelete = vi.fn(() => ({ eq: mockEq })); + const mockUpdate = vi.fn(() => ({ eq: mockEq })); + const mockInsert = vi.fn(() => ({ select: mockSelect })); + const mockFrom = vi.fn(() => ({ + insert: mockInsert, + select: mockSelect, + update: mockUpdate, + delete: mockDelete, + eq: mockEq, + contains: mockContains, + })); + const mockRpc = vi.fn(); + + return { + from: mockFrom, + rpc: mockRpc, + _mocks: { + from: mockFrom, + insert: mockInsert, + select: mockSelect, + update: mockUpdate, + delete: mockDelete, + eq: mockEq, + contains: mockContains, + single: mockSingle, + rpc: mockRpc, + }, + }; +} + +describe("SupabaseStore", () => { + const testUserId = "user-123"; + let mockClient: ReturnType<typeof createMockSupabaseClient>; + let store: SupabaseStore; + + beforeEach(() => { + vi.clearAllMocks(); + mockClient = createMockSupabaseClient(); + store = new SupabaseStore( + mockClient as unknown as SupabaseClient, + testUserId, + ); + }); + describe("create", () => { + it("builds correct insert query with required fields", async () => { + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Test content", + tags: [], + metadata: {}, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }; + + mockClient._mocks.single.mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + await store.create({ + content: "Test content", + projectId: "project-1", + }); + expect(mockClient.from).toHaveBeenCalledWith("memories"); + expect(mockClient._mocks.insert).toHaveBeenCalledWith({ + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Test content", + tags: [], + metadata: {}, + }); + }); + it("builds correct insert query with all optional fields", async () => { + const testTags: Tag[] = [{ id: "tag-1", name: "important" }]; + const testMetadata = { source: "test" }; + const testEmbedding = [0.1, 0.2, 0.3]; + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: "folder-1", + content: "Test content", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + embedding_dimensions: 3, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }; + + mockClient._mocks.single.mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + await store.create({ + content: "Test content", + projectId: "project-1", + folderId: "folder-1", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + }); + expect(mockClient._mocks.insert).toHaveBeenCalledWith({ + user_id: testUserId, + project_id: "project-1", + folder_id: "folder-1", + content: "Test content", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + embedding_dimensions: 3, + }); + }); + it("uses custom embedding dimensions when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Test content", + tags: [], + metadata: {}, + embedding: testEmbedding, + embedding_dimensions: 768, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }; + + mockClient._mocks.single.mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + await store.create({ + content: "Test content", + projectId: "project-1", + embedding: testEmbedding, + embeddingDimensions: 768, + }); + expect(mockClient._mocks.insert).toHaveBeenCalledWith({ + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Test content", + tags: [], + metadata: {}, + embedding: testEmbedding, + embedding_dimensions: 768, + }); + }); + it("returns the created memory with correct field mapping", async () => { + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: "folder-1", + content: "Test content", + tags: [{ id: "tag-1", name: "important" }], + metadata: { source: "test" }, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-02T00:00:00Z", + }; + + mockClient._mocks.single.mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + + const result = await store.create({ + content: "Test content", + projectId: "project-1", + }); + + expect(result.id).toBe("memory-1"); + expect(result.content).toBe("Test content"); + expect(result.projectId).toBe("project-1"); + expect(result.folderId).toBe("folder-1"); + expect(result.tags).toEqual([{ id: "tag-1", name: "important" }]); + expect(result.metadata).toEqual({ source: "test" }); + expect(result.createdAt).toBeInstanceOf(Date); + expect(result.updatedAt).toBeInstanceOf(Date); + }); + it("throws error when insert fails", async () => { + mockClient._mocks.single.mockResolvedValue({ + data: null, + error: { message: "Database error" }, + }); + await expect( + store.create({ + content: "Test content", + projectId: "project-1", + }), + ).rejects.toThrow("Failed to create memory: Database error"); + }); + }); + describe("read", () => { + it("queries by id and user_id", async () => { + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Test content", + tags: [], + metadata: {}, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }; + const mockSingleResult = vi.fn().mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + const mockSelectResult = vi.fn().mockReturnValue({ + single: mockSingleResult, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + single: mockSingleResult, + select: mockSelectResult, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + + const result = await store.read("memory-1"); + + expect(mockClient.from).toHaveBeenCalledWith("memories"); + expect(mockSelect).toHaveBeenCalled(); + expect(mockEqId).toHaveBeenCalledWith("id", "memory-1"); + expect(mockEqUserId).toHaveBeenCalledWith("user_id", testUserId); + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.id).toBe("memory-1"); + } + }); + it("returns failure when memory not found", async () => { + const mockSingleResult = vi.fn().mockResolvedValue({ + data: null, + error: { message: "Not found" }, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + single: mockSingleResult, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + + const result = await store.read("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + }); + describe("update", () => { + it("builds correct update query with content", async () => { + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Updated content", + tags: [], + metadata: {}, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-02T00:00:00Z", + }; + const mockSingleResult = vi.fn().mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + const mockSelectResult = vi.fn().mockReturnValue({ + single: mockSingleResult, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + select: mockSelectResult, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockUpdate = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + update: mockUpdate, + }); + await store.update("memory-1", { + content: "Updated content", + }); + expect(mockClient.from).toHaveBeenCalledWith("memories"); + expect(mockUpdate).toHaveBeenCalledWith({ content: "Updated content" }); + expect(mockEqId).toHaveBeenCalledWith("id", "memory-1"); + expect(mockEqUserId).toHaveBeenCalledWith("user_id", testUserId); + }); + it("builds correct update query with all fields", async () => { + const testTags: Tag[] = [{ id: "tag-1", name: "updated" }]; + const testMetadata = { updated: true }; + const testEmbedding = [0.4, 0.5, 0.6]; + const mockMemoryRow = { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: "folder-2", + content: "Updated content", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + embedding_dimensions: 3, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-02T00:00:00Z", + }; + const mockSingleResult = vi.fn().mockResolvedValue({ + data: mockMemoryRow, + error: null, + }); + const mockSelectResult = vi.fn().mockReturnValue({ + single: mockSingleResult, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + select: mockSelectResult, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockUpdate = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + update: mockUpdate, + }); + await store.update("memory-1", { + content: "Updated content", + folderId: "folder-2", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + embeddingDimensions: 768, + }); + expect(mockUpdate).toHaveBeenCalledWith({ + content: "Updated content", + folder_id: "folder-2", + tags: testTags, + metadata: testMetadata, + embedding: testEmbedding, + embedding_dimensions: 768, + }); + }); + it("returns failure when memory not found", async () => { + const mockSingleResult = vi.fn().mockResolvedValue({ + data: null, + error: { message: "Not found" }, + }); + const mockSelectResult = vi.fn().mockReturnValue({ + single: mockSingleResult, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + select: mockSelectResult, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockUpdate = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + update: mockUpdate, + }); + + const result = await store.update("non-existent-id", { + content: "Updated content", + }); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + }); + describe("delete", () => { + it("builds correct delete query", async () => { + const mockEqUserId = vi.fn().mockResolvedValue({ + error: null, + count: 1, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockDelete = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + delete: mockDelete, + }); + + const result = await store.delete("memory-1"); + + expect(mockClient.from).toHaveBeenCalledWith("memories"); + expect(mockDelete).toHaveBeenCalledWith({ count: "exact" }); + expect(mockEqId).toHaveBeenCalledWith("id", "memory-1"); + expect(mockEqUserId).toHaveBeenCalledWith("user_id", testUserId); + expect(result.success).toBe(true); + }); + it("returns failure when memory not found", async () => { + const mockEqUserId = vi.fn().mockResolvedValue({ + error: null, + count: 0, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockDelete = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + delete: mockDelete, + }); + + const result = await store.delete("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + it("returns failure when delete encounters error", async () => { + const mockEqUserId = vi.fn().mockResolvedValue({ + error: { message: "Database error" }, + count: null, + }); + const mockEqId = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + const mockDelete = vi.fn().mockReturnValue({ + eq: mockEqId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + delete: mockDelete, + }); + + const result = await store.delete("memory-1"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + } + }); + }); + describe("list", () => { + it("queries with user_id filter only when no filter provided", async () => { + const mockQueryResult = Promise.resolve({ data: [], error: null }); + const mockEqUserId = vi.fn().mockReturnValue(mockQueryResult); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await store.list(); + expect(mockClient.from).toHaveBeenCalledWith("memories"); + expect(mockSelect).toHaveBeenCalled(); + expect(mockEqUserId).toHaveBeenCalledWith("user_id", testUserId); + }); + it("adds projectId filter when provided", async () => { + const mockQueryResult = Promise.resolve({ data: [], error: null }); + const mockEqProjectId = vi.fn().mockReturnValue(mockQueryResult); + const mockEqUserId = vi.fn().mockReturnValue({ + eq: mockEqProjectId, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await store.list({ projectId: "project-1" }); + expect(mockEqProjectId).toHaveBeenCalledWith("project_id", "project-1"); + }); + it("adds folderId filter when provided", async () => { + const mockQueryResult = Promise.resolve({ data: [], error: null }); + const mockEqFolderId = vi.fn().mockReturnValue(mockQueryResult); + const mockEqUserId = vi.fn().mockReturnValue({ + eq: mockEqFolderId, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await store.list({ folderId: "folder-1" }); + expect(mockEqFolderId).toHaveBeenCalledWith("folder_id", "folder-1"); + }); + it("adds tags filter with contains when provided", async () => { + const mockQueryResult = Promise.resolve({ data: [], error: null }); + const mockContains = vi.fn().mockReturnValue(mockQueryResult); + const mockEqUserId = vi.fn().mockReturnValue({ + contains: mockContains, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await store.list({ tags: ["tag-1", "tag-2"] }); + expect(mockContains).toHaveBeenCalledWith("tags", [ + { id: "tag-1" }, + { id: "tag-2" }, + ]); + }); + it("applies multiple filters together", async () => { + const mockQueryResult = Promise.resolve({ data: [], error: null }); + const mockContains = vi.fn().mockReturnValue(mockQueryResult); + const mockEqFolderId = vi.fn().mockReturnValue({ + contains: mockContains, + }); + const mockEqProjectId = vi.fn().mockReturnValue({ + eq: mockEqFolderId, + }); + const mockEqUserId = vi.fn().mockReturnValue({ + eq: mockEqProjectId, + }); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await store.list({ + projectId: "project-1", + folderId: "folder-1", + tags: ["tag-1"], + }); + expect(mockEqProjectId).toHaveBeenCalledWith("project_id", "project-1"); + expect(mockEqFolderId).toHaveBeenCalledWith("folder_id", "folder-1"); + expect(mockContains).toHaveBeenCalledWith("tags", [{ id: "tag-1" }]); + }); + it("returns mapped memories from query result", async () => { + const mockMemoryRows = [ + { + id: "memory-1", + user_id: testUserId, + project_id: "project-1", + folder_id: null, + content: "Content 1", + tags: [], + metadata: {}, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }, + { + id: "memory-2", + user_id: testUserId, + project_id: "project-1", + folder_id: "folder-1", + content: "Content 2", + tags: [{ id: "tag-1", name: "important" }], + metadata: { source: "test" }, + embedding: null, + embedding_dimensions: null, + created_at: "2024-01-02T00:00:00Z", + updated_at: "2024-01-02T00:00:00Z", + }, + ]; + const mockQueryResult = Promise.resolve({ + data: mockMemoryRows, + error: null, + }); + const mockEqUserId = vi.fn().mockReturnValue(mockQueryResult); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + + const result = await store.list(); + + expect(result).toHaveLength(2); + expect(result[0]?.id).toBe("memory-1"); + expect(result[0]?.projectId).toBe("project-1"); + expect(result[1]?.id).toBe("memory-2"); + expect(result[1]?.folderId).toBe("folder-1"); + expect(result[1]?.tags).toEqual([{ id: "tag-1", name: "important" }]); + }); + it("throws error when list fails", async () => { + const mockQueryResult = Promise.resolve({ + data: null, + error: { message: "Database error" }, + }); + const mockEqUserId = vi.fn().mockReturnValue(mockQueryResult); + const mockSelect = vi.fn().mockReturnValue({ + eq: mockEqUserId, + }); + + mockClient.from = vi.fn().mockReturnValue({ + select: mockSelect, + }); + await expect(store.list()).rejects.toThrow( + "Failed to list memories: Database error", + ); + }); + }); + describe("search", () => { + it("calls rpc with correct parameters", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.7, + match_count: 10, + filter_project_id: null, + filter_folder_id: null, + }); + }); + it("passes custom threshold when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding, { threshold: 0.8 }); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.8, + match_count: 10, + filter_project_id: null, + filter_folder_id: null, + }); + }); + it("passes custom limit when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding, { limit: 5 }); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.7, + match_count: 5, + filter_project_id: null, + filter_folder_id: null, + }); + }); + it("passes projectId filter when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding, { projectId: "project-1" }); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.7, + match_count: 10, + filter_project_id: "project-1", + filter_folder_id: null, + }); + }); + it("passes folderId filter when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding, { folderId: "folder-1" }); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.7, + match_count: 10, + filter_project_id: null, + filter_folder_id: "folder-1", + }); + }); + it("passes all options when provided", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: [], + error: null, + }); + await store.search(testEmbedding, { + threshold: 0.9, + limit: 20, + projectId: "project-1", + folderId: "folder-1", + }); + expect(mockClient.rpc).toHaveBeenCalledWith("search_memories", { + query_embedding: testEmbedding, + match_threshold: 0.9, + match_count: 20, + filter_project_id: "project-1", + filter_folder_id: "folder-1", + }); + }); + it("returns mapped search results", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + const mockSearchResultRows = [ + { + id: "memory-1", + content: "Test content 1", + project_id: "project-1", + folder_id: null, + tags: [], + metadata: {}, + similarity: 0.95, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + }, + { + id: "memory-2", + content: "Test content 2", + project_id: "project-1", + folder_id: "folder-1", + tags: [{ id: "tag-1", name: "important" }], + metadata: { source: "test" }, + similarity: 0.85, + created_at: "2024-01-02T00:00:00Z", + updated_at: "2024-01-02T00:00:00Z", + }, + ]; + + mockClient.rpc.mockResolvedValue({ + data: mockSearchResultRows, + error: null, + }); + + const result = await store.search(testEmbedding); + + expect(result).toHaveLength(2); + expect(result[0]?.id).toBe("memory-1"); + expect(result[0]?.content).toBe("Test content 1"); + expect(result[0]?.similarity).toBe(0.95); + expect(result[0]?.projectId).toBe("project-1"); + expect(result[0]?.folderId).toBeNull(); + expect(result[0]?.createdAt).toBeInstanceOf(Date); + expect(result[1]?.id).toBe("memory-2"); + expect(result[1]?.similarity).toBe(0.85); + expect(result[1]?.folderId).toBe("folder-1"); + expect(result[1]?.tags).toEqual([{ id: "tag-1", name: "important" }]); + }); + it("throws error when search fails", async () => { + const testEmbedding = [0.1, 0.2, 0.3]; + + mockClient.rpc.mockResolvedValue({ + data: null, + error: { message: "RPC error" }, + }); + await expect(store.search(testEmbedding)).rejects.toThrow( + "Failed to search memories: RPC error", + ); + }); + }); +}); |