summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/tests/xpcshell/test_CreditCard.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/modules/tests/xpcshell/test_CreditCard.js623
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}`
+ );
+ }
+});