diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/modules/tests/xpcshell/test_CreditCard.js | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/toolkit/modules/tests/xpcshell/test_CreditCard.js b/toolkit/modules/tests/xpcshell/test_CreditCard.js new file mode 100644 index 0000000000..90cf67b2f4 --- /dev/null +++ b/toolkit/modules/tests/xpcshell/test_CreditCard.js @@ -0,0 +1,623 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { CreditCard } = ChromeUtils.importESModule( + "resource://gre/modules/CreditCard.sys.mjs" +); + +add_task(function isValidNumber() { + function testValid(number, shouldPass) { + if (shouldPass) { + ok( + CreditCard.isValidNumber(number), + `${number} should be considered valid` + ); + } else { + ok( + !CreditCard.isValidNumber(number), + `${number} should not be considered valid` + ); + } + } + + testValid("0000000000000000", true); + + testValid("41111111112", false); // passes Luhn but too short + testValid("4111-1111-112", false); // passes Luhn but too short + testValid("55555555555544440018", false); // passes Luhn but too long + testValid("5555 5555 5555 4444 0018", false); // passes Luhn but too long + + testValid("4929001587121045", true); + testValid("5103059495477870", true); + testValid("6011029476355493", true); + testValid("3589993783099582", true); + testValid("5415425865751454", true); + + testValid("378282246310005", true); // American Express test number + testValid("371449635398431", true); // American Express test number + testValid("378734493671000", true); // American Express Corporate test number + testValid("5610591081018250", true); // Australian BankCard test number + testValid("6759649826438453", true); // Maestro test number + testValid("6799990100000000019", true); // 19 digit Maestro test number + testValid("6799-9901-0000-0000019", true); // 19 digit Maestro test number + testValid("30569309025904", true); // 14 digit Diners Club test number + testValid("38520000023237", true); // 14 digit Diners Club test number + testValid("6011111111111117", true); // Discover test number + testValid("6011000990139424", true); // Discover test number + testValid("3530111333300000", true); // JCB test number + testValid("3566002020360505", true); // JCB test number + testValid("3532596776688495393", true); // 19-digit JCB number. JCB, Discover, Maestro could have 16-19 digits + testValid("3532 5967 7668 8495393", true); // 19-digit JCB number. JCB, Discover, Maestro could have 16-19 digits + testValid("5555555555554444", true); // MasterCard test number + testValid("5105105105105100", true); // MasterCard test number + testValid("2221000000000009", true); // 2-series MasterCard test number + testValid("4111111111111111", true); // Visa test number + testValid("4012888888881881", true); // Visa test number + testValid("4222222222222", true); // 13 digit Visa test number + testValid("4222 2222 22222", true); // 13 digit Visa test number + testValid("4035 5010 0000 0008", true); // Visadebit/Cartebancaire test number + + testValid("5038146897157463", true); + testValid("4026313395502338", true); + testValid("6387060366272981", true); + testValid("474915027480942", true); + testValid("924894781317325", true); + testValid("714816113937185", true); + testValid("790466087343106", true); + testValid("474320195408363", true); + testValid("219211148122351", true); + testValid("633038472250799", true); + testValid("354236732906484", true); + testValid("095347810189325", true); + testValid("930771457288760", true); + testValid("3091269135815020", true); + testValid("5471839082338112", true); + testValid("0580828863575793", true); + testValid("5015290610002932", true); + testValid("9465714503078607", true); + testValid("4302068493801686", true); + testValid("2721398408985465", true); + testValid("6160334316984331", true); + testValid("8643619970075142", true); + testValid("0218246069710785", true); + testValid("0000-0000-0080-4609", true); + testValid("0000 0000 0222 331", true); + testValid("344060747836806", true); + testValid("001064088", false); // too short + testValid("00-10-64-088", false); // still too short + testValid("4929001587121046", false); + testValid("5103059495477876", false); + testValid("6011029476355494", false); + testValid("3589993783099581", false); + testValid("5415425865751455", false); + testValid("5038146897157462", false); + testValid("4026313395502336", false); + testValid("6387060366272980", false); + testValid("344060747836804", false); + testValid("30190729470496", false); + testValid("36333851788255", false); + testValid("526931005800649", false); + testValid("724952425140686", false); + testValid("379761391174135", false); + testValid("030551436468583", false); + testValid("947377014076746", false); + testValid("254848023655752", false); + testValid("226871580283345", false); + testValid("708025346034339", false); + testValid("917585839076788", false); + testValid("918632588027666", false); + testValid("9946177098017064", false); + testValid("4081194386488872", false); + testValid("3095975979578034", false); + testValid("3662215692222536", false); + testValid("6723210018630429", false); + testValid("4411962856225025", false); + testValid("8276996369036686", false); + testValid("4449796938248871", false); + testValid("3350852696538147", false); + testValid("5011802870046957", false); + testValid("0000", false); +}); + +add_task(function test_formatMaskedNumber() { + function testFormat(number) { + let format = CreditCard.formatMaskedNumber(number); + Assert.equal(format.affix, "****", "Affix should always be four asterisks"); + Assert.equal( + format.label, + number.substr(-4), + "The label should always be the last four digits of the card number" + ); + } + testFormat("************0000"); + testFormat("************1045"); + testFormat("***********6806"); + testFormat("**********0495"); + testFormat("**********8250"); +}); + +add_task(function test_maskNumber() { + function testMask(number, expected) { + let card = new CreditCard({ number }); + Assert.equal( + card.maskedNumber, + expected, + "Masked number should only show the last four digits" + ); + } + testMask("0000000000000000", "**** 0000"); + testMask("4929001587121045", "**** 1045"); + testMask("5103059495477870", "**** 7870"); + testMask("6011029476355493", "**** 5493"); + testMask("3589993783099582", "**** 9582"); + testMask("5415425865751454", "**** 1454"); + testMask("344060747836806", "**** 6806"); + testMask("6799990100000000019", "**** 0019"); + Assert.throws( + () => new CreditCard({ number: "1234" }).maskedNumber, + /Invalid credit card number/, + "Four or less numbers should throw when retrieving the maskedNumber" + ); +}); + +add_task(function test_longMaskedNumber() { + function testMask(number, expected) { + let card = new CreditCard({ number }); + Assert.equal( + card.longMaskedNumber, + expected, + "Long masked number should show asterisks for all digits but last four" + ); + } + testMask("0000000000000000", "************0000"); + testMask("4929001587121045", "************1045"); + testMask("5103059495477870", "************7870"); + testMask("6011029476355493", "************5493"); + testMask("3589993783099582", "************9582"); + testMask("5415425865751454", "************1454"); + testMask("344060747836806", "***********6806"); + testMask("6799990100000000019", "***************0019"); + Assert.throws( + () => new CreditCard({ number: "1234" }).longMaskedNumber, + /Invalid credit card number/, + "Four or less numbers should throw when retrieving the longMaskedNumber" + ); +}); + +add_task(function test_isValid() { + function testValid( + number, + expirationMonth, + expirationYear, + shouldPass, + message + ) { + let isValid = false; + try { + let card = new CreditCard({ + number, + expirationMonth, + expirationYear, + }); + isValid = card.isValid(); + } catch (ex) { + isValid = false; + } + if (shouldPass) { + ok(isValid, message); + } else { + ok(!isValid, message); + } + } + let year = new Date().getFullYear(); + let month = new Date().getMonth() + 1; + + testValid( + "0000000000000000", + month, + year + 2, + true, + "Valid number and future expiry date (two years) should pass" + ); + testValid( + "0000000000000000", + month < 11 ? month + 2 : month % 10, + month < 11 ? year : year + 1, + true, + "Valid number and future expiry date (two months) should pass" + ); + testValid( + "0000000000000000", + month, + year, + true, + "Valid number and expiry date equal to this month should pass" + ); + testValid( + "0000000000000000", + month > 1 ? month - 1 : 12, + month > 1 ? year : year - 1, + false, + "Valid number but overdue expiry date should fail" + ); + testValid( + "0000000000000000", + month, + year - 1, + false, + "Valid number but overdue expiry date (by a year) should fail" + ); + testValid( + "0000000000000001", + month, + year + 2, + false, + "Invalid number but future expiry date should fail" + ); +}); + +add_task(function test_normalize() { + Assert.equal( + new CreditCard({ number: "0000 0000 0000 0000" }).number, + "0000000000000000", + "Spaces should be removed from card number after it is normalized" + ); + Assert.equal( + new CreditCard({ number: "0000 0000\t 0000\t0000" }).number, + "0000000000000000", + "Spaces should be removed from card number after it is normalized" + ); + Assert.equal( + new CreditCard({ number: "0000-0000-0000-0000" }).number, + "0000000000000000", + "Hyphens should be removed from card number after it is normalized" + ); + Assert.equal( + new CreditCard({ number: "0000-0000 0000-0000" }).number, + "0000000000000000", + "Spaces and hyphens should be removed from card number after it is normalized" + ); + Assert.equal( + new CreditCard({ number: "0000000000000000" }).number, + "0000000000000000", + "Normalized numbers should not get changed" + ); + + let card = new CreditCard({ number: "0000000000000000" }); + card.expirationYear = "22"; + card.expirationMonth = "11"; + Assert.equal( + card.expirationYear, + 2022, + "Years less than four digits are in the third millenium" + ); + card.expirationYear = "-200"; + ok(isNaN(card.expirationYear), "Negative years are blocked"); + card.expirationYear = "1998"; + Assert.equal( + card.expirationYear, + 1998, + "Years with four digits are not changed" + ); + card.expirationYear = "test"; + ok(isNaN(card.expirationYear), "non-number years are returned as NaN"); + card.expirationMonth = "02"; + Assert.equal( + card.expirationMonth, + 2, + "Zero-leading months are converted properly (not octal)" + ); + card.expirationMonth = "test"; + ok(isNaN(card.expirationMonth), "non-number months are returned as NaN"); + card.expirationMonth = "12"; + Assert.equal( + card.expirationMonth, + 12, + "Months formatted correctly are unchanged" + ); + card.expirationMonth = "13"; + ok(isNaN(card.expirationMonth), "Months above 12 are blocked"); + card.expirationMonth = "7"; + Assert.equal( + card.expirationMonth, + 7, + "Changing back to a valid number passes" + ); + card.expirationMonth = "0"; + ok(isNaN(card.expirationMonth), "Months below 1 are blocked"); + card.expirationMonth = card.expirationYear = undefined; + card.expirationString = "2022/01"; + Assert.equal(card.expirationMonth, 1, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2022, "Year should be parsed correctly"); + + card.expirationString = "2028 / 05"; + Assert.equal(card.expirationMonth, 5, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2028, "Year should be parsed correctly"); + + card.expirationString = "2023-02"; + Assert.equal(card.expirationMonth, 2, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2023, "Year should be parsed correctly"); + + card.expirationString = "2029 - 09"; + Assert.equal(card.expirationMonth, 9, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2029, "Year should be parsed correctly"); + + card.expirationString = "03-2024"; + Assert.equal(card.expirationMonth, 3, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2024, "Year should be parsed correctly"); + + card.expirationString = "08 - 2024"; + Assert.equal(card.expirationMonth, 8, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2024, "Year should be parsed correctly"); + + card.expirationString = "04/2025"; + Assert.equal(card.expirationMonth, 4, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2025, "Year should be parsed correctly"); + + card.expirationString = "01 / 2023"; + Assert.equal(card.expirationMonth, 1, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2023, "Year should be parsed correctly"); + + card.expirationString = "05/26"; + Assert.equal(card.expirationMonth, 5, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2026, "Year should be parsed correctly"); + + card.expirationString = " 06 / 27 "; + Assert.equal(card.expirationMonth, 6, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2027, "Year should be parsed correctly"); + + card.expirationString = "04 / 25"; + Assert.equal(card.expirationMonth, 4, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2025, "Year should be parsed correctly"); + + card.expirationString = "27-6"; + Assert.equal(card.expirationMonth, 6, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2027, "Year should be parsed correctly"); + + card.expirationString = "26 - 5"; + Assert.equal(card.expirationMonth, 5, "Month should be parsed correctly"); + Assert.equal(card.expirationYear, 2026, "Year should be parsed correctly"); + + card.expirationString = "07/11"; + Assert.equal( + card.expirationMonth, + 7, + "Ambiguous month should be parsed correctly" + ); + Assert.equal( + card.expirationYear, + 2011, + "Ambiguous year should be parsed correctly" + ); + + card.expirationString = "08 / 12"; + Assert.equal( + card.expirationMonth, + 8, + "Ambiguous month should be parsed correctly" + ); + Assert.equal( + card.expirationYear, + 2012, + "Ambiguous year should be parsed correctly" + ); + + card = new CreditCard({ + number: "0000000000000000", + expirationMonth: "02", + expirationYear: "2112", + expirationString: "06-2066", + }); + Assert.equal( + card.expirationMonth, + 2, + "expirationString is takes lower precendence than explicit month" + ); + Assert.equal( + card.expirationYear, + 2112, + "expirationString is takes lower precendence than explicit year" + ); +}); + +add_task(async function test_label() { + let testCases = [ + { + number: "0000000000000000", + name: "Rudy Badoody", + expectedMaskedLabel: "**** 0000, Rudy Badoody", + }, + { + number: "3589993783099582", + name: "Jimmy Babimmy", + expectedMaskedLabel: "**** 9582, Jimmy Babimmy", + }, + ]; + + for (let testCase of testCases) { + let { number, name } = testCase; + Assert.equal( + await CreditCard.getLabel({ number, name }), + testCase.expectedMaskedLabel, + "The expectedMaskedLabel should be shown when showNumbers is false" + ); + } +}); + +add_task(async function test_network() { + let supportedNetworks = CreditCard.getSupportedNetworks(); + Assert.ok( + supportedNetworks.length, + "There are > 0 supported credit card networks" + ); + + let ccNumber = "0000000000000000"; + let testCases = supportedNetworks.map(network => { + return { number: ccNumber, network, expectedNetwork: network }; + }); + testCases.push({ + number: ccNumber, + network: "gringotts", + expectedNetwork: "gringotts", + }); + testCases.push({ + number: ccNumber, + network: "", + expectedNetwork: undefined, + }); + + for (let testCase of testCases) { + let { number, network } = testCase; + let card = new CreditCard({ number, network }); + Assert.equal( + await card.network, + testCase.expectedNetwork, + `The expectedNetwork ${card.network} should match the card network ${testCase.expectedNetwork}` + ); + } +}); + +add_task(async function test_isValidNetwork() { + for (let network of CreditCard.getSupportedNetworks()) { + Assert.ok(CreditCard.isValidNetwork(network), "supported network is valid"); + } + Assert.ok(!CreditCard.isValidNetwork(), "undefined is not a valid network"); + Assert.ok( + !CreditCard.isValidNetwork(""), + "empty string is not a valid network" + ); + Assert.ok(!CreditCard.isValidNetwork(null), "null is not a valid network"); + Assert.ok( + !CreditCard.isValidNetwork("Visa"), + "network validity is case-sensitive" + ); + Assert.ok( + !CreditCard.isValidNetwork("madeupnetwork"), + "unknown network is invalid" + ); +}); + +add_task(async function test_getType() { + const RECOGNIZED_CARDS = [ + // Edge cases + ["2221000000000000", "mastercard"], + ["2720000000000000", "mastercard"], + ["2200000000000000", "mir"], + ["2204000000000000", "mir"], + ["340000000000000", "amex"], + ["370000000000000", "amex"], + ["3000000000000000", "diners"], + ["3050000000000000", "diners"], + ["3095000000000000", "diners"], + ["36000000000000", "diners"], + ["3800000000000000", "diners"], + ["3900000000000000", "diners"], + ["3528000000000000", "jcb"], + ["3589000000000000", "jcb"], + ["4035000000000000", "cartebancaire"], + ["4360000000000000", "cartebancaire"], + ["4000000000000000", "visa"], + ["4999999999999999", "visa"], + ["5400000000000000", "mastercard"], + ["5500000000000000", "mastercard"], + ["5100000000000000", "mastercard"], + ["5399999999999999", "mastercard"], + ["6011000000000000", "discover"], + ["6221260000000000", "discover"], + ["6229250000000000", "discover"], + ["6240000000000000", "discover"], + ["6269990000000000", "discover"], + ["6282000000000000", "discover"], + ["6288990000000000", "discover"], + ["6400000000000000", "discover"], + ["6500000000000000", "discover"], + ["6200000000000000", "unionpay"], + ["8100000000000000", "unionpay"], + // Valid according to Luhn number + ["2204941877211882", "mir"], + ["2720994326581252", "mastercard"], + ["374542158116607", "amex"], + ["36006666333344", "diners"], + ["3541675340715696", "jcb"], + ["3543769248058305", "jcb"], + ["4035501428146300", "cartebancaire"], + ["4111111111111111", "visa"], + ["5346755600299631", "mastercard"], + ["5495770093313616", "mastercard"], + ["5574238524540144", "mastercard"], + ["6011029459267962", "discover"], + ["6278592974938779", "unionpay"], + ["8171999927660000", "unionpay"], + ["30569309025904", "diners"], + ["38520000023237", "diners"], + ]; + for (let [value, type] of RECOGNIZED_CARDS) { + Assert.equal( + CreditCard.getType(value), + type, + `Expected ${value} to be recognized as ${type}` + ); + } + + const UNRECOGNIZED_CARDS = [ + ["411111111111111", "15 digits"], + ["41111111111111111", "17 digits"], + ["", "empty"], + ["9111111111111111", "Unknown prefix"], + ]; + for (let [value, reason] of UNRECOGNIZED_CARDS) { + Assert.equal( + CreditCard.getType(value), + null, + `Expected ${value} to not match any card because: ${reason}` + ); + } +}); + +add_task(async function test_getNetworkFromName() { + const RECOGNIZED_NAMES = [ + ["amex", "amex"], + ["American Express", "amex"], + ["american express", "amex"], + ["mastercard", "mastercard"], + ["master card", "mastercard"], + ["MasterCard", "mastercard"], + ["Master Card", "mastercard"], + ["Union Pay", "unionpay"], + ["UnionPay", "unionpay"], + ["Unionpay", "unionpay"], + ["unionpay", "unionpay"], + + ["Unknown", null], + ["", null], + ]; + for (let [value, type] of RECOGNIZED_NAMES) { + Assert.equal( + CreditCard.getNetworkFromName(value), + type, + `Expected ${value} to be recognized as ${type}` + ); + } +}); + +add_task(async function test_normalizeCardNumber() { + let testCases = [ + ["5495770093313616", "5495770093313616"], + ["5495 7700 9331 3616", "5495770093313616"], + [" 549 57700 93313 616 ", "5495770093313616"], + ["5495-7700-9331-3616", "5495770093313616"], + ["", null], + [undefined, null], + [null, null], + ]; + for (let [input, expected] of testCases) { + let actual = CreditCard.normalizeCardNumber(input); + Assert.equal( + actual, + expected, + `Expected ${input} to normalize to ${expected}` + ); + } +}); |