Skip to main content
Glama
phone-validation.test.ts7.98 kB
/** * Unit tests for phone validation utilities * @attio-mcp/core - Issue #951 */ import { describe, it, expect } from 'vitest'; import { validatePhoneNumber, toE164, hasCountryCode, isPossiblePhoneNumber, isValidPhoneNumber, normalizePhoneForAttio, PhoneValidationError, } from '../../src/utils/phone-validation.js'; describe('phone-validation', () => { describe('validatePhoneNumber', () => { it('validates E.164 format correctly', () => { const result = validatePhoneNumber('+12025550134'); expect(result.valid).toBe(true); expect(result.e164).toBe('+12025550134'); expect(result.country).toBe('US'); }); it('validates US number with formatting', () => { const result = validatePhoneNumber('+1 (202) 555-0134'); expect(result.valid).toBe(true); expect(result.e164).toBe('+12025550134'); expect(result.country).toBe('US'); }); it('applies default country when no prefix', () => { const result = validatePhoneNumber('2025550134', { defaultCountry: 'US', }); expect(result.valid).toBe(true); expect(result.e164).toBe('+12025550134'); }); it('detects country from international format - UK', () => { const result = validatePhoneNumber('+44 20 7946 0958'); expect(result.valid).toBe(true); expect(result.country).toBe('GB'); expect(result.e164).toBe('+442079460958'); }); it('detects country from international format - Japan', () => { const result = validatePhoneNumber('+81 3 1234 5678'); expect(result.valid).toBe(true); expect(result.country).toBe('JP'); }); it('detects country from international format - Australia', () => { const result = validatePhoneNumber('+61 2 9374 4000'); expect(result.valid).toBe(true); expect(result.country).toBe('AU'); }); it('returns error for invalid format', () => { const result = validatePhoneNumber('not-a-phone'); expect(result.valid).toBe(false); expect(result.error).toBeDefined(); expect(result.error?.code).toBe('NOT_A_NUMBER'); }); it('returns error for too-short numbers', () => { const result = validatePhoneNumber('+1202', { defaultCountry: 'US' }); expect(result.valid).toBe(false); expect(result.error?.code).toBe('TOO_SHORT'); }); it('returns error for too-long numbers', () => { const result = validatePhoneNumber('+12025550134567890123456'); expect(result.valid).toBe(false); expect(result.error?.code).toBe('TOO_LONG'); }); it('returns error for empty input', () => { const result = validatePhoneNumber(''); expect(result.valid).toBe(false); expect(result.error?.code).toBe('INVALID_FORMAT'); expect(result.error?.message).toContain('empty'); }); it('returns error for whitespace-only input', () => { const result = validatePhoneNumber(' '); expect(result.valid).toBe(false); expect(result.error?.code).toBe('INVALID_FORMAT'); }); it('returns error for non-string input', () => { // @ts-expect-error Testing invalid input type const result = validatePhoneNumber(12345); expect(result.valid).toBe(false); expect(result.error?.code).toBe('INVALID_TYPE'); }); }); describe('toE164', () => { it('converts US format to E.164', () => { expect(toE164('(202) 555-0134', 'US')).toBe('+12025550134'); }); it('converts international format to E.164', () => { // Use 202 (DC) instead of 555 (fictional) expect(toE164('+1 202 555 0134')).toBe('+12025550134'); }); it('returns null for invalid', () => { expect(toE164('invalid')).toBeNull(); }); it('returns null for empty string', () => { expect(toE164('')).toBeNull(); }); it('returns null for non-string input', () => { expect(toE164(12345)).toBeNull(); expect(toE164(null)).toBeNull(); expect(toE164(undefined)).toBeNull(); }); }); describe('hasCountryCode', () => { it('detects + prefix', () => { expect(hasCountryCode('+1 555 123 4567')).toBe(true); expect(hasCountryCode('+442079460958')).toBe(true); }); it('returns false without + prefix', () => { expect(hasCountryCode('555 123 4567')).toBe(false); expect(hasCountryCode('2025550134')).toBe(false); }); it('handles whitespace', () => { expect(hasCountryCode(' +1 555')).toBe(true); }); it('returns false for non-string', () => { // @ts-expect-error Testing invalid input type expect(hasCountryCode(12345)).toBe(false); }); }); describe('isPossiblePhoneNumber', () => { it('returns true for possible numbers', () => { expect(isPossiblePhoneNumber('+12025550134')).toBe(true); expect(isPossiblePhoneNumber('2025550134', 'US')).toBe(true); }); it('returns false for clearly invalid', () => { expect(isPossiblePhoneNumber('abc')).toBe(false); expect(isPossiblePhoneNumber('')).toBe(false); }); }); describe('isValidPhoneNumber', () => { it('returns true for valid numbers', () => { expect(isValidPhoneNumber('+12025550134')).toBe(true); }); it('returns false for invalid numbers', () => { expect(isValidPhoneNumber('invalid')).toBe(false); }); }); describe('normalizePhoneForAttio', () => { it('normalizes string phone to Attio format', () => { // Use 202 (DC) instead of 555 (fictional) const result = normalizePhoneForAttio('+1 202 555 0134'); expect(result).toEqual({ original_phone_number: '+12025550134', }); }); it('normalizes object with phone_number key', () => { const result = normalizePhoneForAttio({ phone_number: '+1 202 555 0134', label: 'work', }); expect(result).toEqual({ original_phone_number: '+12025550134', label: 'work', }); }); it('preserves metadata fields', () => { const result = normalizePhoneForAttio({ phone_number: '+1 202 555 0134', label: 'work', type: 'mobile', extension: '123', is_primary: true, }); expect(result.original_phone_number).toBe('+12025550134'); expect(result.label).toBe('work'); expect(result.type).toBe('mobile'); expect(result.extension).toBe('123'); expect(result.is_primary).toBe(true); }); it('removes phone_number key after normalization', () => { const result = normalizePhoneForAttio({ phone_number: '+1 202 555 0134', }); expect(result).not.toHaveProperty('phone_number'); expect(result).toHaveProperty('original_phone_number'); }); it('applies default country for national format', () => { const result = normalizePhoneForAttio('2025550134', { defaultCountry: 'US', }); expect(result.original_phone_number).toBe('+12025550134'); }); it('throws PhoneValidationError for invalid phone', () => { expect(() => normalizePhoneForAttio('invalid')).toThrow( PhoneValidationError ); }); it('throws for empty phone', () => { expect(() => normalizePhoneForAttio('')).toThrow(PhoneValidationError); }); }); describe('PhoneValidationError', () => { it('has correct properties', () => { const error = new PhoneValidationError( 'INVALID_FORMAT', 'Test message', '+123', 'US' ); expect(error.name).toBe('PhoneValidationError'); expect(error.code).toBe('INVALID_FORMAT'); expect(error.message).toBe('Test message'); expect(error.input).toBe('+123'); expect(error.country).toBe('US'); }); it('is instanceof Error', () => { const error = new PhoneValidationError('INVALID_FORMAT', 'Test', 'input'); expect(error).toBeInstanceOf(Error); expect(error).toBeInstanceOf(PhoneValidationError); }); }); });

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