Skip to main content
Glama
client.test.ts12.5 kB
import { describe, test, expect } from "vitest"; import { Context7 } from "./client"; import { Context7Error } from "@error"; import type { CodeDocsResponse, InfoDocsResponse } from "@commands/types"; describe("Context7 Client", () => { const apiKey = process.env.CONTEXT7_API_KEY || process.env.API_KEY!; describe("constructor", () => { test("should create client with API key", () => { const client = new Context7({ apiKey }); expect(client).toBeDefined(); }); test("should create client from environment variables", () => { const client = new Context7(); expect(client).toBeDefined(); }); test("should throw error when API key is missing", () => { const originalEnv = process.env.CONTEXT7_API_KEY; const originalApiKey = process.env.API_KEY; delete process.env.CONTEXT7_API_KEY; delete process.env.API_KEY; expect(() => new Context7({ apiKey: "" })).toThrow(Context7Error); expect(() => new Context7({})).toThrow(Context7Error); expect(() => new Context7()).toThrow("API key is required"); if (originalEnv) process.env.CONTEXT7_API_KEY = originalEnv; if (originalApiKey) process.env.API_KEY = originalApiKey; }); test("should prefer config API key over environment variable", () => { const customApiKey = "ctx7sk-custom-key"; const client = new Context7({ apiKey: customApiKey }); expect(client).toBeDefined(); }); }); describe("searchLibrary", () => { const client = new Context7({ apiKey }); test("should search for libraries", async () => { const result = await client.searchLibrary("react"); expect(result).toBeDefined(); expect(result.results).toBeDefined(); expect(Array.isArray(result.results)).toBe(true); expect(result.results.length).toBeGreaterThan(0); expect(result.metadata).toBeDefined(); expect(result.metadata.authentication).toBeDefined(); }); test("should return results with correct structure", async () => { const result = await client.searchLibrary("typescript"); expect(result.results.length).toBeGreaterThan(0); const firstResult = result.results[0]; expect(firstResult).toHaveProperty("id"); expect(firstResult).toHaveProperty("title"); expect(firstResult).toHaveProperty("description"); expect(firstResult).toHaveProperty("branch"); expect(firstResult).toHaveProperty("lastUpdateDate"); expect(firstResult).toHaveProperty("state"); expect(firstResult).toHaveProperty("totalTokens"); expect(firstResult).toHaveProperty("totalSnippets"); }); test("should search with different queries", async () => { const queries = ["vue", "express", "next"]; for (const query of queries) { const result = await client.searchLibrary(query); expect(result.results.length).toBeGreaterThan(0); } }); }); describe("getDocs - text format", () => { const client = new Context7({ apiKey }); test("should get code docs as text with pagination and totalTokens", async () => { const result = await client.getDocs("/facebook/react", { mode: "code", format: "txt", limit: 5, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); expect(typeof result.content).toBe("string"); expect(result.content.length).toBeGreaterThan(0); expect(typeof result.totalTokens).toBe("number"); }); test("should get info docs as text with pagination and totalTokens", async () => { const result = await client.getDocs("/facebook/react", { mode: "info", format: "txt", limit: 5, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); expect(typeof result.content).toBe("string"); expect(result.content.length).toBeGreaterThan(0); expect(typeof result.totalTokens).toBe("number"); }); test("should get docs with default format (json)", async () => { const result = await client.getDocs("/facebook/react", { mode: "code", limit: 5, }); expect(result).toBeDefined(); expect(typeof result).toBe("object"); expect(result).toHaveProperty("snippets"); }); test("should get docs with pagination metadata", async () => { const page1 = await client.getDocs("/facebook/react", { mode: "code", format: "txt", page: 1, limit: 3, }); const page2 = await client.getDocs("/facebook/react", { mode: "code", format: "txt", page: 2, limit: 3, }); expect(page1).toBeDefined(); expect(page2).toBeDefined(); expect(page1).toHaveProperty("content"); expect(page1).toHaveProperty("pagination"); expect(page2).toHaveProperty("content"); expect(page2).toHaveProperty("pagination"); expect(page1.pagination.page).toBe(1); expect(page2.pagination.page).toBe(2); }); test("should get docs with topic filter", async () => { const result = await client.getDocs("/facebook/react", { mode: "code", format: "txt", topic: "hooks", limit: 5, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); }); }); describe("getDocs - JSON format", () => { const client = new Context7({ apiKey }); test("should get code docs as JSON", async () => { const result = await client.getDocs("/facebook/react", { mode: "code", format: "json", limit: 3, }); expect(result).toBeDefined(); expect(typeof result).toBe("object"); const codeResult = result as CodeDocsResponse; expect(codeResult.snippets).toBeDefined(); expect(Array.isArray(codeResult.snippets)).toBe(true); expect(codeResult.snippets.length).toBeGreaterThan(0); expect(codeResult.totalTokens).toBeDefined(); expect(typeof codeResult.totalTokens).toBe("number"); expect(codeResult.pagination).toBeDefined(); }); test("should get info docs as JSON", async () => { const result = await client.getDocs("/facebook/react", { mode: "info", format: "json", limit: 3, }); expect(result).toBeDefined(); expect(typeof result).toBe("object"); const infoResult = result as InfoDocsResponse; expect(infoResult.snippets).toBeDefined(); expect(Array.isArray(infoResult.snippets)).toBe(true); expect(infoResult.snippets.length).toBeGreaterThan(0); expect(infoResult.totalTokens).toBeDefined(); expect(typeof infoResult.totalTokens).toBe("number"); expect(infoResult.pagination).toBeDefined(); }); test("should have correct code snippet structure", async () => { const result = (await client.getDocs("/facebook/react", { mode: "code", format: "json", limit: 1, })) as CodeDocsResponse; const snippet = result.snippets[0]; expect(snippet).toHaveProperty("codeTitle"); expect(snippet).toHaveProperty("codeDescription"); expect(snippet).toHaveProperty("codeLanguage"); expect(snippet).toHaveProperty("codeTokens"); expect(snippet).toHaveProperty("codeId"); expect(snippet).toHaveProperty("pageTitle"); expect(snippet).toHaveProperty("codeList"); expect(Array.isArray(snippet.codeList)).toBe(true); }); test("should have correct info snippet structure", async () => { const result = (await client.getDocs("/facebook/react", { mode: "info", format: "json", limit: 1, })) as InfoDocsResponse; const snippet = result.snippets[0]; expect(snippet).toHaveProperty("content"); expect(snippet).toHaveProperty("contentTokens"); expect(typeof snippet.content).toBe("string"); expect(typeof snippet.contentTokens).toBe("number"); }); test("should have correct pagination structure", async () => { const result = (await client.getDocs("/facebook/react", { mode: "code", format: "json", page: 1, limit: 5, })) as CodeDocsResponse; expect(result.pagination).toBeDefined(); expect(result.pagination.page).toBe(1); expect(result.pagination.limit).toBe(5); expect(typeof result.pagination.totalPages).toBe("number"); expect(typeof result.pagination.hasNext).toBe("boolean"); expect(typeof result.pagination.hasPrev).toBe("boolean"); }); test("should respect limit parameter", async () => { const limit = 2; const result = (await client.getDocs("/facebook/react", { mode: "code", format: "json", limit, })) as CodeDocsResponse; expect(result.snippets.length).toBeLessThanOrEqual(limit); }); }); describe("getDocs - with version", () => { const client = new Context7({ apiKey }); test("should accept version parameter", async () => { const result = await client.getDocs("/facebook/react", { mode: "code", format: "txt", limit: 3, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); }); }); describe("getDocs - different libraries", () => { const client = new Context7({ apiKey }); test("should get docs for Vue", async () => { const result = await client.getDocs("/vuejs/core", { mode: "code", format: "txt", limit: 3, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); expect(result.content.length).toBeGreaterThan(0); }); test("should get docs for Express", async () => { const result = await client.getDocs("/expressjs/express", { mode: "code", format: "txt", limit: 3, }); expect(result).toBeDefined(); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); expect(result.content.length).toBeGreaterThan(0); }); }); describe("error handling", () => { const client = new Context7({ apiKey }); test("should handle invalid library ID gracefully", async () => { await expect( client.getDocs("/nonexistent/library", { mode: "code", format: "txt", limit: 1, }) ).rejects.toThrow(); }); test("should handle invalid search query", async () => { const result = await client.searchLibrary(""); expect(result).toBeDefined(); expect(result.results).toBeDefined(); expect(Array.isArray(result.results)).toBe(true); }); }); describe("type inference", () => { const client = new Context7({ apiKey }); test("should infer TextDocsResponse type for txt format", async () => { const result = await client.getDocs("/facebook/react", { format: "txt", limit: 1, }); expect(result).toHaveProperty("content"); expect(result).toHaveProperty("pagination"); expect(result).toHaveProperty("totalTokens"); expect(typeof result.content).toBe("string"); expect(typeof result.totalTokens).toBe("number"); }); test("should infer CodeDocsResponse for json format with code mode", async () => { const result = await client.getDocs("/facebook/react", { format: "json", mode: "code", limit: 1, }); expect(result).toHaveProperty("snippets"); expect((result as CodeDocsResponse).snippets).toBeDefined(); }); test("should infer InfoDocsResponse for json format with info mode", async () => { const result = await client.getDocs("/facebook/react", { format: "json", mode: "info", limit: 1, }); expect(result).toHaveProperty("snippets"); expect((result as InfoDocsResponse).snippets).toBeDefined(); }); }); });

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/upstash/context7-mcp'

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