Skip to main content
Glama
UniversalRetrievalService-core-operations.test.tsβ€’12.9 kB
/** * Split: UniversalRetrievalService core operations */ // Local mocks (must match specifiers used below) import { vi } from 'vitest'; vi.mock('../../src/services/ValidationService.js', () => ({ ValidationService: { validateUUID: vi.fn() }, })); vi.mock('../../src/services/CachingService.js', () => ({ CachingService: { isCached404: vi.fn(), cache404Response: vi.fn() }, })); vi.mock('../../src/services/UniversalUtilityService.js', () => ({ UniversalUtilityService: { convertTaskToRecord: vi.fn() }, })); vi.mock('../../src/middleware/performance-enhanced.js', () => ({ enhancedPerformanceTracker: { startOperation: vi.fn(() => 'perf-123'), markTiming: vi.fn(), markApiStart: vi.fn(() => 100), markApiEnd: vi.fn(), endOperation: vi.fn(), }, })); vi.mock('../../src/utils/validation/uuid-validation.js', () => ({ createRecordNotFoundError: vi.fn(() => new Error('Record not found')), })); vi.mock('../../src/errors/enhanced-api-errors.js', () => ({ ErrorEnhancer: { autoEnhance: vi.fn((e) => e), getErrorMessage: vi.fn((e) => (e as any).message), }, EnhancedApiError: class EnhancedApiError extends Error { public readonly statusCode: number; public readonly endpoint: string; public readonly method: string; public readonly context?: any; constructor( message: string, statusCode = 500, endpoint = '', method = 'GET', context: any = {} ) { super(message); this.name = 'EnhancedApiError'; this.statusCode = statusCode; this.endpoint = endpoint; this.method = method; this.context = context; } }, })); vi.mock('../../src/objects/companies/index.js', () => ({ getCompanyDetails: vi.fn(), })); vi.mock('../../src/objects/people/index.js', () => ({ getPersonDetails: vi.fn(), })); vi.mock('../../src/objects/lists.js', () => ({ getListDetails: vi.fn() })); vi.mock('../../src/objects/records/index.js', () => ({ getObjectRecord: vi.fn(), })); vi.mock('../../src/objects/tasks.js', () => ({ getTask: vi.fn() })); vi.mock('../../src/objects/notes.js', () => ({ getNote: vi.fn() })); vi.mock('../../src/services/create/index.js', () => ({ shouldUseMockData: vi.fn(), })); import { describe, it, expect, beforeEach } from 'vitest'; import { UniversalRetrievalService } from '../../src/services/UniversalRetrievalService.js'; import { UniversalResourceType } from '../../src/handlers/tool-configs/universal/types.js'; import { AttioRecord, AttioTask } from '../../src/types/attio.js'; import { enhancedPerformanceTracker } from '../../src/middleware/performance-enhanced.js'; import { CachingService } from '../../src/services/CachingService.js'; import { UniversalUtilityService } from '../../src/services/UniversalUtilityService.js'; import { getCompanyDetails } from '../../src/objects/companies/index.js'; import { getPersonDetails } from '../../src/objects/people/index.js'; import * as lists from '../../src/objects/lists.js'; import { getObjectRecord } from '../../src/objects/records/index.js'; import * as tasks from '../../src/objects/tasks.js'; import { shouldUseMockData } from '../../src/services/create/index.js'; describe('UniversalRetrievalService', () => { beforeEach(() => { vi.clearAllMocks(); // Default to using mock data for most tests (offline mode) vi.mocked(shouldUseMockData).mockReturnValue(true); }); describe('getRecordDetails', () => { const mockRecord: AttioRecord = { id: { record_id: 'test_123' }, values: { name: 'Test Record' }, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }; beforeEach(() => { vi.mocked(CachingService.isCached404).mockReturnValue(false); }); it('should retrieve a company record', async () => { vi.mocked(getCompanyDetails).mockResolvedValue(mockRecord); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.COMPANIES, record_id: 'comp_123', }); expect(getCompanyDetails).toHaveBeenCalledWith('comp_123'); expect(result).toEqual(mockRecord); }); it('should retrieve a person record', async () => { vi.mocked(getPersonDetails).mockResolvedValue(mockRecord); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.PEOPLE, record_id: 'person_456', }); expect(getPersonDetails).toHaveBeenCalledWith('person_456'); expect(result).toEqual(mockRecord); }); it('should retrieve a list record and convert format', async () => { const mockList = { id: { list_id: 'list_789' }, name: 'Test List', title: 'Test List', description: 'Test description', object_slug: 'companies', api_slug: 'test-list', workspace_id: 'ws_123', workspace_member_access: 'read', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', } as any; vi.mocked(lists.getListDetails).mockResolvedValue(mockList); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.LISTS, record_id: 'list_789', }); expect(lists.getListDetails).toHaveBeenCalledWith('list_789'); expect(result).toEqual({ id: { record_id: 'list_789', list_id: 'list_789', }, values: { name: 'Test List', description: 'Test description', parent_object: 'companies', api_slug: 'test-list', workspace_id: 'ws_123', workspace_member_access: 'read', created_at: '2024-01-01T00:00:00Z', }, }); }); it('should retrieve a records object record', async () => { vi.mocked(getObjectRecord).mockResolvedValue(mockRecord); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.RECORDS, record_id: 'record_abc', }); expect(getObjectRecord).toHaveBeenCalledWith('records', 'record_abc'); expect(result).toEqual(mockRecord); }); it('should retrieve a deals object record', async () => { vi.mocked(getObjectRecord).mockResolvedValue(mockRecord); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.DEALS, record_id: 'deal_def', }); expect(getObjectRecord).toHaveBeenCalledWith('deals', 'deal_def'); expect(result).toEqual(mockRecord); }); it('should retrieve a task record and convert to AttioRecord', async () => { // Ensure we use real task API, not mock data vi.mocked(shouldUseMockData).mockReturnValue(false); const mockTask: AttioTask = { id: { task_id: 'task_ghi' }, content: 'Test Task', status: 'pending', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', } as any; vi.mocked(tasks.getTask).mockResolvedValue(mockTask); vi.mocked(UniversalUtilityService.convertTaskToRecord).mockReturnValue( mockRecord ); const result = await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.TASKS, record_id: 'task_ghi', }); expect(tasks.getTask).toHaveBeenCalledWith('task_ghi'); expect(UniversalUtilityService.convertTaskToRecord).toHaveBeenCalledWith( mockTask ); expect(result).toEqual(mockRecord); }); it('should handle performance tracking correctly', async () => { vi.mocked(getCompanyDetails).mockResolvedValue(mockRecord); await UniversalRetrievalService.getRecordDetails({ resource_type: UniversalResourceType.COMPANIES, record_id: 'comp_123', }); expect(enhancedPerformanceTracker.startOperation).toHaveBeenCalledWith( 'get-record-details', 'get', { resourceType: UniversalResourceType.COMPANIES, recordId: 'comp_123' } ); expect(enhancedPerformanceTracker.markTiming).toHaveBeenCalled(); expect(enhancedPerformanceTracker.markApiStart).toHaveBeenCalledWith( 'perf-123' ); expect(enhancedPerformanceTracker.markApiEnd).toHaveBeenCalledWith( 'perf-123', 100 ); expect(enhancedPerformanceTracker.endOperation).toHaveBeenCalledWith( 'perf-123', true, undefined, 200 ); }); }); describe('recordExists', () => { it('should return true when record exists', async () => { vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails).mockResolvedValue({ id: { record_id: 'comp_123' }, values: { name: [{ value: 'Test Company' }] }, } as any); const exists = await UniversalRetrievalService.recordExists( UniversalResourceType.COMPANIES, 'comp_123' ); expect(exists).toBe(true); }); it('should return false when record is cached as 404', async () => { vi.mocked(CachingService.isCached404).mockReturnValue(true); const exists = await UniversalRetrievalService.recordExists( UniversalResourceType.COMPANIES, 'comp_123' ); expect(exists).toBe(false); }); it('should return false when record throws not found error', async () => { vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails).mockRejectedValue( new Error('Record not found') ); const exists = await UniversalRetrievalService.recordExists( UniversalResourceType.COMPANIES, 'comp_123' ); expect(exists).toBe(false); }); }); describe('getMultipleRecords', () => { it('should retrieve multiple records successfully', async () => { const record1: AttioRecord = { id: { record_id: 'comp_123' }, values: { name: [{ value: 'Company 1' }] }, } as any; const record2: AttioRecord = { id: { record_id: 'comp_456' }, values: { name: [{ value: 'Company 2' }] }, } as any; vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails) .mockResolvedValueOnce(record1) .mockResolvedValueOnce(record2); const results = await UniversalRetrievalService.getMultipleRecords( UniversalResourceType.COMPANIES, ['comp_123', 'comp_456'] ); expect(results).toEqual([record1, record2]); }); it('should handle mixed success and failure results', async () => { const record1: AttioRecord = { id: { record_id: 'comp_123' }, values: { name: [{ value: 'Company 1' }] }, } as any; vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails) .mockResolvedValueOnce(record1) .mockRejectedValueOnce(new Error('Not found')); const results = await UniversalRetrievalService.getMultipleRecords( UniversalResourceType.COMPANIES, ['comp_123', 'comp_456'] ); expect(results).toEqual([record1, null]); }); it('should apply field filtering to multiple records', async () => { const record1: AttioRecord = { id: { record_id: 'comp_123' }, values: { name: [{ value: 'Company 1' }], domain: 'company1.com', employees: 10, }, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', } as any; vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails).mockResolvedValue(record1); const results = await UniversalRetrievalService.getMultipleRecords( UniversalResourceType.COMPANIES, ['comp_123'], ['name'] ); expect(results[0]?.values).toEqual({ name: 'Company 1' }); expect(results[0]?.id).toEqual(record1.id); }); }); describe('getRecordWithMetrics', () => { it('should return record with performance metrics', async () => { const mockRecord: AttioRecord = { id: { record_id: 'comp_123' }, values: { name: [{ value: 'Test Company' }] }, } as any; vi.mocked(CachingService.isCached404).mockReturnValue(false); vi.mocked(getCompanyDetails).mockResolvedValue(mockRecord); const result = await UniversalRetrievalService.getRecordWithMetrics({ resource_type: UniversalResourceType.COMPANIES, record_id: 'comp_123', }); expect(result.record).toEqual(mockRecord); expect(result.metrics).toEqual( expect.objectContaining({ duration: expect.any(Number), cached: false, }) ); }); }); }); // local shim to satisfy import order (side-effect first) export {};

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