fix(input-tel): rename and export PhoneNumber validator

This commit is contained in:
Thijs Louisse 2022-03-21 23:04:45 +01:00 committed by Thijs Louisse
parent 7c5a25d011
commit 5d5f041ab9
11 changed files with 49 additions and 47 deletions

View file

@ -25,7 +25,7 @@ import { LionInputTel } from '@lion/input-tel';
* @typedef {import('../types').OnDropdownChangeEvent} OnDropdownChangeEvent
* @typedef {import('../types').DropdownRef} DropdownRef
* @typedef {import('../types').RegionMeta} RegionMeta
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
* @typedef {import('@lion/select-rich').LionSelectRich} LionSelectRich
* @typedef {import('@lion/overlays').OverlayController} OverlayController
* @typedef {TemplateDataForDropdownInputTel & {data: {regionMetaList:RegionMeta[]}}} TemplateDataForIntlInputTel

View file

@ -41,6 +41,7 @@ class WithFormControlInputTelDropdown extends LionInputTelDropdown {
};
}
// @ts-expect-error
runInputTelSuite({ klass: LionInputTelDropdown });
runInputTelDropdownSuite();

View file

@ -1,3 +1,4 @@
export { LionInputTel } from './src/LionInputTel.js';
export { PhoneNumber } from './src/validators.js';
export { PhoneUtilManager } from './src/PhoneUtilManager.js';
export { liveFormatPhoneNumber } from './src/preprocessors.js';

View file

@ -5,14 +5,14 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
import { liveFormatPhoneNumber } from './preprocessors.js';
import { formatPhoneNumber } from './formatters.js';
import { parsePhoneNumber } from './parsers.js';
import { IsPhoneNumber } from './validators.js';
import { PhoneNumber } from './validators.js';
/**
* @typedef {import('../types').FormatStrategy} FormatStrategy
* @typedef {import('../types').RegionCode} RegionCode
* @typedef {import('../types').PhoneNumberType} PhoneNumberType
* @typedef {import('@lion/form-core/types/FormatMixinTypes').FormatOptions} FormatOptions
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
* @typedef {FormatOptions & {regionCode: RegionCode; formatStrategy: FormatStrategy}} FormatOptionsTel
*/
@ -131,17 +131,17 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
this.allowedRegions = [];
/** @private */
this.__isPhoneNumberValidatorInstance = new IsPhoneNumber();
this.__isPhoneNumberValidatorInstance = new PhoneNumber();
/** @configures ValidateMixin */
this.defaultValidators.push(this.__isPhoneNumberValidatorInstance);
// Expose awesome-phonenumber lib for Subclassers
/**
* @protected
* @type {PhoneNumber|null}
* @type {AwesomePhoneNumber|null}
*/
this._phoneUtil = PhoneUtilManager.isLoaded
? /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber)
? /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil)
: null;
/**
@ -270,7 +270,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
*/
_onPhoneNumberUtilReady() {
// This should trigger a rerender in shadow dom
this._phoneUtil = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber);
this._phoneUtil = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneUtil);
// This should trigger a rerender in light dom
this._scheduleLightDomRender();
// Format when libPhoneNumber is loaded

View file

@ -9,17 +9,17 @@ let resolveLoaded;
*/
export class PhoneUtilManager {
static async loadLibPhoneNumber() {
const PhoneNumber = (await import('../lib/awesome-phonenumber-esm.js')).default;
this.PhoneNumber = PhoneNumber;
const PhoneUtil = (await import('../lib/awesome-phonenumber-esm.js')).default;
this.PhoneUtil = PhoneUtil;
resolveLoaded(undefined);
return PhoneNumber;
return PhoneUtil;
}
/**
* Check if google-libphonenumber has been loaded
*/
static get isLoaded() {
return Boolean(this.PhoneNumber);
return Boolean(this.PhoneUtil);
}
}

View file

