Skip to main content
Glama
data.test.ts10.6 kB
import { HeptabaseMcpServer } from '@/server'; import { HeptabaseDataService } from '@/services/HeptabaseDataService'; import { Whiteboard, Card, CardInstance, Connection } from '@/types/heptabase'; import { z } from 'zod'; jest.mock('@/services/HeptabaseDataService'); describe('Data Retrieval Tools', () => { let server: HeptabaseMcpServer; let mockDataService: jest.Mocked<HeptabaseDataService>; const mockWhiteboard: Whiteboard = { id: 'wb1', name: 'Test Whiteboard', createdBy: 'user1', createdTime: '2024-01-01T00:00:00Z', lastEditedTime: '2024-01-02T00:00:00Z', spaceId: 'space1', isTrashed: false }; const mockCard: Card = { id: 'card1', title: 'Test Card', content: '{"text": "Test content"}', createdBy: 'user1', createdTime: '2024-01-01T00:00:00Z', lastEditedTime: '2024-01-02T00:00:00Z', spaceId: 'space1', isTrashed: false }; const mockCardInstance: CardInstance = { id: 'instance1', cardId: 'card1', whiteboardId: 'wb1', x: 100, y: 200, width: 300, height: 150, color: '#FFFFFF', createdBy: 'user1', createdTime: '2024-01-01T00:00:00Z', lastEditedTime: '2024-01-02T00:00:00Z', spaceId: 'space1' }; const mockConnection: Connection = { id: 'conn1', whiteboardId: 'wb1', beginId: 'instance1', beginObjectType: 'card', endId: 'instance2', endObjectType: 'card', color: '#000000', lineStyle: 'solid', type: 'arrow', createdBy: 'user1', createdTime: '2024-01-01T00:00:00Z' }; beforeEach(() => { jest.clearAllMocks(); // Create mock data service mockDataService = { config: { dataPath: '/test/data', cacheEnabled: true, cacheTTL: 3600 }, loadData: jest.fn(), searchWhiteboards: jest.fn(), searchCards: jest.fn(), getWhiteboard: jest.fn(), getCard: jest.fn(), getCardsByArea: jest.fn(), getConnections: jest.fn(), getData: jest.fn() } as any; // Initialize server with mocked service server = new HeptabaseMcpServer(); server['dataService'] = mockDataService; }); describe('getWhiteboard tool', () => { it('should get whiteboard without cards', async () => { mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard }); const params = { whiteboardId: 'wb1' }; const result = await server.tools.getWhiteboard.handler(params); expect(mockDataService.getWhiteboard).toHaveBeenCalledWith('wb1', { includeCards: false, includeConnections: false }); expect(result.content[0].text).toContain('Test Whiteboard'); expect(result.content[0].text).toContain('wb1'); }); it('should get whiteboard with cards', async () => { mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard, cards: [mockCard] }); const params = { whiteboardId: 'wb1', includeCards: true }; const result = await server.tools.getWhiteboard.handler(params); expect(mockDataService.getWhiteboard).toHaveBeenCalledWith('wb1', { includeCards: true, includeConnections: false }); expect(result.content[0].text).toContain('Cards: 1'); expect(result.content[0].text).toContain('Test Card'); }); it('should get whiteboard with connections', async () => { mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard, connections: [mockConnection] }); const params = { whiteboardId: 'wb1', includeConnections: true }; const result = await server.tools.getWhiteboard.handler(params); expect(mockDataService.getWhiteboard).toHaveBeenCalledWith('wb1', { includeCards: false, includeConnections: true }); expect(result.content[0].text).toContain('Connections: 1'); }); it('should get whiteboard with depth parameter', async () => { mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard, cards: [mockCard], connections: [mockConnection] }); const params = { whiteboardId: 'wb1', includeCards: true, includeConnections: true, depth: 2 }; const result = await server.tools.getWhiteboard.handler(params); expect(mockDataService.getWhiteboard).toHaveBeenCalledWith('wb1', { includeCards: true, includeConnections: true, depth: 2 }); }); it('should handle error when data service not initialized', async () => { server['dataService'] = undefined; server['backupManager'] = undefined; await expect(server.tools.getWhiteboard.handler({ whiteboardId: 'wb1' })) .rejects.toThrow('Backup manager not initialized'); }); }); describe('getCard tool', () => { it('should get card with default JSON format', async () => { mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [mockCardInstance] }); mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard }); const params = { cardId: 'card1' }; const result = await server.tools.getCard.handler(params); expect(mockDataService.getCard).toHaveBeenCalledWith('card1'); expect(result.content[0].text).toContain('Test Card'); expect(result.content[0].text).toContain('Instances: 1'); expect(result.content[0].text).toContain('Test Whiteboard'); }); it('should get card in markdown format', async () => { mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [mockCardInstance] }); const params = { cardId: 'card1', format: 'markdown' }; const result = await server.tools.getCard.handler(params); expect(result.content[0].text).toContain('# Test Card'); expect(result.content[0].text).toContain('Test content'); }); it('should get card in HTML format', async () => { mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [] }); const params = { cardId: 'card1', format: 'html' }; const result = await server.tools.getCard.handler(params); expect(result.content[0].text).toContain('<h1>Test Card</h1>'); expect(result.content[0].text).toContain('<p>Test content</p>'); }); it('should include related cards when requested', async () => { mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [mockCardInstance] }); mockDataService.getWhiteboard.mockResolvedValue({ whiteboard: mockWhiteboard }); mockDataService.getConnections.mockResolvedValue([mockConnection]); const params = { cardId: 'card1', includeRelated: true }; const result = await server.tools.getCard.handler(params); expect(mockDataService.getConnections).toHaveBeenCalledWith('card1'); expect(result.content[0].text).toContain('Related connections: 1'); }); }); describe('getCardsByArea tool', () => { it('should get cards within area', async () => { mockDataService.getCardsByArea.mockResolvedValue([mockCard]); mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [mockCardInstance] }); const params = { whiteboardId: 'wb1', x: 100, y: 200, radius: 50 }; const result = await server.tools.getCardsByArea.handler(params); expect(mockDataService.getCardsByArea).toHaveBeenCalledWith('wb1', 100, 200, 50); expect(result.content[0].text).toContain('Found 1 cards within radius 50'); expect(result.content[0].text).toContain('Test Card'); }); it('should use default radius when not specified', async () => { mockDataService.getCardsByArea.mockResolvedValue([]); const params = { whiteboardId: 'wb1', x: 100, y: 200 }; const result = await server.tools.getCardsByArea.handler(params); expect(mockDataService.getCardsByArea).toHaveBeenCalledWith('wb1', 100, 200, 100); expect(result.content[0].text).toContain('Found 0 cards within radius 100'); }); it('should show card positions', async () => { // Mock the data service to return card instances mockDataService.getCardsByArea.mockResolvedValue([mockCard]); mockDataService.getCard.mockResolvedValue({ card: mockCard, instances: [mockCardInstance] }); const params = { whiteboardId: 'wb1', x: 100, y: 200, radius: 50 }; const result = await server.tools.getCardsByArea.handler(params); expect(result.content[0].text).toContain('Position: (100, 200)'); }); }); describe('tool schemas', () => { it('should have valid getWhiteboard schema', () => { const schema = server.tools.getWhiteboard.inputSchema; expect(schema).toBeInstanceOf(z.ZodObject); const validInput = { whiteboardId: 'wb1', includeCards: true, includeConnections: true, depth: 2 }; expect(() => schema.parse(validInput)).not.toThrow(); }); it('should have valid getCard schema', () => { const schema = server.tools.getCard.inputSchema; expect(schema).toBeInstanceOf(z.ZodObject); const validInput = { cardId: 'card1', format: 'markdown', includeRelated: true }; expect(() => schema.parse(validInput)).not.toThrow(); }); it('should have valid getCardsByArea schema', () => { const schema = server.tools.getCardsByArea.inputSchema; expect(schema).toBeInstanceOf(z.ZodObject); const validInput = { whiteboardId: 'wb1', x: 100, y: 200, radius: 50 }; expect(() => schema.parse(validInput)).not.toThrow(); }); it('should validate format enum in getCard', () => { const schema = server.tools.getCard.inputSchema; expect(() => schema.parse({ cardId: 'card1', format: 'json' })).not.toThrow(); expect(() => schema.parse({ cardId: 'card1', format: 'markdown' })).not.toThrow(); expect(() => schema.parse({ cardId: 'card1', format: 'html' })).not.toThrow(); expect(() => schema.parse({ cardId: 'card1', format: 'invalid' })).toThrow(); }); }); });

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/LarryStanley/heptabase-mcp'

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