feat(sms): Enable SMS in Belgium, France, Luxembourg (#5698) r=@philbooth
Monaco is not yet enabled, I have not found a phone number that validates. I was being too clever with the phone number validation and was looking for mobile prefixes. At the same time, I had the validation logic wrong. For many European countries a trunk line prefix of `0` can be specified IFF the country code prefix is not specified. For BE, FR, and GB, I erroneously allowed the user to delete the country code prefix, but did not force the trunk prefix. This is fixed. @philbooth also noticed that the unit tests for the module were exploding as more countries are added. He suggested that I convert the tests to be table driven, which condenses the tests quite a bit. issue #5573
This commit is contained in:
Родитель
38688e0940
Коммит
83dc5ed9af
|
@ -84,6 +84,15 @@ define((require, exports, module) => {
|
||||||
prefix: '+43',
|
prefix: '+43',
|
||||||
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=AT`
|
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=AT`
|
||||||
},
|
},
|
||||||
|
// Belgium
|
||||||
|
// https://en.wikipedia.org/wiki/Telephone_numbers_in_Belgium
|
||||||
|
BE: {
|
||||||
|
format: formatter('+32 ${serverPhoneNumber}'),
|
||||||
|
normalize: ensurePrefix('+32'),
|
||||||
|
pattern: /^(?:\+32\d{9}|\d{10})$/,
|
||||||
|
prefix: '+32',
|
||||||
|
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=DE`
|
||||||
|
},
|
||||||
// Germany
|
// Germany
|
||||||
// https://en.wikipedia.org/wiki/Telephone_numbers_in_Germany
|
// https://en.wikipedia.org/wiki/Telephone_numbers_in_Germany
|
||||||
DE: {
|
DE: {
|
||||||
|
@ -93,12 +102,29 @@ define((require, exports, module) => {
|
||||||
prefix: '+49',
|
prefix: '+49',
|
||||||
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=DE`
|
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=DE`
|
||||||
},
|
},
|
||||||
|
// France
|
||||||
|
// https://en.wikipedia.org/wiki/Telephone_numbers_in_France
|
||||||
|
FR: {
|
||||||
|
format: formatter('+33 ${serverPhoneNumber}'),
|
||||||
|
normalize: ensurePrefix('+33'),
|
||||||
|
pattern: /^(?:\+33\d{9}|\d{10})$/,
|
||||||
|
prefix: '+33',
|
||||||
|
rolloutRate: 0 // being soft launched. Testers will need to open `/sms?service=sync&country=DE`
|
||||||
|
},
|
||||||
GB: {
|
GB: {
|
||||||
format: formatter('+44 ${serverPhoneNumber}'),
|
format: formatter('+44 ${serverPhoneNumber}'),
|
||||||
normalize: ensurePrefix('+44'),
|
normalize: ensurePrefix('+44'),
|
||||||
pattern: /^(?:\+44)?\d{10,10}$/,
|
pattern: /^(?:\+44\d{10}|\d{11})$/,
|
||||||
prefix: '+44'
|
prefix: '+44'
|
||||||
},
|
},
|
||||||
|
// Luxembourg
|
||||||
|
// https://en.wikipedia.org/wiki/Telephone_numbers_in_Luxembourg
|
||||||
|
LU: {
|
||||||
|
format: formatter('+352 ${serverPhoneNumber}'),
|
||||||
|
normalize: ensurePrefix('+352'),
|
||||||
|
pattern: /^(?:\+352)?\d{9}$/,
|
||||||
|
prefix: '+352'
|
||||||
|
},
|
||||||
RO: {
|
RO: {
|
||||||
format: formatter('+40 ${serverPhoneNumber}'),
|
format: formatter('+40 ${serverPhoneNumber}'),
|
||||||
normalize(num) {
|
normalize(num) {
|
||||||
|
|
|
@ -9,147 +9,227 @@ define((require, exports, module) => {
|
||||||
const CountryTelephoneInfo = require('lib/country-telephone-info');
|
const CountryTelephoneInfo = require('lib/country-telephone-info');
|
||||||
|
|
||||||
describe('lib/country-telephone-info', () => {
|
describe('lib/country-telephone-info', () => {
|
||||||
|
/**
|
||||||
|
* An entry per country. `format` and `normalize`
|
||||||
|
* use the entry key as input, and entry value as output.
|
||||||
|
*
|
||||||
|
* To avoid duplicating validation logic between front and
|
||||||
|
* back ends, very little validation is done on the front end,
|
||||||
|
* primarily length validation. The back end uses a much
|
||||||
|
* more full featured library to validate numbers and will reject
|
||||||
|
* a phone number it views as invalid.
|
||||||
|
*/
|
||||||
|
/* eslint-disable sorting/sort-object-props */
|
||||||
|
const testData = {
|
||||||
|
// Austria
|
||||||
|
AT: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '+43 1234567890'
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+431234567890': '+431234567890',
|
||||||
|
'1234567890': '+431234567890'
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'123456',
|
||||||
|
'+43123456'
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
// wrong country code
|
||||||
|
'+331234567890'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Belgium
|
||||||
|
BE: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '+32 1234567890'
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+32123456789': '+32123456789',
|
||||||
|
'1234567890': '+321234567890'
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'1234567890',
|
||||||
|
'+32123456789'
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
// too short
|
||||||
|
'123456789',
|
||||||
|
'+3212345678',
|
||||||
|
|
||||||
describe('AT', () => {
|
// too long
|
||||||
const { format, normalize, pattern } = CountryTelephoneInfo.AT;
|
'12345678901',
|
||||||
|
'+321234567890',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Germany
|
||||||
|
DE: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '+49 1234567890'
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+491234567890': '+491234567890',
|
||||||
|
'1234567890': '+491234567890'
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'123456',
|
||||||
|
'1234567890123',
|
||||||
|
'+49123456',
|
||||||
|
'+491234567890123'
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
'+331234567890'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// France
|
||||||
|
FR: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '+33 1234567890'
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+33123456789': '+33123456789',
|
||||||
|
'1234567890': '+331234567890'
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'1234567890',
|
||||||
|
'+33123456789'
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
// too short
|
||||||
|
'123456789',
|
||||||
|
'+3312345678',
|
||||||
|
|
||||||
describe('format', () => {
|
// too long
|
||||||
it('formats correctly', () => {
|
'12345678901',
|
||||||
assert.equal(format('1234567890'), '+43 1234567890');
|
'+331234567890',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Great Britain
|
||||||
|
GB: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '+44 1234567890',
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+441234567890': '+441234567890',
|
||||||
|
'1234567890': '+441234567890',
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'12345678901',
|
||||||
|
'+441234567890',
|
||||||
|
'07775556372'
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
'+331234567890',
|
||||||
|
'+44123456789',
|
||||||
|
// trunk 0 not allowed w/ country code prefix
|
||||||
|
'+4407775551234',
|
||||||
|
'123456789',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Luxembourg
|
||||||
|
LU: {
|
||||||
|
format: {
|
||||||
|
'621123456': '+352 621123456',
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+352123456789': '+352123456789',
|
||||||
|
'123456789': '+352123456789',
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'123456789',
|
||||||
|
'+352123456789',
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
// too short
|
||||||
|
'12345678',
|
||||||
|
'+35212345678',
|
||||||
|
|
||||||
|
// too long
|
||||||
|
'1234567890',
|
||||||
|
'+3521234567890',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Romania
|
||||||
|
RO: {
|
||||||
|
format: {
|
||||||
|
'712345678': '+40 712345678',
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'712345678': '+40712345678', // no country code prefix
|
||||||
|
'0712345678': '+40712345678', // no country code prefix, extra 0 before the 7
|
||||||
|
'+40712345678': '+40712345678', // full country code prefix
|
||||||
|
'+400712345678': '+40712345678', // full country code prefix, extra 0 before the 7
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'712345678',
|
||||||
|
'0712345678', // allow leading 0
|
||||||
|
'+40712345678', // full country code prefix
|
||||||
|
'+400712345678', // full country code prefix with 0 before 7
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
'71234567', // too short
|
||||||
|
'7123456789', // too long
|
||||||
|
'812345678', // invalid prefix (must be 7)
|
||||||
|
'+45712345678', // incorrect country code prefix
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// United States & Canada
|
||||||
|
US: {
|
||||||
|
format: {
|
||||||
|
'1234567890': '1234567890',
|
||||||
|
},
|
||||||
|
normalize: {
|
||||||
|
'+11234567890': '+11234567890', // full country code prefix
|
||||||
|
'11234567890': '+11234567890', // country code prefix w/o +
|
||||||
|
'1234567890': '+11234567890', // no country code prefix
|
||||||
|
},
|
||||||
|
validPatterns: [
|
||||||
|
'2134567890',
|
||||||
|
'+12134567890', // full country code prefix
|
||||||
|
'12134567890', // country code prefix w/o +
|
||||||
|
'15234567890',
|
||||||
|
],
|
||||||
|
invalidPatterns: [
|
||||||
|
'+332134567890',
|
||||||
|
'+1213456789',
|
||||||
|
'213456789',
|
||||||
|
'1213456789',
|
||||||
|
'1123456789', // can't start an area code with 1
|
||||||
|
'11234567890', // can't start an area code with 1
|
||||||
|
'121345678901', // too long, has country prefix
|
||||||
|
'21345678901', // too long, no country prefix
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* eslint-enable sorting/sort-object-props */
|
||||||
|
|
||||||
|
Object.keys(testData).forEach((countryCode) => {
|
||||||
|
describe(countryCode, () => {
|
||||||
|
const { format, normalize, pattern } = CountryTelephoneInfo[countryCode];
|
||||||
|
const countryTelephoneTestData = testData[countryCode];
|
||||||
|
|
||||||
|
it('format formats correctly', () => {
|
||||||
|
Object.keys(countryTelephoneTestData.format).forEach((input) => {
|
||||||
|
assert.equal(format(input), countryTelephoneTestData.format[input]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalize', () => {
|
it('normalize normalizes a number accepted by pattern correctly', () => {
|
||||||
it('normalizes a number accepted by pattern correctly', () => {
|
Object.keys(countryTelephoneTestData.normalize).forEach((input) => {
|
||||||
assert.equal(normalize('+431234567890'), '+431234567890');
|
assert.equal(normalize(input), countryTelephoneTestData.normalize[input]);
|
||||||
assert.equal(normalize('1234567890'), '+431234567890');
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('pattern', () => {
|
it('accepts valid patterns', () => {
|
||||||
it('validates correctly', () => {
|
countryTelephoneTestData.validPatterns.forEach((input) => {
|
||||||
assert.ok(pattern.test('123456'));
|
assert.isTrue(pattern.test(input));
|
||||||
assert.ok(pattern.test('+43123456'));
|
});
|
||||||
assert.isFalse(pattern.test('+331234567890'));
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('DE', () => {
|
it('rejects invalid patterns', () => {
|
||||||
const { format, normalize, pattern } = CountryTelephoneInfo.DE;
|
countryTelephoneTestData.invalidPatterns.forEach((input) => {
|
||||||
|
assert.isFalse(pattern.test(input));
|
||||||
describe('format', () => {
|
});
|
||||||
it('formats correctly', () => {
|
|
||||||
assert.equal(format('1234567890'), '+49 1234567890');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalize', () => {
|
|
||||||
it('normalizes a number accepted by pattern correctly', () => {
|
|
||||||
assert.equal(normalize('+491234567890'), '+491234567890');
|
|
||||||
assert.equal(normalize('1234567890'), '+491234567890');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pattern', () => {
|
|
||||||
it('validates correctly', () => {
|
|
||||||
assert.ok(pattern.test('123456'));
|
|
||||||
assert.ok(pattern.test('1234567890123'));
|
|
||||||
assert.ok(pattern.test('+49123456'));
|
|
||||||
assert.ok(pattern.test('+491234567890123'));
|
|
||||||
assert.isFalse(pattern.test('+331234567890'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('GB', () => {
|
|
||||||
const { format, normalize, pattern } = CountryTelephoneInfo.GB;
|
|
||||||
|
|
||||||
describe('format', () => {
|
|
||||||
it('formats correctly', () => {
|
|
||||||
assert.equal(format('1234567890'), '+44 1234567890');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalize', () => {
|
|
||||||
it('normalizes a number accepted by pattern correctly', () => {
|
|
||||||
assert.equal(normalize('+441234567890'), '+441234567890');
|
|
||||||
assert.equal(normalize('1234567890'), '+441234567890');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pattern', () => {
|
|
||||||
it('validates correctly', () => {
|
|
||||||
assert.ok(pattern.test('1234567890'));
|
|
||||||
assert.ok(pattern.test('+441234567890'));
|
|
||||||
assert.isFalse(pattern.test('+331234567890'));
|
|
||||||
assert.isFalse(pattern.test('+4401234567890')); // that leading 0 kills me.
|
|
||||||
assert.isFalse(pattern.test('+44123456789'));
|
|
||||||
assert.isFalse(pattern.test('123456789'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('RO', () => {
|
|
||||||
const { format, normalize, pattern } = CountryTelephoneInfo.RO;
|
|
||||||
|
|
||||||
it('formats correctly', () => {
|
|
||||||
assert.equal(format('712345678'), '+40 712345678');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalize', () => {
|
|
||||||
it('normalizes a number accepted by pattern correctly', () => {
|
|
||||||
assert.equal(normalize('712345678'), '+40712345678'); // no country code prefix
|
|
||||||
assert.equal(normalize('0712345678'), '+40712345678'); // no country code prefix, extra 0 before the 7
|
|
||||||
assert.equal(normalize('+40712345678'), '+40712345678'); // full country code prefix
|
|
||||||
assert.equal(normalize('+400712345678'), '+40712345678'); // full country code prefix, extra 0 before the 7
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pattern', () => {
|
|
||||||
it('validates correctly', () => {
|
|
||||||
assert.isFalse(pattern.test('71234567')); // too short
|
|
||||||
assert.isFalse(pattern.test('7123456789')); // too long
|
|
||||||
assert.isFalse(pattern.test('812345678')); // invalid prefix (must be 7)
|
|
||||||
|
|
||||||
assert.ok(pattern.test('712345678'));
|
|
||||||
assert.ok(pattern.test('0712345678')); // allow leading 0
|
|
||||||
assert.ok(pattern.test('+40712345678')); // full country code prefix
|
|
||||||
assert.ok(pattern.test('+400712345678')); // full country code prefix with 0 before 7
|
|
||||||
assert.isFalse(pattern.test('+45712345678')); // incorrect country code prefix
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('US', () => {
|
|
||||||
const { format, normalize, pattern } = CountryTelephoneInfo.US;
|
|
||||||
|
|
||||||
it('formats correctly', () => {
|
|
||||||
assert.equal(format('1234567890'), '1234567890');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalize', () => {
|
|
||||||
it('normalizes a number accepted by pattern correctly', () => {
|
|
||||||
assert.equal(normalize('+11234567890'), '+11234567890'); // full country code prefix
|
|
||||||
assert.equal(normalize('11234567890'), '+11234567890'); // country code prefix w/o +
|
|
||||||
assert.equal(normalize('1234567890'), '+11234567890'); // no country code prefix
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pattern', () => {
|
|
||||||
it('validates correctly', () => {
|
|
||||||
assert.ok(pattern.test('2134567890'));
|
|
||||||
assert.ok(pattern.test('+12134567890')); // full country code prefix
|
|
||||||
assert.ok(pattern.test('12134567890')); // country code prefix w/o +
|
|
||||||
assert.ok(pattern.test('15234567890'));
|
|
||||||
assert.isFalse(pattern.test('+332134567890'));
|
|
||||||
assert.isFalse(pattern.test('+1213456789'));
|
|
||||||
assert.isFalse(pattern.test('213456789'));
|
|
||||||
assert.isFalse(pattern.test('1213456789'));
|
|
||||||
assert.isFalse(pattern.test('1123456789')); // can't start an area code with 1
|
|
||||||
assert.isFalse(pattern.test('11234567890')); // can't start an area code with 1
|
|
||||||
assert.isFalse(pattern.test('121345678901')); // too long, has country prefix
|
|
||||||
assert.isFalse(pattern.test('21345678901')); // too long, no country prefix
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -103,7 +103,7 @@ define(function (require, exports, module) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not throw if valid', () => {
|
it('does not throw if valid', () => {
|
||||||
assert.isUndefined(validate($requiredTelEl, '1234567890'));
|
assert.isUndefined(validate($requiredTelEl, '12345678901'));
|
||||||
assert.isUndefined(validate($requiredTelEl, '+441234567890'));
|
assert.isUndefined(validate($requiredTelEl, '+441234567890'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,9 +109,12 @@ define([
|
||||||
},
|
},
|
||||||
|
|
||||||
'with `country=AT`': testSmsSupportedCountryForm('AT', '+43'),
|
'with `country=AT`': testSmsSupportedCountryForm('AT', '+43'),
|
||||||
|
'with `country=BE`': testSmsSupportedCountryForm('BE', '+32'),
|
||||||
'with `country=CA`': testSmsSupportedCountryForm('CA', ''),
|
'with `country=CA`': testSmsSupportedCountryForm('CA', ''),
|
||||||
'with `country=DE`': testSmsSupportedCountryForm('DE', '+49'),
|
'with `country=DE`': testSmsSupportedCountryForm('DE', '+49'),
|
||||||
|
'with `country=FR`': testSmsSupportedCountryForm('FR', '+33'),
|
||||||
'with `country=GB`': testSmsSupportedCountryForm('GB', '+44'),
|
'with `country=GB`': testSmsSupportedCountryForm('GB', '+44'),
|
||||||
|
'with `country=LU`': testSmsSupportedCountryForm('LU', '+352'),
|
||||||
'with `country=RO`': testSmsSupportedCountryForm('RO', '+40'),
|
'with `country=RO`': testSmsSupportedCountryForm('RO', '+40'),
|
||||||
'with `country=US`': testSmsSupportedCountryForm('US', ''),
|
'with `country=US`': testSmsSupportedCountryForm('US', ''),
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче