Skip to content

Commit

Permalink
Merge pull request #1 from nthombare-mdsol/nthombare-mdsol-patch-1
Browse files Browse the repository at this point in the history
Updated regex for E.164 compliant to support phone number with extension.
  • Loading branch information
nthombare-mdsol authored Jan 28, 2025
2 parents 5471b05 + 37e747a commit 387d8eb
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 56 deletions.
12 changes: 8 additions & 4 deletions src/scalars/PhoneNumber.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { GraphQLScalarType, Kind } from 'graphql';
import { createGraphQLError } from '../error.js';

const PHONE_NUMBER_REGEX = /^\+[1-9]\d{6,14}$/;
// The regex supports all phone numbers compliant with the E.164 international format standard,
// which includes country codes (Optional), area codes, and local numbers and extension (optional). For more information on E.164 formatting,
// Regex: https://regex101.com/r/nol2F6/1
// Ex. +62 (21) 9175 5194, 2191755194, +1 123-456-7890 12345, +1 (123) 456-7890
const PHONE_NUMBER_REGEX = /^\+?\d{1,3}(\-|\x20)?\(?\d+\)?((\-|\x20)?\d+)+$/;

export const GraphQLPhoneNumber = /*#__PURE__*/ new GraphQLScalarType({
name: 'PhoneNumber',
Expand All @@ -16,7 +20,7 @@ export const GraphQLPhoneNumber = /*#__PURE__*/ new GraphQLScalarType({

if (!PHONE_NUMBER_REGEX.test(value)) {
throw createGraphQLError(
`Value is not a valid phone number of the form +17895551234 (7-15 digits): ${value}`,
`Invalid phone number: ${value}. Please ensure it's in a valid format. The country code is optional, and Spaces and dashes are allowed. Examples: +1 (123) 456-7890, +44 (20) 2121 2222, or 123 456-7890.`,
);
}

Expand All @@ -30,7 +34,7 @@ export const GraphQLPhoneNumber = /*#__PURE__*/ new GraphQLScalarType({

if (!PHONE_NUMBER_REGEX.test(value)) {
throw createGraphQLError(
`Value is not a valid phone number of the form +17895551234 (7-15 digits): ${value}`,
`Invalid phone number: ${value}. Please ensure it's in a valid format. The country code is optional, and Spaces and dashes are allowed. Examples: +1 (123) 456-7890, +44 (20) 2121 2222, or 123 456-7890.`,
);
}

Expand All @@ -47,7 +51,7 @@ export const GraphQLPhoneNumber = /*#__PURE__*/ new GraphQLScalarType({

if (!PHONE_NUMBER_REGEX.test(ast.value)) {
throw createGraphQLError(
`Value is not a valid phone number of the form +17895551234 (7-15 digits): ${ast.value}`,
`Invalid phone number: ${ast.value}. Please ensure it's in a valid format. The country code is optional, and Spaces and dashes are allowed. Examples: +1 (123) 456-7890, +44 (20) 2121 2222, or 123 456-7890.`,
{ nodes: ast },
);
}
Expand Down
121 changes: 69 additions & 52 deletions tests/PhoneNumber.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,80 @@
import { Kind } from 'graphql/language';
import { GraphQLPhoneNumber } from '../src/scalars/PhoneNumber.js';

function PhoneNumberError(value: string) {
return `Invalid phone number: ${value}. Please ensure it's in a valid format. The country code is optional, and Spaces and dashes are allowed. Examples: +1 (123) 456-7890, +44 (20) 2121 2222, or 123 456-7890.`
}

describe('PhoneNumber', () => {
describe('valid', () => {
test('serialize', () => {
expect(GraphQLPhoneNumber.serialize('+16075551234')).toBe('+16075551234');
describe('valid formats', () => {
describe('with country code', () => {
test('serialize', () => {
expect(GraphQLPhoneNumber.serialize('+16075551234')).toBe('+16075551234');
});

test('parseValue', () => {
expect(GraphQLPhoneNumber.parseValue('+16075551234')).toBe('+16075551234');
});

test('parseLiteral', () => {
expect(
GraphQLPhoneNumber.parseLiteral({ value: '+16075551234', kind: Kind.STRING }, {}),
).toBe('+16075551234');
});
});
describe('without country code', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('7895551234')).not.toThrow()
});

test('parseValue', () => {
expect(GraphQLPhoneNumber.parseValue('+16075551234')).toBe('+16075551234');
test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('123 456-7890')).not.toThrow()
});

test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral({ value: '789 555 1234', kind: Kind.STRING }, {}),
).not.toThrow();
});
});
describe('different formatting', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('62-(21)-9175-5194')).not.toThrow()
});

test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('+622191755194')).not.toThrow()
});

test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('+62 (21) 9175 5194')).not.toThrow()
});

