Skip to main content
Glama
store.test.ts10.3 kB
/** * Tests for storeMemory function helper logic * Tests the pure function patterns used in store.ts */ import { describe, expect, test } from "bun:test"; describe("storeMemory", () => { describe("ID generation", () => { function generateMemoryId(): string { const uuid = crypto.randomUUID().replace(/-/g, "").slice(0, 16); return `mem_${uuid}`; } function generateVectorId(): string { const uuid = crypto.randomUUID().replace(/-/g, "").slice(0, 16); return `vec_${uuid}`; } test("memory ID has correct prefix", () => { const id = generateMemoryId(); expect(id.startsWith("mem_")).toBe(true); }); test("memory ID has correct length", () => { const id = generateMemoryId(); // "mem_" (4) + 16 chars = 20 expect(id.length).toBe(20); }); test("vector ID has correct prefix", () => { const id = generateVectorId(); expect(id.startsWith("vec_")).toBe(true); }); test("vector ID has correct length", () => { const id = generateVectorId(); // "vec_" (4) + 16 chars = 20 expect(id.length).toBe(20); }); test("generated IDs are unique", () => { const ids = new Set<string>(); for (let i = 0; i < 100; i++) { ids.add(generateMemoryId()); } expect(ids.size).toBe(100); }); test("ID contains only alphanumeric after prefix", () => { const id = generateMemoryId(); const suffix = id.slice(4); expect(/^[a-f0-9]+$/.test(suffix)).toBe(true); }); }); describe("text embedding preparation", () => { function prepareTextForEmbedding(title: string, content: string): string { return `${title}\n\n${content}`; } test("combines title and content with double newline", () => { const result = prepareTextForEmbedding("My Title", "My content here"); expect(result).toBe("My Title\n\nMy content here"); }); test("handles empty title", () => { const result = prepareTextForEmbedding("", "Content only"); expect(result).toBe("\n\nContent only"); }); test("handles empty content", () => { const result = prepareTextForEmbedding("Title only", ""); expect(result).toBe("Title only\n\n"); }); test("handles multiline content", () => { const result = prepareTextForEmbedding("Title", "Line 1\nLine 2\nLine 3"); expect(result).toBe("Title\n\nLine 1\nLine 2\nLine 3"); }); test("handles special characters", () => { const result = prepareTextForEmbedding( "Title with 'quotes'", 'Content with "double quotes" and <tags>', ); expect(result).toContain("'quotes'"); expect(result).toContain('"double quotes"'); expect(result).toContain("<tags>"); }); test("handles unicode", () => { const result = prepareTextForEmbedding("日本語タイトル", "中文内容"); expect(result).toBe("日本語タイトル\n\n中文内容"); }); }); describe("vector payload creation", () => { interface VectorPayload { memoryId: string; type: string; title: string; tags: string[]; relatedFiles: string[]; importance: number; } function createVectorPayload( memoryId: string, type: string, title: string, tags: string[], relatedFiles: string[], importance: number, ): VectorPayload { return { memoryId, type, title, tags, relatedFiles, importance, }; } test("creates payload with all fields", () => { const payload = createVectorPayload( "mem_123", "decision", "Use TypeScript", ["typescript", "lang"], ["src/index.ts"], 0.8, ); expect(payload.memoryId).toBe("mem_123"); expect(payload.type).toBe("decision"); expect(payload.title).toBe("Use TypeScript"); expect(payload.tags).toEqual(["typescript", "lang"]); expect(payload.relatedFiles).toEqual(["src/index.ts"]); expect(payload.importance).toBe(0.8); }); test("handles empty arrays", () => { const payload = createVectorPayload( "mem_123", "note", "Simple note", [], [], 0.5, ); expect(payload.tags).toEqual([]); expect(payload.relatedFiles).toEqual([]); }); test("handles minimum importance", () => { const payload = createVectorPayload("mem_123", "note", "Low", [], [], 0); expect(payload.importance).toBe(0); }); test("handles maximum importance", () => { const payload = createVectorPayload("mem_123", "note", "High", [], [], 1); expect(payload.importance).toBe(1); }); }); describe("memory creation data", () => { interface MemoryInput { id: string; qdrantId: string; type: string; title: string; content: string; summary?: string; importance: number; tags: string[]; relatedFiles: string[]; gitCommit?: string; sourcePr?: string; experts: string[]; } function createMemoryData(input: { type: string; title: string; content: string; summary?: string; importance?: number; tags?: string[]; relatedFiles?: string[]; gitCommit?: string; sourcePr?: string; experts?: string[]; }): MemoryInput { const id = `mem_${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`; const qdrantId = `vec_${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`; return { id, qdrantId, type: input.type, title: input.title, content: input.content, summary: input.summary, importance: input.importance ?? 0.5, tags: input.tags ?? [], relatedFiles: input.relatedFiles ?? [], gitCommit: input.gitCommit, sourcePr: input.sourcePr, experts: input.experts ?? [], }; } test("creates memory with required fields", () => { const data = createMemoryData({ type: "decision", title: "Test", content: "Content", }); expect(data.type).toBe("decision"); expect(data.title).toBe("Test"); expect(data.content).toBe("Content"); }); test("applies default importance of 0.5", () => { const data = createMemoryData({ type: "note", title: "Test", content: "Content", }); expect(data.importance).toBe(0.5); }); test("applies empty arrays as defaults", () => { const data = createMemoryData({ type: "note", title: "Test", content: "Content", }); expect(data.tags).toEqual([]); expect(data.relatedFiles).toEqual([]); expect(data.experts).toEqual([]); }); test("preserves optional fields when provided", () => { const data = createMemoryData({ type: "solution", title: "Test", content: "Content", summary: "Brief summary", gitCommit: "abc123", sourcePr: "#42", }); expect(data.summary).toBe("Brief summary"); expect(data.gitCommit).toBe("abc123"); expect(data.sourcePr).toBe("#42"); }); test("generates unique IDs each call", () => { const data1 = createMemoryData({ type: "note", title: "A", content: "A", }); const data2 = createMemoryData({ type: "note", title: "B", content: "B", }); expect(data1.id).not.toBe(data2.id); expect(data1.qdrantId).not.toBe(data2.qdrantId); }); }); describe("input validation patterns", () => { const VALID_TYPES = [ "decision", "solution", "pattern", "architecture", "note", ]; function isValidType(type: string): boolean { return VALID_TYPES.includes(type); } function isValidImportance(importance: number): boolean { return importance >= 0 && importance <= 1; } function isValidTitle(title: string): boolean { return title.length > 0; } test("validates decision type", () => { expect(isValidType("decision")).toBe(true); }); test("validates solution type", () => { expect(isValidType("solution")).toBe(true); }); test("validates pattern type", () => { expect(isValidType("pattern")).toBe(true); }); test("validates architecture type", () => { expect(isValidType("architecture")).toBe(true); }); test("validates note type", () => { expect(isValidType("note")).toBe(true); }); test("rejects invalid type", () => { expect(isValidType("invalid")).toBe(false); expect(isValidType("")).toBe(false); expect(isValidType("DECISION")).toBe(false); }); test("validates importance at boundaries", () => { expect(isValidImportance(0)).toBe(true); expect(isValidImportance(0.5)).toBe(true); expect(isValidImportance(1)).toBe(true); }); test("rejects out of range importance", () => { expect(isValidImportance(-0.1)).toBe(false); expect(isValidImportance(1.1)).toBe(false); expect(isValidImportance(-1)).toBe(false); expect(isValidImportance(2)).toBe(false); }); test("validates non-empty title", () => { expect(isValidTitle("A")).toBe(true); expect(isValidTitle("Long title here")).toBe(true); }); test("rejects empty title", () => { expect(isValidTitle("")).toBe(false); }); }); describe("tags normalization", () => { function normalizeTags(tags: string[]): string[] { return tags .map((tag) => tag.trim().toLowerCase()) .filter((tag) => tag.length > 0); } test("lowercases tags", () => { expect(normalizeTags(["TypeScript", "REACT"])).toEqual([ "typescript", "react", ]); }); test("trims whitespace", () => { expect(normalizeTags([" tag1 ", "tag2 "])).toEqual(["tag1", "tag2"]); }); test("filters empty tags", () => { expect(normalizeTags(["tag1", "", " ", "tag2"])).toEqual([ "tag1", "tag2", ]); }); test("handles empty array", () => { expect(normalizeTags([])).toEqual([]); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/docleaai/doclea-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server