Skip to main content
Glama
universal-error-handling.test.tsβ€’7.71 kB
/** * Tests for enhanced universal error handling */ import { describe, it, expect, beforeEach } from 'vitest'; import { validateUniversalToolParams, UniversalValidationError, ErrorType, HttpStatusCode, InputSanitizer, CrossResourceValidator, } from '../src/handlers/tool-configs/universal/schemas.js'; import { UniversalResourceType } from '../src/handlers/tool-configs/universal/types.js'; import { getErrorMessage, ensureError } from '../src/utils/error-utilities.js'; describe('Enhanced Universal Error Handling', () => { describe('Input Sanitization', () => { it('should sanitize XSS attempts in strings', () => { const maliciousInput = '<script>alert("xss")</script>Hello'; const sanitized = InputSanitizer.sanitizeString(maliciousInput); expect(sanitized).toBe('alert("xss")Hello'); }); it('should normalize email addresses', () => { const email = ' TEST@EXAMPLE.COM '; const normalized = InputSanitizer.normalizeEmail(email); expect(normalized).toBe('test@example.com'); }); it('should sanitize objects recursively', () => { const obj = { name: '<script>evil</script>Company', email: ' ADMIN@COMPANY.COM ', nested: { description: 'onclick=alert(1)Safe description', }, }; const sanitized = InputSanitizer.sanitizeObject(obj) as any; expect(sanitized.name).toBe('evilCompany'); expect(sanitized.email).toBe('admin@company.com'); expect(sanitized.nested.description).toBe('alert(1)Safe description'); }); }); describe('Error Classification', () => { it('should create UniversalValidationError with proper classification', () => { const error = new UniversalValidationError( 'Test error message', ErrorType.USER_ERROR, { field: 'test_field', suggestion: 'Try this instead', example: 'field: "correct_value"', } ); expect(error.message).toBe('Test error message'); expect(error.errorType).toBe(ErrorType.USER_ERROR); expect(error.field).toBe('test_field'); expect(error.suggestion).toBe('Try this instead'); expect(error.example).toBe('field: "correct_value"'); }); }); describe('Enhanced Validation Messages', () => { it('should provide helpful suggestions for invalid resource types', () => { const params = { resource_type: 'company' }; // Missing 's' try { validateUniversalToolParams('search-records', params); expect.fail('Should have thrown validation error'); } catch (error: unknown) { const errorObj = ensureError(error); expect(errorObj).toBeInstanceOf(UniversalValidationError); const validationError = errorObj as UniversalValidationError; expect(validationError.suggestion).toContain('companies'); expect(validationError.example).toContain('companies, people'); } }); it('should provide detailed missing parameter errors', () => { const params = { resource_type: UniversalResourceType.COMPANIES }; try { validateUniversalToolParams('create-record', params); expect.fail('Should have thrown validation error'); } catch (error: unknown) { expect(error).toBeInstanceOf(UniversalValidationError); const validationError = error as UniversalValidationError; expect(validationError.field).toBe('record_data'); expect(validationError.suggestion).toContain( 'Provide the data for creating' ); expect(validationError.example).toContain('record_data:'); } }); it('should handle batch operations validation with specific messages', () => { const params = { resource_type: UniversalResourceType.COMPANIES, operation_type: 'create', // Missing records array }; try { validateUniversalToolParams('records_batch', params); expect.fail('Should have thrown validation error'); } catch (error: unknown) { expect(error).toBeInstanceOf(UniversalValidationError); const validationError = error as UniversalValidationError; expect(validationError.field).toBe('records'); expect(validationError.suggestion).toContain('array of record data'); expect(validationError.example).toContain('records:'); } }); }); describe('Parameter Sanitization', () => { it('should return sanitized parameters from validation', () => { const params = { resource_type: UniversalResourceType.COMPANIES, query: ' <script>alert(1)</script>Search Term ', }; const sanitized = validateUniversalToolParams('search-records', params); expect(sanitized.query).toBe('alert(1)Search Term'); expect(sanitized.resource_type).toBe(UniversalResourceType.COMPANIES); }); }); describe('String Similarity Suggestions', () => { it('should suggest common resource type alternatives', () => { const testCases = [ { input: 'person', expected: 'people' }, { input: 'contact', expected: 'people' }, { input: 'organization', expected: 'companies' }, { input: 'task', expected: 'tasks' }, ]; for (const testCase of testCases) { try { validateUniversalToolParams('search-records', { resource_type: testCase.input, }); expect.fail( `Should have thrown validation error for ${testCase.input}` ); } catch (error: unknown) { expect(error).toBeInstanceOf(UniversalValidationError); const validationError = error as UniversalValidationError; expect(validationError.suggestion).toContain(testCase.expected); } } }); }); }); describe('Cross-Resource Validation', () => { describe('Company Validation', () => { it('should validate company existence (mock test)', async () => { // This is a unit test - we'd need integration tests with real API for full validation // For now, just test that the validation function exists and can be called expect(typeof CrossResourceValidator.validateCompanyExists).toBe( 'function' ); expect(typeof CrossResourceValidator.validateRecordRelationships).toBe( 'function' ); }); it('should handle people record validation structure', async () => { const recordData = { name: 'John Doe', company_id: 'comp_123', }; // Mock the company validation to return failure result for this test const originalValidate = CrossResourceValidator.validateCompanyExists; CrossResourceValidator.validateCompanyExists = async () => ({ exists: false, error: { type: 'not_found' as const, message: "Company with ID 'comp_123' does not exist", httpStatusCode: HttpStatusCode.NOT_FOUND, }, }); try { await CrossResourceValidator.validateRecordRelationships( UniversalResourceType.PEOPLE, recordData ); expect.fail( 'Should have thrown validation error for non-existent company' ); } catch (error: unknown) { expect(error).toBeInstanceOf(UniversalValidationError); const validationError = error as UniversalValidationError; expect(validationError.field).toBe('company_id'); expect(validationError.suggestion).toContain( 'Verify the company ID exists' ); } finally { // Restore original function CrossResourceValidator.validateCompanyExists = originalValidate; } }); }); });

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