Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DTSPB-4477: Increase max mobile number length #2348

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f02d9ce
DTSPB-4477: Increase max mobile number length
jamiealbertelli Dec 31, 2024
3dbd952
DTSPB-4477: Widen length so validation can do its job
jamiealbertelli Jan 7, 2025
7a96d18
DTSPB-4477: Update mobile phone validation tests
jamiealbertelli Jan 7, 2025
c694703
DTSPB-4477: Update phone validation with new lib
jamiealbertelli Jan 7, 2025
0ca9eaa
DTSPB-4477: Add libphonenumber-js lib
jamiealbertelli Jan 7, 2025
101e291
DTSPB-4477: Add try-catch
jamiealbertelli Jan 7, 2025
90f3df3
DTSPB-4477: Correct test naming
jamiealbertelli Jan 7, 2025
d938250
Merge branch 'master' into DTSPB-4477-phone-number-validation-fix
jamiealbertelli Jan 7, 2025
8980d8d
DTSPB-4477: Refactor validation to return error and not entirely swal…
jamiealbertelli Jan 8, 2025
43734cd
DTSPB-4477: errorType now stores the json error message key so valida…
jamiealbertelli Jan 8, 2025
87fffc2
DTSPB-4477: Check object value is equal to refactored validation
jamiealbertelli Jan 8, 2025
6bbfd25
DTSPB-4477: Remove specificity on isValid
jamiealbertelli Jan 8, 2025
e25e8cc
DTSPB-4477: Remove redundant return
jamiealbertelli Jan 8, 2025
b77b2a6
DTSPB-4477: Refactor validation to return error and not entirely swal…
jamiealbertelli Jan 8, 2025
d5ad924
Merge branch 'master' into DTSPB-4477-phone-number-validation-fix
jamiealbertelli Jan 15, 2025
87d329c
DTSPB-4477: Add granule error messages
jamiealbertelli Jan 16, 2025
329ad39
DTSPB-4477: Adjust validation to match new granule error messages
jamiealbertelli Jan 16, 2025
09651cd
DTSPB-4477: Remove min and max length constraint as they are now cont…
jamiealbertelli Jan 16, 2025
9383300
DTSPB-4477: Update tests to match new mew messaging and validation
jamiealbertelli Jan 16, 2025
03dc011
DTSPB-4477: Git merge
jamiealbertelli Jan 16, 2025
641dc78
DTSPB-4477: Correct Welsh error message
jamiealbertelli Jan 16, 2025
5d164ef
DTSPB-4477: Correct test error message
jamiealbertelli Jan 16, 2025
86302f5
DTSPB-4477: Revert expected error message and add logging to see what…
jamiealbertelli Jan 16, 2025
a89e51f
DTSPB-4477: Revert schema to handle length errors
jamiealbertelli Jan 16, 2025
8459523
DTSPB-4477: Revert logging
jamiealbertelli Jan 16, 2025
c0bb16b
DTSPB-4477: Remove num length for error control
jamiealbertelli Jan 16, 2025
f409cba
DTSPB-4477: Change expected error outcome
jamiealbertelli Jan 16, 2025
e91f39d
DTSPB-4477: Remove unused error messages
jamiealbertelli Jan 16, 2025
203e571
Merge branch 'master' into DTSPB-4477-phone-number-validation-fix
jamiealbertelli Jan 16, 2025
8df4c81
DTSPB-4477: Correctly revert schema
jamiealbertelli Jan 16, 2025
5f1d2e2
DTSPB-4477: Merge
jamiealbertelli Jan 16, 2025
22f0c69
DTSPB-4477: Check why error message is not correctly returning in test
jamiealbertelli Jan 16, 2025
c6e553c
DTSPB-4477: Check why error message is not correctly returning in test
jamiealbertelli Jan 16, 2025
aeca5d3
DTSPB-4477: Fix schema vars and adjust tests to match
jamiealbertelli Jan 17, 2025
db87a11
Merge branch 'master' into DTSPB-4477-phone-number-validation-fix
FeliTam Jan 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions app/steps/ui/executors/contactdetails/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,13 @@ class ExecutorContactDetails extends ValidationStep {
if (executorsWrapper.executorEmailAlreadyUsed(ctx.email, executor.fullName, formdata.applicantEmail)) {
errors.push(FieldError('email', 'duplicate', this.resourcePath, this.generateContent({}, {}, session.language), session.language));
}
if (!PhoneNumberValidator.validateMobilePhoneNumber(ctx.mobile)) {
errors.push(FieldError('mobile', 'invalid', this.resourcePath, this.generateContent({}, {}, session.language), session.language));
const validationResult = PhoneNumberValidator.validateMobilePhoneNumber(ctx.mobile);
if (!validationResult.isValid) {
errors.push(FieldError('mobile', validationResult.errorType, this.resourcePath, this.generateContent({}, {}, session.language), session.language));
}

if (executorsWrapper.executorPhoneNumberAlreadyUsed(ctx.mobile, executor.fullName, formdata.applicant.phoneNumber)) {
errors.push(FieldError('mobile', 'duplicate', this.resourcePath, this.generateContent({}, {}, session.language), session.language));
}

if (ctx.email !== executor.email && (executor.emailSent || executor.inviteId)) {
executor.emailChanged = true;
}
Expand Down
2 changes: 1 addition & 1 deletion app/steps/ui/executors/contactdetails/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"mobile": {
"type": "string",
"minLength": 11,
"maxLength": 13
"maxItems": 16
}
},
"required": [
Expand Down
33 changes: 10 additions & 23 deletions app/utils/PhoneNumberValidator.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
class PhoneNumberValidator {
static validateMobilePhoneNumber(num) {
const ukNumberMatchRE = new RegExp(/^7[0-9]{9}$/);
const ukPrefix = '44';
const internationalMatchRE = new RegExp(/^[0-9]*$/);

if (num.startsWith('+')) {
let toValidate = num.slice(1);
if (toValidate.startsWith(ukPrefix)) {
toValidate = toValidate.slice(2);
if (toValidate.match(ukNumberMatchRE)) {
return true;
}
} else if (toValidate.match(internationalMatchRE)) {
return true;
}
}
const parsePhoneNumber = require('libphonenumber-js/mobile').parsePhoneNumber;

if (num.startsWith('07')) {
const toValidate = num.slice(1);
if (toValidate.match(ukNumberMatchRE)) {
return true;
class PhoneNumberValidator {
static validateMobilePhoneNumber(phoneNumber) {
try {
const parsedPhoneNumber = parsePhoneNumber(phoneNumber, 'GB');
if (parsedPhoneNumber && parsedPhoneNumber.isValid()) {
return {isValid: true};
}
return {isValid: false, errorType: 'invalid'};
} catch (error) {
return {isValid: false, errorType: 'invalid'};
}

return false;
}
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
"js-yaml": "^4.0.0",
"jsdom": "^26.0.0",
"launchdarkly-node-server-sdk": "^7.0.0",
"libphonenumber-js": "^1.11.17",
"lodash": "^4.17.21",
"mocha-lcov-reporter": "^1.3.0",
"moment": "^2.29.4",
Expand Down
188 changes: 137 additions & 51 deletions test/unit/utils/testPhoneNumberValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,147 @@ const expect = require('chai').expect;

describe('PhoneNumberValidator.js', () => {
describe('validateUKMobilePhoneNumber()', () => {
it('should return failure for invalid number', (done) => {
const phoneNumber = '0208 863 8689';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
describe('Base Case', () => {
it('should return true to validate number for testing purposes', (done) => {
const phoneNumber = '07123456789';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
});
it('should return failure for invalid chars', (done) => {
const phoneNumber = 'abcdef';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return failure for invalid spces', (done) => {
const phoneNumber = ' 07958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return failure for uk landline number', (done) => {
const phoneNumber = '02088638689';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return fail for uk mobile number INTL staring with 00', (done) => {
const phoneNumber = '00447958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return failure for bad format uk mobile number', (done) => {
const phoneNumber = '+44 7958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return failure for invalid uk mobile number', (done) => {
const phoneNumber = '08958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(false);
done();
});
it('should return pass for uk mobile number INTL', (done) => {
const phoneNumber = '+447958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(true);
done();
});
it('should return pass for overseas mobile number', (done) => {
const phoneNumber = '+337958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(true);
done();

describe('Length Validation', () => {
it('should return false for not meeting minimum length', (done) => {
const phoneNumber = '020 1234';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return false for exceeding maximum length', (done) => {
const phoneNumber = '020 12345 6789 10 11';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return true for acceptable length (11 chars)', (done) => {
const phoneNumber = '07123456789';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for acceptable length (15 chars)', (done) => {
const phoneNumber = '+4917642010039';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return false for invalid mobile number', (done) => {
const phoneNumber = '+179589953302345234';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
});
it('should return pass for uk mobile number', (done) => {
const phoneNumber = '07958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(true);
done();

describe('Alphanumeric Input Validation', () => {
it('should return false for invalid input', (done) => {
const phoneNumber = 'INVALID_INPUT';
const validationResult = PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber);
const expectedResult = {'isValid': false, 'errorType': 'invalid'};
expect(validationResult).to.deep.equal(expectedResult);
done();
});
it('should return true for hyphens input', (done) => {
const phoneNumber = '07-1234-56789';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for spaces input', (done) => {
const phoneNumber = '07 1234 56789';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return false for invalid chars', (done) => {
const phoneNumber = 'abcdef';
const validationResult = PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber);
const expectedResult = {'isValid': false, 'errorType': 'invalid'};
expect(validationResult).to.deep.equal(expectedResult);
done();
});
});
it('should return pass for international mobile number', (done) => {
const phoneNumber = '+179589953302345234';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.equal(true);
done();

describe('International Number Validation', () => {
it('should return true for international number (French)', (done) => {
const phoneNumber = '+33 6 12 34 56 78';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for overseas mobile number', (done) => {
const phoneNumber = '+33 7 58 99 53 30';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for British with country code', (done) => {
const phoneNumber = '+44 7911 123456';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return false for invalid country code', (done) => {
const phoneNumber = '+999 6 12 34 56 78';
const validationResult = PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber);
const expectedResult = {'isValid': false, 'errorType': 'invalid'};
expect(validationResult).to.deep.equal(expectedResult);
done();
});
it('should return false for missing country code', (done) => {
const phoneNumber = '+ 6 12 34 56 78';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return false invalid international number', (done) => {
const phoneNumber = '+44-7911-12345';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
});

describe('General Validation Tests', () => {
it('should return false for invalid number', (done) => {
const phoneNumber = '0208 863 8689';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return false for uk landline number', (done) => {
const phoneNumber = '02088638689';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return false for invalid uk mobile number', (done) => {
const phoneNumber = '08958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: false, errorType: 'invalid'});
done();
});
it('should return true for uk mobile number INTL', (done) => {
const phoneNumber = '+447958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for uk mobile number', (done) => {
const phoneNumber = '07958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
//The following are edited tests which failed under previous validation
it('should return true for spaces', (done) => {
const phoneNumber = ' 07958995330 ';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for uk mobile number INTL staring with 00', (done) => {
const phoneNumber = '00447958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});
it('should return true for spaced format uk mobile number', (done) => {
const phoneNumber = '+44 7958995330';
expect(PhoneNumberValidator.validateMobilePhoneNumber(phoneNumber)).to.deep.equal({isValid: true});
done();
});

});
});
});
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10340,6 +10340,13 @@ __metadata:
languageName: node
linkType: hard

"libphonenumber-js@npm:^1.11.17":
version: 1.11.17
resolution: "libphonenumber-js@npm:1.11.17"
checksum: 10/e8e897834822060fe3067fc573a76f94eb0fbcc1ac075e3fdd9e1870b0c68f7c20f2bc50053ceeb69364fc3a8b881395bd121d904c38f716c4b69c3382b8f011
languageName: node
linkType: hard

"lie@npm:~3.3.0":
version: 3.3.0
resolution: "lie@npm:3.3.0"
Expand Down Expand Up @@ -13489,6 +13496,7 @@ __metadata:
js-yaml: "npm:^4.0.0"
jsdom: "npm:^26.0.0"
launchdarkly-node-server-sdk: "npm:^7.0.0"
libphonenumber-js: "npm:^1.11.17"
lodash: "npm:^4.17.21"
mocha: "npm:^11.0.0"
mocha-jenkins-reporter: "npm:^0.4.8"
Expand Down