Skip to content

Commit

Permalink
[HDSG-215] Fix errors thrown when unmasking field with no numbers (#276)
Browse files Browse the repository at this point in the history
* Attempting to unmask a field that has only non-numeric characters threw errors. That's fixed now.

* Return an empty string rather than null

* A more robust toNumber function

* Remove the compiled file

* More tests for mixed garbage-numeric input
  • Loading branch information
pwolfert authored Oct 1, 2018
1 parent 752e14f commit dfa8748
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
44 changes: 35 additions & 9 deletions packages/core/src/components/TextField/Mask.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,45 @@ function stringWithFixedDigits(value, digits = 2) {
}

/**
* Remove all non-digits
* Remove everything that isn't a digit or asterisk
* @param {String} value
* @returns {String}
*/
function toDigitsAndAsterisks(value) {
return value.replace(/[^\d*]/g, '');
}

/**
* Remove all non-digits
* @param {String} value
* @returns {String}
*/
function toDigits(value) {
return value.replace(/[^\d]/g, '');
}

/**
* Convert string into a number (positive or negative float or integer)
* @param {String} value
* @returns {Number}
*/
function toNumber(value) {
if (typeof value !== 'string') return value;
if (!value.match(/\d/)) return undefined;

// 0 = number, 1 = decimals
const sign = value.charAt(0) === '-' ? -1 : 1;
const parts = value.split('.');
const digitsRegex = /^-|\d/g; // include a check for a beginning "-" for negative numbers
const a = parts[0].match(digitsRegex).join('');
const b = parts.length >= 2 && parts[1].match(digitsRegex).join('');

return b ? parseFloat(`${a}.${b}`) : parseInt(a);
// This assumes if the user adds a "." it should be a float. If we want it to
// evaluate as an integer if there are no digits beyond the decimal, then we
// can change it.
const hasDecimal = parts[1] !== undefined;
if (hasDecimal) {
const a = toDigits(parts[0]);
const b = toDigits(parts[1]);
return sign * parseFloat(`${a}.${b}`);
} else {
return sign * parseInt(toDigits(parts[0]));
}
}

/**
Expand All @@ -98,7 +114,12 @@ function maskValue(value = '', mask) {
if (mask === 'currency') {
// Format number with commas. If the number includes a decimal,
// ensure it includes two decimal points
value = stringWithFixedDigits(toNumber(value).toLocaleString('en-US'));
const number = toNumber(value);
if (number === undefined) {
value = '';
} else {
value = stringWithFixedDigits(number.toLocaleString('en-US'));
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
value = deliminateRegexGroups(value, deliminatedMaskRegex[mask]);
}
Expand Down Expand Up @@ -248,7 +269,12 @@ export function unmask(value, mask) {

if (mask === 'currency') {
// Preserve only digits, decimal point, or negative symbol
value = value.match(/^-|[\d.]/g).join('');
const matches = value.match(/^-|[\d.]/g);
if (matches) {
value = matches.join('');
} else {
value = '';
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
// Remove the deliminators and revert to single ungrouped string
value = toDigitsAndAsterisks(value);
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/components/TextField/Mask.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,26 @@ describe('unmask', () => {
expect(unmask(null)).toBeNull();
});

it('returns empty string when there are no numeric characters in the value', () => {
expect(unmask('banana', 'currency')).toBe('');
expect(unmask('banana', 'zip')).toBe('');
expect(unmask('banana', 'ssn')).toBe('');
expect(unmask('banana', 'phone')).toBe('');
});

it('returns just the numbers when there is other garbage mixed in', () => {
expect(unmask('b4n4n4', 'currency')).toBe('444');
expect(unmask('b4n4n4', 'zip')).toBe('444');
expect(unmask('b4n4n4', 'ssn')).toBe('444');
expect(unmask('b4n4n4', 'phone')).toBe('444');

expect(unmask('a1.b2c3', 'currency')).toBe('1.23');
expect(unmask('1,,00.b', 'currency')).toBe('100.');
expect(unmask('1-1-1-2-3-4', 'zip')).toBe('111234');
expect(unmask('4---31', 'ssn')).toBe('431');
expect(unmask('--2-3444', 'phone')).toBe('23444');
});

it('removes mask from currency value', () => {
const name = 'currency';

Expand Down

0 comments on commit dfa8748

Please sign in to comment.