/ tests / utils / contact-validator.test.js
contact-validator.test.js
  1  /**
  2   * Tests for src/utils/contact-validator.js
  3   *
  4   * Covers pure/sync functions only:
  5   * - validatePhone
  6   * - isMobilePhone
  7   *
  8   * validateEmail and validateSocialUrl require network (DNS/HTTP) — not tested here.
  9   */
 10  
 11  import { test, describe } from 'node:test';
 12  import assert from 'node:assert/strict';
 13  
 14  import { validatePhone, isMobilePhone } from '../../src/utils/contact-validator.js';
 15  
 16  // ─── validatePhone ────────────────────────────────────────────────────────────
 17  
 18  describe('validatePhone', () => {
 19    test('returns invalid for null', () => {
 20      const result = validatePhone(null, 'AU');
 21      assert.equal(result.valid, false);
 22      assert.ok(result.reason);
 23    });
 24  
 25    test('returns invalid for non-string', () => {
 26      const result = validatePhone(12345, 'AU');
 27      assert.equal(result.valid, false);
 28    });
 29  
 30    test('returns invalid for empty string', () => {
 31      const result = validatePhone('', 'AU');
 32      assert.equal(result.valid, false);
 33    });
 34  
 35    test('returns invalid for whitespace-only string', () => {
 36      const result = validatePhone('   ', 'AU');
 37      assert.equal(result.valid, false);
 38    });
 39  
 40    test('returns valid for a real AU mobile number in E.164', () => {
 41      const result = validatePhone('+61412345678', 'AU');
 42      assert.equal(result.valid, true);
 43      assert.equal(result.reason, null);
 44    });
 45  
 46    test('returns valid for a real US mobile number in E.164', () => {
 47      const result = validatePhone('+14089990000', 'US');
 48      assert.equal(result.valid, true);
 49      assert.equal(result.reason, null);
 50    });
 51  
 52    test('returns valid for a real GB mobile number', () => {
 53      const result = validatePhone('+447712345678', 'GB');
 54      assert.equal(result.valid, true);
 55      assert.equal(result.reason, null);
 56    });
 57  
 58    test('maps UK alias to GB', () => {
 59      // UK is a non-standard alias for GB; should still validate a real GB number
 60      const result = validatePhone('+447712345678', 'UK');
 61      assert.equal(result.valid, true);
 62    });
 63  
 64    test('returns invalid for placeholder number with 6+ repeated digits', () => {
 65      const result = validatePhone('+15555555555', 'US');
 66      assert.equal(result.valid, false);
 67      assert.ok(result.reason.includes('placeholder'));
 68    });
 69  
 70    test('returns invalid for NANP 555 fictional number', () => {
 71      const result = validatePhone('+12125550123', 'US');
 72      assert.equal(result.valid, false);
 73      assert.ok(result.reason.includes('fictitious'));
 74    });
 75  
 76    test('returns invalid for obviously fake number', () => {
 77      const result = validatePhone('0000000000', 'AU');
 78      assert.equal(result.valid, false);
 79    });
 80  
 81    test('returns invalid for number that is wrong region', () => {
 82      // US number passed as AU — should fail region check
 83      const result = validatePhone('+12025551234', 'AU');
 84      assert.equal(result.valid, false);
 85      assert.ok(result.reason);
 86    });
 87  
 88    test('returns invalid for completely unparseable string', () => {
 89      const result = validatePhone('not-a-phone', 'AU');
 90      assert.equal(result.valid, false);
 91      assert.ok(result.reason);
 92    });
 93  });
 94  
 95  // ─── isMobilePhone ────────────────────────────────────────────────────────────
 96  
 97  describe('isMobilePhone', () => {
 98    test('returns true for a real AU mobile number', () => {
 99      assert.equal(isMobilePhone('+61412345678', 'AU'), true);
100    });
101  
102    test('returns false for an AU landline number', () => {
103      // +61 2 9999 9999 is a Sydney landline
104      assert.equal(isMobilePhone('+61299999999', 'AU'), false);
105    });
106  
107    test('returns false for a US landline number', () => {
108      // US toll-free 800 numbers are not mobile
109      assert.equal(isMobilePhone('+18005551234', 'US'), false);
110    });
111  
112    test('returns false for unparseable input', () => {
113      assert.equal(isMobilePhone('not-a-number', 'AU'), false);
114    });
115  
116    test('returns false for null', () => {
117      assert.equal(isMobilePhone(null, 'AU'), false);
118    });
119  });