import { describe, expect, it } from "vitest"; import { isSmsReachable, isValidPhone } from "./PhoneField"; /** * `isSmsReachable` mirrors `isDomesticPhone` in the API's otp.service. The two * must agree: this one greys out the SMS option, that one decides whether the * message is actually sent, and a disagreement means the UI promises a text * nobody sends (or hides one that would have worked). These cases are the same * ones the API spec asserts. */ describe("isSmsReachable", () => { it.each(["+251986680099", "0986680099", "251986680099"])( "accepts Ethiopian mobile form %s", (phone) => expect(isSmsReachable(phone)).toBe(true), ); it.each(["+25377123456", "25377123456", "77123456"])( "accepts Djibouti mobile form %s", (phone) => expect(isSmsReachable(phone)).toBe(true), ); it.each([ "+14155550123", "+447911123456", "0712345678", "+2519866", "12345", // Djibouti fixed line — valid number, not a mobile the gateway serves. "+25321350000", "+25366123456", ])("rejects unreachable or malformed %s", (phone) => expect(isSmsReachable(phone)).toBe(false), ); it.each([undefined, null, ""])("treats %s as unreachable", (phone) => expect(isSmsReachable(phone)).toBe(false), ); }); /** * The country-picker input emits a PARTIAL E.164 while the user is still * typing — "+25377" is a non-empty string that will post happily and come back * as a 400 from the API's own IsValidPhone. Forms must treat "non-empty" and * "complete" as different questions, so this is the check they call. */ describe("isValidPhone", () => { it.each(["+25377834567", "+251911223344"])( "accepts the complete number %s", (phone) => expect(isValidPhone(phone)).toBe(true), ); it.each(["+253", "+25377", "+2537712", "+251", "+2519112"])( "rejects the partial number %s the picker emits mid-typing", (phone) => expect(isValidPhone(phone)).toBe(false), ); it.each([undefined, null, ""])("treats %s as invalid", (phone) => expect(isValidPhone(phone)).toBe(false), ); });