card-validator
Version:
A library for validating credit card fields
374 lines (345 loc) • 11.7 kB
text/typescript
import { cardNumber, CardNumberVerification } from "../card-number";
describe("number validates", () => {
describe.each([
[
"partial validation sequences",
[
["", { card: null, isPotentiallyValid: true, isValid: false }],
["6", { card: null, isPotentiallyValid: true, isValid: false }],
["60", { card: null, isPotentiallyValid: true, isValid: false }],
["601", { card: null, isPotentiallyValid: true, isValid: false }],
[
"6011",
{ card: "discover", isPotentiallyValid: true, isValid: false },
],
["4", { card: null, isPotentiallyValid: true, isValid: false }],
["41", { card: "visa", isPotentiallyValid: true, isValid: false }],
["411", { card: "visa", isPotentiallyValid: true, isValid: false }],
["", { card: null, isPotentiallyValid: true, isValid: false }],
["x", { card: null, isPotentiallyValid: false, isValid: false }],
["123", { card: null, isPotentiallyValid: false, isValid: false }],
],
],
[
"normal cases",
[
[
"4012888888881881",
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[
"62123456789002",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"621234567890003",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"6288997715452584",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"6282001509099283",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"6269992058134322",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"6240008631401148",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"6221558812340000", // UnionPay is not always Luhn10 valid
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
[
"4111111111111111",
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[
"4111111111111111",
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[
"6011000990139424",
{ card: "discover", isPotentiallyValid: true, isValid: true },
],
["411111y", { card: null, isPotentiallyValid: false, isValid: false }],
[
"41111111111111111111", // Too long
{ card: "visa", isPotentiallyValid: false, isValid: false },
],
[
"4111111111111112", // right length, not Luhn, potentialls valid because visas can be 19 digits
{ card: "visa", isPotentiallyValid: true, isValid: false },
],
],
],
[
"weird formatting",
[
[
"4111-1111-1111-1111",
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[
"4111 1111 1111 1111",
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[
"601 1 1 1 1 1 1 1 1 1 1 1 1 7",
{ card: "discover", isPotentiallyValid: true, isValid: true },
],
],
],
[
"Discover",
[
[
"6011111",
{ card: "discover", isPotentiallyValid: true, isValid: false },
],
[
"6011111111111117",
{ card: "discover", isPotentiallyValid: true, isValid: true },
],
],
],
[
"MasterCard",
[
["2", { card: null, isPotentiallyValid: true, isValid: false }],
[
"27",
{ card: "mastercard", isPotentiallyValid: true, isValid: false },
],
[
"272",
{ card: "mastercard", isPotentiallyValid: true, isValid: false },
],
[
"2720",
{ card: "mastercard", isPotentiallyValid: true, isValid: false },
],
[
"55555555",
{ card: "mastercard", isPotentiallyValid: true, isValid: false },
],
[
"5555555555554444",
{ card: "mastercard", isPotentiallyValid: true, isValid: true },
],
[
"5555555555554446",
{ card: "mastercard", isPotentiallyValid: false, isValid: false },
],
],
],
[
"Maestro",
[
[
"602011",
{ card: "maestro", isPotentiallyValid: true, isValid: false },
],
[
"500000000000",
{ card: "maestro", isPotentiallyValid: true, isValid: false },
],
[
"500000000000061",
{ card: "maestro", isPotentiallyValid: true, isValid: false },
],
[
"5000000000000611",
{ card: "maestro", isPotentiallyValid: true, isValid: true },
],
[
"5000000000000612",
{ card: "maestro", isPotentiallyValid: true, isValid: false },
],
[
"500000000000000005",
{ card: "maestro", isPotentiallyValid: true, isValid: false },
],
[
"5000000000000000005",
{ card: "maestro", isPotentiallyValid: true, isValid: true },
],
[
"5000000000000000001",
{ card: "maestro", isPotentiallyValid: false, isValid: false },
],
[
"50000000000000000009",
{ card: "maestro", isPotentiallyValid: false, isValid: false },
],
],
],
[
"Amex",
[
[
"3782",
{
card: "american-express",
isPotentiallyValid: true,
isValid: false,
},
],
[
"378282246310005",
{ card: "american-express", isPotentiallyValid: true, isValid: true },
],
],
],
[
"JCB",
[
["1", { card: "jcb", isPotentiallyValid: true, isValid: false }],
["21", { card: "jcb", isPotentiallyValid: true, isValid: false }],
["3530111", { card: "jcb", isPotentiallyValid: true, isValid: false }],
[
"3530111333300000",
{ card: "jcb", isPotentiallyValid: true, isValid: true },
],
],
],
[
"UnionPay",
[
["6", { card: null, isPotentiallyValid: true, isValid: false }],
["62", { card: null, isPotentiallyValid: true, isValid: false }],
[
"623456",
{ card: "unionpay", isPotentiallyValid: true, isValid: false },
],
[
"6212345678901232",
{ card: "unionpay", isPotentiallyValid: true, isValid: true },
],
],
],
[
"edge cases",
[
["", { card: null, isPotentiallyValid: true, isValid: false }],
["foo", { card: null, isPotentiallyValid: false, isValid: false }],
[{}, { card: null, isPotentiallyValid: false, isValid: false }],
[[], { card: null, isPotentiallyValid: false, isValid: false }],
["32908234", { card: null, isPotentiallyValid: false, isValid: false }],
[32908234, { card: null, isPotentiallyValid: false, isValid: false }],
[
4111111111111111,
{ card: "visa", isPotentiallyValid: true, isValid: true },
],
[true, { card: null, isPotentiallyValid: false, isValid: false }],
[false, { card: null, isPotentiallyValid: false, isValid: false }],
],
],
] as Array<[string, Array<[string, CardNumberVerification]>]>)(
"Validator for %s",
(description, tests) => {
describe.each(tests)("when number is %p", (number, expected) => {
const actual = cardNumber(number);
it(`card: is ${expected.card} for ${number}`, () => {
if (expected.card) {
expect(actual.card.type).toBe(expected.card);
} else {
expect(actual.card).toBeNull();
}
});
it(`isPotentiallyValid: is ${expected.isPotentiallyValid} for ${number}`, () => {
expect(actual.isPotentiallyValid).toBe(expected.isPotentiallyValid);
});
it(`valid: is ${expected.isValid} for ${number}`, () => {
expect(actual.isValid).toBe(expected.isValid);
});
});
},
);
describe("UnionPay", () => {
describe("where card number is luhn invalid", () => {
const number = "6212345000000001";
it("marks card valid by default", () => {
const actual = cardNumber(number);
expect(actual.card.type).toBe("unionpay");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(true);
});
it('marks card invalid when "luhnValidateUnionPay" is present', () => {
const options = {
luhnValidateUnionPay: true,
};
const actual = cardNumber(number, options);
expect(actual.card.type).toBe("unionpay");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(false);
});
});
});
describe('with "maxCardLength" option', () => {
it("marks card invalid when card is longer than the max length", () => {
const options = {
maxLength: 16,
};
let actual = cardNumber("4111 1111 1111 1111 110", options);
expect(actual.card.type).toBe("visa");
expect(actual.isPotentiallyValid).toBe(false);
expect(actual.isValid).toBe(false);
options.maxLength = 19;
actual = cardNumber("4111 1111 1111 1111 110", options);
expect(actual.card.type).toBe("visa");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(true);
});
it("marks card as not potentially valid when card is equal to max length and not luhn valid", () => {
const options = {
maxLength: 16,
};
const actual = cardNumber("4111 1111 1111 1112", options);
expect(actual.card.type).toBe("visa");
expect(actual.isPotentiallyValid).toBe(false);
expect(actual.isValid).toBe(false);
});
it("marks card as valid and potentially valid when card is equal to max length and luhn valid", () => {
const options = {
maxLength: 16,
};
const actual = cardNumber("4111 1111 1111 1111", options);
expect(actual.card.type).toBe("visa");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(true);
});
it("uses the lesser value for max length if the card brands largest length value is smaller than the configured one", () => {
const options = {
maxLength: 16,
};
// amex has a max length of 15
const actual = cardNumber("378282246310005", options);
expect(actual.card.type).toBe("american-express");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(true);
});
});
describe("Skip Luhn Validation", () => {
const number = "5732806135556590";
it("should fail validation for a card with invalid luhn check digit", () => {
const actual = cardNumber(number);
expect(actual.card.type).toBe("maestro");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(false);
});
it("should succeed validation for a card with invalid luhn check digit when using skipLuhnValidation=true", () => {
const actual = cardNumber(number, {
skipLuhnValidation: true,
});
expect(actual.card.type).toBe("maestro");
expect(actual.isPotentiallyValid).toBe(true);
expect(actual.isValid).toBe(true);
});
});
});