test('parseLiteral', () => {
expect(
GraphQLPhoneNumber.parseLiteral({ value: '+16075551234', kind: Kind.STRING }, {}),
).toBe('+16075551234');
test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral({ value: '+1 (123) 456-7890', kind: Kind.STRING }, {}),
).not.toThrow();
});
});
});

describe('invalid', () => {
describe('not a phone number', () => {
describe('invalid case', () => {
describe('contains Non-Numeric Characters', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('this is not a phone number')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.serialize('98aaa333')).toThrow(PhoneNumberError('98aaa333'));
});

test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('this is not a phone number')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.parseValue('98aaa333ppp')).toThrow(PhoneNumberError('98aaa333ppp'));
});

test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral(
{ value: 'this is not a phone number', kind: Kind.STRING },
{ value: '98aa', kind: Kind.STRING },
{},
),
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/);
).toThrow(PhoneNumberError('98aa'));
});
});

Expand All @@ -60,65 +96,46 @@ describe('PhoneNumber', () => {
});
});

describe('too long', () => {
describe('wrong formate', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('+1789555123456789')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
});

test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('+1789555123456789')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.serialize('+17 89- 5')).toThrow(PhoneNumberError('+17 89- 5'));
});

test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral({ value: '+1789555123456789', kind: Kind.STRING }, {}),
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/);
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('+1 ( 123 ) 456-7890')).toThrow(PhoneNumberError('+1 ( 123 ) 456-7890'));
});
});

describe('too small', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('+123')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.serialize('+1[123]456 7890')).toThrow(PhoneNumberError('+1[123]456 7890'));
});

test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('+123')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.parseValue('+(178)95 55 5678')).toThrow(PhoneNumberError('+(178)95 55 5678'));
});

test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral({ value: '+123', kind: Kind.STRING }, {}),
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/);
GraphQLPhoneNumber.parseLiteral({ value: '1789 [555] 1234', kind: Kind.STRING }, {}),
).toThrow(PhoneNumberError('1789 [555] 1234'));
});
});

describe('no plus sign', () => {
describe('too small', () => {
test('serialize', () => {
expect(() => GraphQLPhoneNumber.serialize('17895551234')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.serialize('+12')).toThrow(PhoneNumberError('+12'));
});

test('parseValue', () => {
expect(() => GraphQLPhoneNumber.parseValue('17895551234')).toThrow(
/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/,
);
expect(() => GraphQLPhoneNumber.parseValue('+12')).toThrow(PhoneNumberError('+12'));
});

test('parseLiteral', () => {
expect(() =>
GraphQLPhoneNumber.parseLiteral({ value: '17895551234', kind: Kind.STRING }, {}),
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(7-15 digits\)/);
GraphQLPhoneNumber.parseLiteral({ value: '+12', kind: Kind.STRING }, {}),
).toThrow(PhoneNumberError('+12'));
});
});

describe('support more countries', () => {
test('support Singapore numbers - 10 digits', () => {
expect(() => {
Expand Down

0 comments on commit 387d8eb

Please sign in to comment.