Skip to main content
Glama
n-r-w

KnowledgeGraph MCP Server

by n-r-w
base-strategy.test.ts6.32 kB
import { Entity } from '../../core.js'; import { SearchConfig } from '../../search/types.js'; import { BaseSearchStrategy } from '../../search/strategies/base-strategy.js'; // Skip global test setup for search strategy tests jest.mock('../setup.ts', () => ({ beforeEach: jest.fn(), afterEach: jest.fn() })); // Concrete implementation for testing the abstract base class class TestSearchStrategy extends BaseSearchStrategy { constructor(config: SearchConfig) { super(config); } canUseDatabase(): boolean { return false; } async searchDatabase(query: string, threshold: number, project?: string): Promise<Entity[]> { throw new Error('Not implemented in test strategy'); } searchClientSide(entities: Entity[], query: string): Entity[] { // Simple implementation for testing return entities.filter(e => e.name.toLowerCase().includes(query.toLowerCase())); } async getAllEntities(project?: string): Promise<Entity[]> { // Simple implementation for testing return []; } } describe('BaseSearchStrategy', () => { let strategy: TestSearchStrategy; let config: SearchConfig; let testEntities: Entity[]; beforeEach(() => { config = { useDatabaseSearch: false, threshold: 0.3, clientSideFallback: true }; strategy = new TestSearchStrategy(config); testEntities = [ { name: 'JavaScript', entityType: 'Language', observations: ['Popular programming language', 'Used for web development'], tags: ['programming', 'web', 'frontend'] }, { name: 'TypeScript', entityType: 'Language', observations: ['Superset of JavaScript', 'Adds static typing'], tags: ['programming', 'web', 'typed'] }, { name: 'React', entityType: 'Framework', observations: ['UI library for JavaScript', 'Component-based'], tags: ['frontend', 'ui', 'javascript'] }, { name: 'Node.js', entityType: 'Runtime', observations: ['JavaScript runtime for server-side'], tags: ['backend', 'javascript', 'server'] } ]; }); describe('Constructor', () => { test('should initialize with provided config', () => { expect(strategy).toBeDefined(); expect(strategy['config']).toEqual(config); }); test('should accept different config options', () => { const customConfig: SearchConfig = { useDatabaseSearch: true, threshold: 0.5, clientSideFallback: false, fuseOptions: { threshold: 0.4, distance: 200, includeScore: true, keys: ['name', 'entityType'] } }; const customStrategy = new TestSearchStrategy(customConfig); expect(customStrategy['config']).toEqual(customConfig); }); }); describe('exactSearch', () => { test('should find entities by name (case insensitive)', () => { const results = strategy['exactSearch']('javascript', testEntities); // Should find JavaScript directly, plus React and Node.js which contain "javascript" in tags/observations expect(results.length).toBeGreaterThanOrEqual(1); expect(results.map(r => r.name)).toContain('JavaScript'); }); test('should find entities by entity type', () => { const results = strategy['exactSearch']('language', testEntities); expect(results).toHaveLength(2); expect(results.map(r => r.name)).toContain('JavaScript'); expect(results.map(r => r.name)).toContain('TypeScript'); }); test('should find entities by observations', () => { const results = strategy['exactSearch']('web development', testEntities); expect(results).toHaveLength(1); expect(results[0].name).toBe('JavaScript'); }); test('should find entities by tags', () => { const results = strategy['exactSearch']('frontend', testEntities); expect(results).toHaveLength(2); expect(results.map(r => r.name)).toContain('JavaScript'); expect(results.map(r => r.name)).toContain('React'); }); test('should handle partial matches', () => { const results = strategy['exactSearch']('script', testEntities); // Should find JavaScript, TypeScript, plus React and Node.js which contain "javascript" in tags/observations expect(results.length).toBeGreaterThanOrEqual(2); expect(results.map(r => r.name)).toContain('JavaScript'); expect(results.map(r => r.name)).toContain('TypeScript'); }); test('should return empty array for no matches', () => { const results = strategy['exactSearch']('python', testEntities); expect(results).toHaveLength(0); }); test('should handle empty query', () => { const results = strategy['exactSearch']('', testEntities); expect(results).toHaveLength(4); // All entities match empty string }); test('should handle entities with missing tags', () => { const entitiesWithoutTags: Entity[] = [ { name: 'Test Entity', entityType: 'Test', observations: ['test observation'], tags: [] } ]; const results = strategy['exactSearch']('test', entitiesWithoutTags); expect(results).toHaveLength(1); }); test('should handle entities with undefined tags', () => { const entitiesWithUndefinedTags: Entity[] = [ { name: 'Test Entity', entityType: 'Test', observations: ['test observation'], tags: undefined as any } ]; const results = strategy['exactSearch']('test', entitiesWithUndefinedTags); expect(results).toHaveLength(1); }); }); describe('Abstract Methods', () => { test('should require implementation of canUseDatabase', () => { expect(strategy.canUseDatabase()).toBe(false); }); test('should require implementation of searchDatabase', async () => { await expect(strategy.searchDatabase('test', 0.3)).rejects.toThrow('Not implemented in test strategy'); }); test('should require implementation of searchClientSide', () => { const results = strategy.searchClientSide(testEntities, 'JavaScript'); expect(results).toHaveLength(1); expect(results[0].name).toBe('JavaScript'); }); }); });

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/n-r-w/knowledgegraph-mcp'

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