Skip to main content
Glama
notebook.test.ts8.91 kB
import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { EphemeralNotebookStore } from "../src/notebook/EphemeralNotebook.js"; import { getPresetForPattern, NOTEBOOK_PRESETS, } from "../src/notebook/presets.js"; describe("EphemeralNotebook", () => { let store: EphemeralNotebookStore; beforeEach(() => { store = new EphemeralNotebookStore({ defaultTimeoutMs: 1000, maxCells: 10, }); }); afterEach(() => { store.cleanup(); }); describe("Notebook Management", () => { it("should create a notebook for a session", () => { const notebook = store.createNotebook("test-session"); expect(notebook).toBeDefined(); expect(notebook.sessionId).toBe("test-session"); expect(notebook.cells).toHaveLength(0); }); it("should return existing notebook for same session", () => { const notebook1 = store.createNotebook("test-session"); const notebook2 = store.createNotebook("test-session"); expect(notebook1.id).toBe(notebook2.id); }); it("should retrieve notebook by ID", () => { const notebook = store.createNotebook("test-session"); const retrieved = store.getNotebook(notebook.id); expect(retrieved).toBeDefined(); expect(retrieved?.id).toBe(notebook.id); }); it("should delete a notebook", () => { const notebook = store.createNotebook("test-session"); const deleted = store.deleteNotebook(notebook.id); expect(deleted).toBe(true); expect(store.getNotebook(notebook.id)).toBeUndefined(); }); }); describe("Cell Operations", () => { it("should add a markdown cell", () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell(notebook.id, "markdown", "# Test Heading"); expect(cell).toBeDefined(); expect(cell?.type).toBe("markdown"); expect(cell?.source).toBe("# Test Heading"); }); it("should add a code cell", () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell( notebook.id, "code", 'console.log("test");', "javascript", ); expect(cell).toBeDefined(); expect(cell?.type).toBe("code"); expect(cell?.language).toBe("javascript"); expect(cell?.status).toBe("idle"); }); it("should update a cell", () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell(notebook.id, "code", 'console.log("old");'); const updated = store.updateCell(notebook.id, cell?.id, { source: 'console.log("new");', }); expect(updated?.source).toBe('console.log("new");'); }); it("should delete a cell", () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell(notebook.id, "code", 'console.log("test");'); const deleted = store.deleteCell(notebook.id, cell?.id); expect(deleted).toBe(true); const updatedNotebook = store.getNotebook(notebook.id); expect(updatedNotebook?.cells).toHaveLength(0); }); it("should respect max cells limit", () => { const notebook = store.createNotebook("test-session"); // Add cells up to the limit for (let i = 0; i < 10; i++) { store.addCell(notebook.id, "code", `console.log(${i});`); } // Should throw when exceeding limit expect(() => { store.addCell(notebook.id, "code", 'console.log("overflow");'); }).toThrow("Maximum number of cells"); }); }); describe("Code Execution", () => { it("should execute simple JavaScript code", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell( notebook.id, "code", 'console.log("Hello, World!");', ); const execution = await store.executeCell(notebook.id, cell?.id); expect(execution.status).toBe("complete"); expect(execution.outputs).toHaveLength(1); expect(execution.outputs[0].type).toBe("stdout"); expect(execution.outputs[0].data).toBe("Hello, World!"); }); it("should capture return values", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell(notebook.id, "code", "2 + 2"); const execution = await store.executeCell(notebook.id, cell?.id); expect(execution.status).toBe("complete"); expect(execution.outputs).toContainEqual({ type: "result", data: "4", }); }); it("should handle errors gracefully", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell( notebook.id, "code", 'throw new Error("Test error");', ); const execution = await store.executeCell(notebook.id, cell?.id); expect(execution.status).toBe("failed"); expect(execution.error).toContain("Test error"); }); it("should respect timeout", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell(notebook.id, "code", "while(true) {}"); const execution = await store.executeCell(notebook.id, cell?.id, 100); expect(execution.status).toBe("failed"); expect(execution.error).toContain("timed out"); }); it("should handle console.error", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell( notebook.id, "code", 'console.error("Error message");', ); const execution = await store.executeCell(notebook.id, cell?.id); expect(execution.outputs).toContainEqual({ type: "stderr", data: "Error message", }); }); }); describe("Export Functionality", () => { it("should export to srcmd format", () => { const notebook = store.createNotebook("test-session"); store.addCell(notebook.id, "markdown", "# Test Notebook"); store.addCell(notebook.id, "code", "const x = 42;"); const srcmd = store.exportToSrcMd(notebook.id); expect(srcmd).toContain("# Test Notebook"); expect(srcmd).toContain("```javascript"); expect(srcmd).toContain("const x = 42;"); }); it("should export to JSON format", () => { const notebook = store.createNotebook("test-session"); store.addCell(notebook.id, "markdown", "# Test"); const json = store.exportToJson(notebook.id); expect(json).toBeDefined(); expect((json as any).sessionId).toBe("test-session"); expect((json as any).cells).toHaveLength(1); }); it("should include outputs in srcmd export", async () => { const notebook = store.createNotebook("test-session"); const cell = store.addCell( notebook.id, "code", 'console.log("Output test");', ); await store.executeCell(notebook.id, cell?.id); const srcmd = store.exportToSrcMd(notebook.id); expect(srcmd).toContain("**Output:**"); expect(srcmd).toContain("Output test"); }); }); }); describe("Notebook Presets", () => { it("should have presets for all supported patterns", () => { const patterns = [ "tree_of_thought", "beam_search", "mcts", "graph_of_thought", "orchestration_suggest", ]; for (const pattern of patterns) { const preset = getPresetForPattern(pattern); expect(preset).toBeDefined(); expect(preset?.cells.length).toBeGreaterThan(0); } }); it("should return undefined for unknown pattern", () => { const preset = getPresetForPattern("unknown_pattern"); expect(preset).toBeUndefined(); }); it("tree_of_thought preset should have TreeNode implementation", () => { const preset = NOTEBOOK_PRESETS.tree_of_thought; const codeCell = preset.cells.find((c) => c.type === "code"); expect(codeCell?.source).toContain("class TreeNode"); expect(codeCell?.source).toContain("class TreeOfThought"); }); it("beam_search preset should have BeamSearchPath implementation", () => { const preset = NOTEBOOK_PRESETS.beam_search; const codeCell = preset.cells.find((c) => c.type === "code"); expect(codeCell?.source).toContain("class BeamSearchPath"); expect(codeCell?.source).toContain("class BeamSearch"); }); it("mcts preset should have MCTSNode implementation", () => { const preset = NOTEBOOK_PRESETS.mcts; const codeCell = preset.cells.find((c) => c.type === "code"); expect(codeCell?.source).toContain("class MCTSNode"); expect(codeCell?.source).toContain("ucb1"); expect(codeCell?.source).toContain("backpropagate"); }); it("graph_of_thought preset should have GraphNode implementation", () => { const preset = NOTEBOOK_PRESETS.graph_of_thought; const codeCell = preset.cells.find((c) => c.type === "code"); expect(codeCell?.source).toContain("class GraphNode"); expect(codeCell?.source).toContain("class GraphEdge"); expect(codeCell?.source).toContain("class GraphOfThought"); }); it("orchestration_suggest preset should have TaskOrchestrator", () => { const preset = NOTEBOOK_PRESETS.orchestration_suggest; const codeCell = preset.cells.find((c) => c.type === "code"); expect(codeCell?.source).toContain("class TaskOrchestrator"); expect(codeCell?.source).toContain("decomposeTask"); expect(codeCell?.source).toContain("suggestTools"); }); });

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/waldzellai/clearthought-onepointfive'

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