@ -3,7 +3,7 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
/**
* @typedef {import('../types').FormatStrategy} FormatStrategy
* @typedef {import('../types').RegionCode} RegionCode
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
*/
/**
@ -20,11 +20,11 @@ export function formatPhoneNumber(modelValue, { regionCode, formatStrategy = 'in
}
// eslint-disable-next-line prefer-destructuring
const PhoneNumber = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber);
const PhoneUtil = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil);
let pn;
try {
pn = new PhoneNumber(modelValue, regionCode); // phoneNumberUtil.parse(modelValue, regionCode);
pn = new PhoneUtil(modelValue, regionCode);
// eslint-disable-next-line no-empty
} catch (_) {}

View file

@ -2,7 +2,7 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
/**
* @typedef {import('../types').RegionCode} RegionCode
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
*/
/**
@ -17,7 +17,7 @@ export function parsePhoneNumber(viewValue, { regionCode }) {
}
// eslint-disable-next-line prefer-destructuring
const PhoneNumber = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber);
const PhoneNumber = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil);
let pn;
try {

View file

@ -4,7 +4,7 @@ import { formatPhoneNumber } from './formatters.js';
/**
* @typedef {import('../types').FormatStrategy} FormatStrategy
* @typedef {import('../types').RegionCode} RegionCode
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
*/
/**
@ -27,7 +27,7 @@ export function liveFormatPhoneNumber(
}
// eslint-disable-next-line prefer-destructuring
const PhoneNumber = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber);
const PhoneNumber = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil);
const ayt = PhoneNumber.getAsYouType(regionCode);
for (const char of viewValue) {

View file

@ -3,7 +3,7 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
/**
* @typedef {import('../types').RegionCode} RegionCode
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
*/
/**
@ -13,7 +13,7 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
*/
function hasFeedback(modelValue, regionCode) {
// eslint-disable-next-line prefer-destructuring
const PhoneNumber = /** @type {PhoneNumber} */ (PhoneUtilManager.PhoneNumber);
const PhoneNumber = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil);
let invalidCountryCode = false;
if (regionCode && modelValue?.length >= 4 && modelValue?.length <= 16) {
@ -37,8 +37,8 @@ function hasFeedback(modelValue, regionCode) {
return 'unknown';
}
export class IsPhoneNumber extends Validator {
static validatorName = 'IsPhoneNumber';
export class PhoneNumber extends Validator {
static validatorName = 'PhoneNumber';
static get async() {
// Will be run as async the first time if PhoneUtilManager hasn't loaded yet, sync afterwards

View file

@ -11,7 +11,7 @@ import sinon from 'sinon';
import { mimicUserInput } from '@lion/form-core/test-helpers';
import { localize } from '@lion/localize';
import { LionInputTel } from '../src/LionInputTel.js';
import { IsPhoneNumber } from '../src/validators.js';
import { PhoneNumber } from '../src/validators.js';
import { PhoneUtilManager } from '../src/PhoneUtilManager.js';
import {
mockPhoneUtilManager,
@ -97,7 +97,7 @@ function runActiveRegionTests({ tag, phoneUtilLoadedAfterInit }) {
]}" .modelValue="${'+31612345678'}" ></${tag}> `,
);
if (resolvePhoneUtilLoaded) {
resolvePhoneUtilLoaded();
resolvePhoneUtilLoaded(undefined);
await el.updateComplete;
}
expect(el.activeRegion).to.equal('NL');
@ -287,18 +287,18 @@ export function runInputTelSuite({ klass = LionInputTel } = {}) {
});
describe('Validation', () => {
it('applies IsPhoneNumber as default validator', async () => {
it('applies PhoneNumber as default validator', async () => {
const el = await fixture(html` <${tag}></${tag}> `);
expect(el.defaultValidators.find(v => v instanceof IsPhoneNumber)).to.be.not.undefined;
expect(el.defaultValidators.find(v => v instanceof PhoneNumber)).to.be.not.undefined;
});
it('configures IsPhoneNumber with regionCode before first validation', async () => {
it('configures PhoneNumber with regionCode before first validation', async () => {
const el = fixtureSync(
html` <${tag} .allowedRegions="${['NL']}" .modelValue="${'612345678'}"></${tag}> `,
);
const spy = sinon.spy(el, 'validate');
const validatorInstance = /** @type {IsPhoneNumber} */ (
el.defaultValidators.find(v => v instanceof IsPhoneNumber)
const validatorInstance = /** @type {PhoneNumber} */ (
el.defaultValidators.find(v => v instanceof PhoneNumber)
);
await el.updateComplete;
expect(validatorInstance.param).to.equal('NL');
@ -306,12 +306,12 @@ export function runInputTelSuite({ klass = LionInputTel } = {}) {
spy.restore();
});
it('updates IsPhoneNumber param on regionCode change', async () => {
it('updates PhoneNumber param on regionCode change', async () => {
const el = await fixture(
html` <${tag} .allowedRegions="${['NL']}" .modelValue="${'612345678'}"></${tag}> `,
);
const validatorInstance = /** @type {IsPhoneNumber} */ (
el.defaultValidators.find(v => v instanceof IsPhoneNumber)
const validatorInstance = /** @type {PhoneNumber} */ (
el.defaultValidators.find(v => v instanceof PhoneNumber)
);
// @ts-expect-error allow protected in tests
el._setActiveRegion('DE');

View file

@ -1,6 +1,6 @@
import sinon from 'sinon';
import { expect, aTimeout } from '@open-wc/testing';
import { IsPhoneNumber } from '../src/validators.js';
import { PhoneNumber } from '../src/validators.js';
import { PhoneUtilManager } from '../src/PhoneUtilManager.js';
import {
mockPhoneUtilManager,
@ -8,52 +8,52 @@ import {
} from '../test-helpers/mockPhoneUtilManager.js';
/**
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} PhoneNumber
* @typedef {* & import('@lion/input-tel/lib/awesome-phonenumber-esm').default} AwesomePhoneNumber
*/
// For enum output, see: https://www.npmjs.com/package/awesome-phonenumber
describe('IsPhoneNumber validation', () => {
describe('PhoneNumber validation', () => {
beforeEach(async () => {
// Wait till PhoneUtilManager has been loaded
await PhoneUtilManager.loadComplete;
});
it('is invalid when no input is provided', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
expect(validator.execute('', 'NL')).to.equal('unknown');
});
it('is invalid when non digits are entered, returns "unknown"', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
expect(validator.execute('foo', 'NL')).to.equal('unknown');
});
it('is invalid when wrong country code is entered, returns "invalid-country-code"', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
// 32 is BE region code
expect(validator.execute('+32612345678', 'NL')).to.equal('invalid-country-code');
});
// TODO: find out why awesome-phonenumber does not detect too-short/too-long
it.skip('is invalid when number is too short, returns "too-short"', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
expect(validator.execute('+3161234567', 'NL')).to.equal('too-short');
});
// TODO: find out why awesome-phonenumber does not detect too-short/too-long
it.skip('is invalid when number is too long, returns "too-long"', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
expect(validator.execute('+316123456789', 'NL')).to.equal('too-long');
});
it('is valid when a phone number is entered', () => {
const validator = new IsPhoneNumber();
const validator = new PhoneNumber();
expect(validator.execute('+31612345678', 'NL')).to.be.false;
});
it('handles validation via awesome-phonenumber', () => {
const validator = new IsPhoneNumber();
const spy = sinon.spy(PhoneUtilManager, 'PhoneNumber');
const validator = new PhoneNumber();
const spy = sinon.spy(PhoneUtilManager, 'PhoneUtil');
validator.execute('0123456789', 'NL');
expect(spy).to.have.been.calledOnce;
expect(spy.lastCall.args[1]).to.equal('NL');
@ -74,14 +74,14 @@ describe('IsPhoneNumber validation', () => {
});
it('behaves asynchronously when lib is still loading', () => {
expect(IsPhoneNumber.async).to.be.true;
expect(PhoneNumber.async).to.be.true;
resolveLoaded(undefined);
expect(IsPhoneNumber.async).to.be.false;
expect(PhoneNumber.async).to.be.false;
});
it('waits for the lib to be loaded before execution completes when still in async mode', async () => {
const validator = new IsPhoneNumber();
const spy = sinon.spy(PhoneUtilManager, 'PhoneNumber');
const validator = new PhoneNumber();
const spy = sinon.spy(PhoneUtilManager, 'PhoneUtil');
const validationResult = validator.execute('061234', 'NL');
expect(validationResult).to.be.instanceOf(Promise);
expect(spy).to.not.have.been.called;