UNPKG

number-currency-format

Version:

Dependency-less price formatting

151 lines (132 loc) 9.59 kB
const { format, unformat } = require('./index'); let testIndex = 0; let successes = 0; let verbose = true; suite('FORMAT'); suite('Integer number formatting'); assert(format(parseInt(123)), '123.00', 'Integer number'); assert(format(parseInt(123), { showDecimals: 'NEVER' }), '123', 'Integer number without decimals, never showing decimals'); assert(format(parseInt(123), { showDecimals: 'IF_NEEDED' }), '123', 'Integer number without decimals, showing decimals only if needed'); assert(format(parseInt(123), { showDecimals: 'ALWAYS' }), '123.00', 'Integer number without decimals, enforcing decimals always'); suite('Integer number formatting'); assert(format(123.45), '123.45', 'Simple number with decimals'); assert(format(123.45, { showDecimals: 'NEVER' }), '123', 'Floating price without decimals shown'); assert(format(123.45, { showDecimals: 'IF_NEEDED' }), '123.45', 'Floating price with decimals only if needed'); assert(format(123.45, { showDecimals: 'ALWAYS' }), '123.45', 'Floating number enforcing decimals'); suite('Custom decimals length'); assert(format(123.456), '123.46', 'Long decimals should be rounded to the precision of two by default'); assert(format(123.456, { decimalsDigits: 3 }), '123.456', 'Decimals should follow custom decimals digits'); assert(format(123.4), '123.40', 'Decimals should follow the decimal precision for input that has less decimal digits'); assert(format(123.45, { decimalsDigits: 5 }), '123.45000', 'Custom decimal digits should work for larger decimal and padding'); assert(format(123, { decimalsDigits: 5, showDecimals: 'ALWAYS' }), '123.00000', 'Custom decimal digits should be respected when no decimals but showing decimals is forced'); assert(format(123.1, { showDecimals: 'AS_IS' }), '123.1', 'AS_IS does not change the decimal places'); assert(format('123.0', { showDecimals: 'AS_IS' }), '123.0', 'AS_IS preserves the number exactly'); assert(format(123, { showDecimals: 'AS_IS' }), '123', 'AS_IS works also without decimals'); assert(format(123333.4567, { showDecimals: 'AS_IS' }), '123,333.4567', 'AS_IS does the formating but does not round the decimal places'); assert(format(123.123, { decimalsDigits: 5, showDecimals: 'AS_IS' }), '123.123', 'AS_IS also ignores any decimalsDigits setting'); suite('Decimal rounding with tie breaking'); assert(format(0.005), '0.01', '0.005 -> 0.01 [up]'); assert(format(0.015), '0.01', '0.015 -> 0.01 [down]'); assert(format(0.025), '0.03', '0.025 -> 0.03 [up]'); assert(format(0.035), '0.04', '0.035 -> 0.04 [up]'); assert(format(0.045), '0.04', '0.045 -> 0.04 [down]'); assert(format(0.055), '0.06', '0.055 -> 0.06 [up]'); assert(format(0.065), '0.07', '0.065 -> 0.07 [up]'); assert(format(0.075), '0.07', '0.075 -> 0.07 [down]'); assert(format(0.085), '0.09', '0.085 -> 0.09 [up]'); assert(format(0.095), '0.10', '0.095 -> 0.10 [up]'); suite('Decimal rounding half-ups with arithmetical rounding enforced'); assert(format(0.005, { arithmeticalRounding: true }), '0.01', '0.005 -> 0.01 [up]'); assert(format(0.015, { arithmeticalRounding: true }), '0.02', '0.015 -> 0.02 [up]'); assert(format(0.025, { arithmeticalRounding: true }), '0.03', '0.025 -> 0.03 [up]'); assert(format(0.035, { arithmeticalRounding: true }), '0.04', '0.035 -> 0.04 [up]'); assert(format(0.045, { arithmeticalRounding: true }), '0.05', '0.045 -> 0.05 [up]'); assert(format(0.055, { arithmeticalRounding: true }), '0.06', '0.055 -> 0.06 [up]'); assert(format(0.065, { arithmeticalRounding: true }), '0.07', '0.065 -> 0.07 [up]'); assert(format(0.075, { arithmeticalRounding: true }), '0.08', '0.075 -> 0.08 [up]'); assert(format(0.085, { arithmeticalRounding: true }), '0.09', '0.085 -> 0.09 [up]'); assert(format(0.095, { arithmeticalRounding: true }), '0.10', '0.095 -> 0.10 [up]'); suite('Decimal separator'); assert(format(123.45, { decimalSeparator: '.' }), '123.45', 'Decimal separator is by default a dot'); assert(format(123.45, { decimalSeparator: ',' }), '123,45', 'Decimal separator can be customized'); suite('Thousand separators'); assert(format(1234.56), '1,234.56', 'Thousand number should be separated from hundred digit with a comma'); assert(format(123412345123456.89), '123,412,345,123,456.89', 'Thousand separator should divide every 10^3 digit'); assert(format(1234.56, { thousandSeparator: ' '}), '1 234.56', 'Thousand separator is customizable'); assert(format(1234.56, { thousandSeparator: ''}), '1234.56', 'Thousand separator can be disabled'); assert(format(123456789.00, { thousandSeparator: '__'}), '123__456__789.00', 'Thousand separator can have more than one character'); suite('Currency options'); assert(format(123, { currency: 'Kr' }), '123.00 Kr', 'Simple number with currency'); assert(format(123, { currency: 'Kr.', currencyPosition: 'LEFT' }), 'Kr. 123.00', 'Simple number with currency in front'); assert(format(123, { currency: '$', spacing: false }), '123.00$', 'Spacing between currency can be disabled'); assert(format(123, { currency: '$', spacing: false, currencyPosition: 'LEFT' }), '$123.00', 'Currency settings should be respected altogether'); suite('API edge cases'); assert(format(10, {decimalsDigits: 8, currency: '฿'}), '10.00000000 ฿', 'Handle floating arythmetics right (without dangling 1)'); assert(format(0), '0.00','Zero format'); assert(format('0'), '0.00', 'Zero format from string'); assert(format(0, {}), '0.00', 'Zero format with empty config'); assert(format('124.22'), '124.22', 'From string as number'); assert(format('five'), 'five', 'Invalid string should be passed through'); assert(format(), undefined, 'If nothing is provided, return undefined'); assert(format(-234.56, { thousandSeparator: ','}), '-234.56', 'Thousand separator works fine with negative number'); suite('Diacritics and actual language examples'); assert(format(1999.99, { currency: 'zł', thousandSeparator: '', decimalSeparator: ','}), '1999,99 zł', 'Poland'); assert(format(1999.99, { currency: '$', spacing: false, currencyPosition: 'LEFT'}), '$1,999.99', 'US'); assert(format(1999.99, { currency: 'Rp', thousandSeparator: '.', spacing: false, currencyPosition: 'LEFT', showDecimals: 'NEVER'}), 'Rp2.000', 'Indonesian'); suite('UNFORMAT'); assert(unformat('123'), 123., 'Unformat integer number'); assert(unformat('123.'), 123., 'Unformat integer number with a trailing separator'); assert(unformat('.55'), .55, 'Unformat only decimal part'); assert(unformat(',55'), .55, 'Unformat only decimal part with different separator'); assert(unformat('.456'), .456, 'Unformat only decimal part that is a bit longer'); assert(unformat('.1'), .1, 'Unformat size one decimal part'); assert(unformat('0,0'), .0, 'Zero trailing decimals'); assert(unformat('0.123'), .123, 'Zero trailing decials 2'); assert(unformat('.1'), .1, 'Unformat size one decimal part'); assert(unformat('123,456,789'), 123456789., 'Unformat integer number with thousands separators'); assert(unformat('123.456'), 123456, 'Unformat integer number with thousand separator'); assert(unformat('123.12'), 123.12, 'Unformat integer number with decimal separator'); assert(unformat('123,12'), 123.12, 'Unformat integer number with decimal separator (different separator character)'); assert(unformat('123,456.78'), 123456.78, 'Unformat integer number with decimal separator and thousand separator when decimals length is known'); assert(unformat('123,456.789'), 123456.789, 'Unformat integer number with decimal separator and thousand separator when decimals length is unknown but it can be deducted from the types of separators'); assert(unformat('-123,456.789'), -123456.789, 'Unformat negative number'); assert(unformat('123,456:789', { decimalSeparator: ':'}), 123456.789, 'Unformat with regard of custom decimal separator'); assert(unformat('123,456:789', { decimalSeparator: '.'}), 123456789, 'Unformat with regard of custom decimal separator and ignoring decimal guesser'); suite('Currencies and real-life examples'); assert(unformat('kr. 55'), 55, 'Does not treat non-single character separators as decimal separator'); assert(unformat('kr 250,162'), 250162, 'Does not treat non-single character separators as decimal separator'); assert(unformat('14$'), 14, 'Handles simple currency case'); assert(unformat('$14'), 14, 'Handles simple currency case (currency before the number)'); assert(unformat('$123.45'), 123.45, 'Handles a bit trickier currency case'); assert(unformat('$-123,456.7'), -123456.7, 'Handles a bit trickier price+currency case'); assert(unformat('$-123 456.78'), -123456.78, 'Handles a bit trickier price+currency case'); assert(unformat('123.456.789$'), 123456789, 'Handles a bit trickier price+currency case'); assert(unformat('123.456.789$', { decimalSeparator: '.'}), 123456.789, 'Handles a bit trickier price+currency case'); function suite(suiteName) { console.log(`\n${suiteName}\n${(() => {let line = ''; for(let i = 0;i<suiteName.length;i++){line+='-'} return line;})()}`); } function assert(actual, expected, msg) { const passed = actual === expected; testIndex++; if (passed) { successes++; if (verbose) { console.log(`+ [success] ${msg} - ${actual}`) } else { process.stdout.write('.'); } } else { if (verbose) { console.log(''); console.log(`✘ ${msg}`); console.log(`>>> Expected <${expected}> but got <${actual}>`); } else { console.log('x'); } } } const failedTests = testIndex - successes; console.log(`\nFailed: ${failedTests}, total: ${testIndex}`); if (failedTests > 0) { process.exit(1); }