Skip to main content
Glama
core-operations-search.test.tsβ€’10.8 kB
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; // Import shared helpers import { setupUnitTestMocks, cleanupMocks } from './helpers/index.js'; // Import tool configurations import { searchRecordsConfig, getRecordDetailsConfig, } from '../../../../src/handlers/tool-configs/universal/core/index.js'; // Import types import { UniversalResourceType, UniversalSearchParams, UniversalRecordDetailsParams, } from '../../../../src/handlers/tool-configs/universal/types.js'; import { resolveToolName } from '../../../../src/config/tool-aliases.js'; describe('Universal Core Operations Search Tests', () => { beforeEach(() => { setupUnitTestMocks(); }); afterEach(() => { cleanupMocks(); }); describe('records_search tool', () => { it('should search companies successfully', async () => { const mockResults: any[] = [ { id: { record_id: 'comp-1' }, values: { name: [{ value: 'Test Company' }], domains: [{ domain: 'test.com' }], }, }, ]; const { handleUniversalSearch } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalSearch).mockResolvedValue(mockResults); const params: UniversalSearchParams = { resource_type: UniversalResourceType.COMPANIES, query: 'test', }; const result = await searchRecordsConfig.handler(params); expect(result).toEqual(mockResults); expect(vi.mocked(handleUniversalSearch)).toHaveBeenCalledWith(params); }); it('should search people successfully', async () => { const mockResults: any[] = [ { id: { record_id: 'person-1' }, values: { name: [{ value: 'John Doe' }], email: [{ value: 'john@example.com' }], }, }, ]; const { handleUniversalSearch } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalSearch).mockResolvedValue(mockResults); const params: UniversalSearchParams = { resource_type: UniversalResourceType.PEOPLE, query: 'john', limit: 10, }; const result = await searchRecordsConfig.handler(params); expect(result).toEqual(mockResults); expect(vi.mocked(handleUniversalSearch)).toHaveBeenCalledWith(params); }); it('should handle search errors properly', async () => { const mockError = new Error('API error'); const { handleUniversalSearch } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalSearch).mockRejectedValue(mockError); const params: UniversalSearchParams = { resource_type: UniversalResourceType.COMPANIES, query: 'test', }; await expect(searchRecordsConfig.handler(params)).rejects.toSatisfy( (error: unknown) => { if (!error) return false; if ( typeof error === 'object' && 'name' in error && (error as { name?: unknown }).name === 'search_error' ) { const typed = error as { message?: string; details?: { context?: { operation?: string; resourceType?: string; recordData?: Record<string, unknown>; }; }; }; return ( typed.message === 'Failed to search companies: API error' && typed.details?.context?.operation === 'search' && typed.details?.context?.resourceType === 'companies' && typed.details?.context?.recordData?.resource_type === 'companies' && typed.details?.context?.recordData?.query === 'test' ); } if ( typeof error === 'object' && 'status' in error && 'body' in error ) { const typed = error as { status?: number; body?: { message?: string; type?: string }; }; return ( typeof typed.status === 'number' && typed.body?.message === 'Universal search failed for resource type companies: API error' && typed.body?.type === 'validation_error' ); } return false; } ); }); it('should format search results correctly', () => { const mockResults = [ { id: { record_id: 'comp-1' }, values: { name: [{ value: 'Test Company' }], domains: [{ domain: 'test.com' }], }, }, { id: { record_id: 'comp-2' }, values: { name: [{ value: 'Another Company' }], email: [{ value: 'info@another.com' }], }, }, ]; const formatted = (searchRecordsConfig.formatResult as any)( mockResults, UniversalResourceType.COMPANIES ); expect(formatted).toContain('Found 2 companies'); expect(formatted).toContain('1. Test Company (test.com) (ID: comp-1)'); expect(formatted).toContain( '2. Another Company (info@another.com) (ID: comp-2)' ); }); it('should handle empty search results', () => { const formatted = (searchRecordsConfig.formatResult as any)([]); expect(formatted).toContain('Found 0 records'); }); }); describe('records_get_details tool', () => { it('should get company details successfully', async () => { const mockRecord: any = { id: { record_id: 'comp-1' }, values: { name: [{ value: 'Test Company' }], domains: [{ domain: 'test.com' }], }, }; const { handleUniversalGetDetails } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalGetDetails).mockResolvedValue(mockRecord as any); const params: UniversalRecordDetailsParams = { resource_type: UniversalResourceType.COMPANIES, record_id: 'comp-1', }; const result = await getRecordDetailsConfig.handler(params); expect(result).toEqual(mockRecord); expect(vi.mocked(handleUniversalGetDetails)).toHaveBeenCalledWith(params); }); it('should get person details successfully', async () => { const mockRecord = { id: { record_id: 'person-1' }, values: { name: [{ value: 'John Doe' }], email: [{ value: 'john@example.com' }], phone: [{ value: '+1234567890' }], }, }; const { handleUniversalGetDetails } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); // Cast to any to align with AttioRecord typing used by handler vi.mocked(handleUniversalGetDetails).mockResolvedValue(mockRecord as any); const params: UniversalRecordDetailsParams = { resource_type: UniversalResourceType.PEOPLE, record_id: 'person-1', fields: ['name', 'email', 'phone'], }; const result = await getRecordDetailsConfig.handler(params); expect(result).toEqual(mockRecord); }); it('should format record details correctly', async () => { const mockRecord = { id: { record_id: 'comp-1' }, values: { name: [{ value: 'Test Company' }], domains: [{ domain: 'test.com' }], primary_location: [{ value: 'San Francisco, CA' }], }, }; const { getSingularResourceType } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(getSingularResourceType).mockReturnValue('company'); const formatted = (getRecordDetailsConfig.formatResult as any)( mockRecord, UniversalResourceType.COMPANIES ); expect(formatted).toContain('Company: Test Company'); expect(formatted).toContain('ID: comp-1'); expect(formatted).toContain('Domains: test.com'); expect(formatted).toContain('Primary location: San Francisco, CA'); }); }); describe('Cross-resource type validation', () => { it('should handle all resource types for search', async () => { const { handleUniversalSearch } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalSearch).mockResolvedValue([]); const resourceTypes = [ UniversalResourceType.COMPANIES, UniversalResourceType.PEOPLE, UniversalResourceType.LISTS, UniversalResourceType.RECORDS, UniversalResourceType.TASKS, UniversalResourceType.DEALS, ]; for (const resourceType of resourceTypes) { const params: UniversalSearchParams = { resource_type: resourceType, query: 'test', }; await searchRecordsConfig.handler(params); expect(vi.mocked(handleUniversalSearch)).toHaveBeenCalledWith(params); } expect(vi.mocked(handleUniversalSearch)).toHaveBeenCalledTimes(6); }); it('should handle all resource types for CRUD operations', async () => { const { handleUniversalGetDetails, handleUniversalCreate, handleUniversalUpdate, handleUniversalDelete, } = await import( '../../../../src/handlers/tool-configs/universal/shared-handlers.js' ); vi.mocked(handleUniversalGetDetails).mockResolvedValue({} as any); vi.mocked(handleUniversalCreate).mockResolvedValue({} as any); vi.mocked(handleUniversalUpdate).mockResolvedValue({} as any); vi.mocked(handleUniversalDelete).mockResolvedValue({ success: true, record_id: 'test', }); const resourceTypes = Object.values(UniversalResourceType); for (const resourceType of resourceTypes) { // Test get details await getRecordDetailsConfig.handler({ resource_type: resourceType, record_id: 'test-id', }); // Note: Create, Update, Delete tests are in the CRUD file // We only test get details here to avoid duplication } expect(vi.mocked(handleUniversalGetDetails)).toHaveBeenCalledTimes(7); }); }); describe('legacy alias compatibility', () => { it('resolves search-records alias to records.search', () => { const resolution = resolveToolName('search-records'); expect(resolution.name).toBe('records_search'); expect(resolution.alias?.alias).toBe('search-records'); }); }); });

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/kesslerio/attio-mcp-server'

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