UNPKG

card-validator

Version:

A library for validating credit card fields

1,330 lines (1,318 loc) 30.3 kB
import { expirationDate, ExpirationDateVerification } from "../expiration-date"; const date = new Date(); const currentYear = date.getFullYear(); const twoDigitYear = Number(String(currentYear).substr(2, 2)); const firstTwoDigitsOfCurrentYear = Number(String(currentYear).substr(0, 2)); const nextYear = currentYear + 1; const currentMonth = date.getMonth() + 1; const previousMonth = currentMonth - 1 || currentMonth; const nextMonth = currentMonth === 12 ? currentMonth : currentMonth + 1; function yearsFromNow(fromNow: number): string { return String(currentYear + fromNow); } describe("expirationDate validates", () => { const stringContexts = [ [ "within current year", [ [ `${previousMonth} / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: previousMonth.toString(), year: nextYear.toString(), }, ], [ `${currentMonth} / ${currentYear}`, { isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: currentYear.toString(), }, ], [ `${nextMonth} / ${currentYear}`, { isValid: true, isPotentiallyValid: true, month: nextMonth.toString(), year: currentYear.toString(), }, ], ], ], [ "valid expiration dates with dashes", [ [ `${currentYear}-${currentMonth}`, { isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: currentYear.toString(), }, ], [ `${nextYear}-10`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `${nextYear}-10`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `${nextYear}-12`, { isValid: true, isPotentiallyValid: true, month: "12", year: nextYear.toString(), }, ], [ `${nextYear}-01`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], [ `${nextYear}-1`, { isValid: true, isPotentiallyValid: true, month: "1", year: nextYear.toString(), }, ], [ `${nextYear}-09`, { isValid: true, isPotentiallyValid: true, month: "09", year: nextYear.toString(), }, ], [ `${nextYear}-01`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], [ `${nextYear}-01`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], ], ], [ "invalid expiration dates with dashes", [ [ `${nextYear}-00`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `${nextYear}-13`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "1999-01", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "2100-01", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "valid expiration dates with slashes", [ [ `${currentMonth} / ${currentYear}`, { isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: currentYear.toString(), }, ], [ `10 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `10/${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `12 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "12", year: nextYear.toString(), }, ], [ `01 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], [ `1 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "1", year: nextYear.toString(), }, ], [ `09 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "09", year: nextYear.toString(), }, ], [ `01 / ${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (twoDigitYear + 1).toString(), }, ], [ `1 / ${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (twoDigitYear + 1).toString(), }, ], [ `01 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], [ `01 / ${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], ], ], [ "invalid expiration dates with slashes", [ [ "11 / 11", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `00 / ${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `13 / ${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 1999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01/1999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 2100", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "10/123", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "ambiguous expiration dates with slashes", [ [ "11 / 1", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "01 / 201", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "01 / 211", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 199", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01/199", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `02/${firstTwoDigitsOfCurrentYear}`, { isValid: false, isPotentiallyValid: true, month: null, year: null, }, ], ], ], [ "valid expiration dates with no slashes", [ [ `10${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `10${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ `12${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "12", year: nextYear.toString(), }, ], [ `01${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "01", year: nextYear.toString(), }, ], [ `09${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "09", year: nextYear.toString(), }, ], [ `1${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "1", year: nextYear.toString(), }, ], [ `9${nextYear}`, { isValid: true, isPotentiallyValid: true, month: "9", year: nextYear.toString(), }, ], [ `1${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (twoDigitYear + 1).toString(), }, ], [ `9${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "9", year: (twoDigitYear + 1).toString(), }, ], [ `12${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "12", year: (twoDigitYear + 1).toString(), }, ], [ `01${twoDigitYear + 1}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (twoDigitYear + 1).toString(), }, ], ], ], [ "valid space separated month and year", [ [ `01 ${currentYear + 4}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (currentYear + 4).toString(), }, ], [ `01 ${currentYear + 5}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (currentYear + 5).toString(), }, ], [ `01 ${twoDigitYear + 4}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (twoDigitYear + 4).toString(), }, ], [ `01 ${twoDigitYear + 6}`, { isValid: true, isPotentiallyValid: true, month: "01", year: (twoDigitYear + 6).toString(), }, ], [ `1 ${currentYear + 4}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (currentYear + 4).toString(), }, ], [ `1 ${currentYear + 5}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (currentYear + 5).toString(), }, ], [ `1 ${twoDigitYear + 4}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (twoDigitYear + 4).toString(), }, ], [ `1 ${twoDigitYear + 5}`, { isValid: true, isPotentiallyValid: true, month: "1", year: (twoDigitYear + 5).toString(), }, ], [ `9 ${currentYear + 4}`, { isValid: true, isPotentiallyValid: true, month: "9", year: (currentYear + 4).toString(), }, ], [ `9 ${currentYear + 5}`, { isValid: true, isPotentiallyValid: true, month: "9", year: (currentYear + 5).toString(), }, ], ], ], [ "ambiguous space separated month and year", [ [ "1 2", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "1 202", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ `1 ${firstTwoDigitsOfCurrentYear}`, { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "1 ", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "12 2", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "12 202", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "12 ", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], ], ], [ "invalid space separated month and year", [ [ "11 11", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `00 ${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `13 ${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 1999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 1999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 2100", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "invalid expiration dates with no slashes", [ [ " ", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ " ", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "1111", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `00${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `13${nextYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "011999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "011999", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "012100", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "ambiguous expiration dates with no slashes", [ [ "011", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "111", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "2202", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "1202", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "01201", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "01211", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01199", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01199", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `02${firstTwoDigitsOfCurrentYear}`, { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], ], ], [ "empty strings", [ [ "", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "/", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ " / ", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], ], ], [ "non-strings", [ [ [], { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ {}, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ null, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ undefined, // eslint-disable-line no-undefined { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ Infinity, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 0 / 0, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 0, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 1, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 2, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 12, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ -1, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ -12, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ 2015, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "malformed strings", [ [ "foo", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "0120197", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "1.2", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ " 1", { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ "01 / 20015", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ `15 / ${currentYear}`, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 2016 / 2016", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 16/2016", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ "01 / 2016 / 01 / 2016", { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], ] as Array<[string, Array<[string, ExpirationDateVerification]>]>; if (currentMonth !== 1) { stringContexts.push([ "within current year", [ [ `${previousMonth} / ${currentYear}`, { isValid: false, isPotentiallyValid: false, month: previousMonth.toString(), year: currentYear.toString(), }, ], ], ]); stringContexts.push([ "valid expiration dates with slashes", [ [ `${previousMonth} / ${currentYear}`, { isValid: false, isPotentiallyValid: false, month: previousMonth.toString(), year: currentYear.toString(), }, ], ], ]); } describe.each(stringContexts)("String argument %s", (description, tests) => { it.each(tests)( "parses %s to be %p", (exp: string | number, meta: ExpirationDateVerification) => { expect(expirationDate(exp)).toEqual(meta); }, ); }); const objectContexts = [ [ "within current year with number values", [ [ { month: previousMonth, year: nextYear }, { isValid: true, isPotentiallyValid: true, month: previousMonth.toString(), year: nextYear.toString(), }, ], [ { month: currentMonth, year: currentYear }, { isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: currentYear.toString(), }, ], [ { month: nextMonth, year: currentYear }, { isValid: true, isPotentiallyValid: true, month: nextMonth.toString(), year: currentYear.toString(), }, ], ], ], [ "valid expiration dates", [ [ { month: currentMonth, year: currentYear }, { isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: currentYear.toString(), }, ], // eslint-disable-line max-len [ { month: "10", year: nextYear }, { isValid: true, isPotentiallyValid: true, month: "10", year: nextYear.toString(), }, ], [ { month: "01", year: twoDigitYear + 1 }, { isValid: true, isPotentiallyValid: true, month: "01", year: (twoDigitYear + 1).toString(), }, ], [ { month: "1", year: twoDigitYear + 1 }, { isValid: true, isPotentiallyValid: true, month: "1", year: (twoDigitYear + 1).toString(), }, ], ], ], [ "invalid expiration dates", [ [ { month: "11", year: "11" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "00", year: nextYear }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "13", year: nextYear }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "01", year: "1999" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "0", year: "1999" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "01", year: "2100" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "1", year: "123" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "ambiguous expiration dates", [ [ { month: "11", year: "1" }, { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ { month: "01", year: "201" }, { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], [ { month: "01", year: "211" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], [ { month: "02", year: "20" }, { isValid: false, isPotentiallyValid: true, month: null, year: null, }, ], [ { month: "0", year: "199" }, { isValid: false, isPotentiallyValid: false, month: null, year: null, }, ], ], ], [ "empty strings", [ [ { month: "", year: "" }, { isValid: false, isPotentiallyValid: true, month: null, year: null }, ], ], ], ] as Array< [string, Array<[Record<string, number>, ExpirationDateVerification]>] >; if (currentMonth !== 1) { objectContexts[0][1].push([ { month: previousMonth, year: currentYear, }, { isValid: false, isPotentiallyValid: false, month: previousMonth.toString(), year: currentYear.toString(), }, ]); } describe.each(objectContexts)("Object Argument %s", (description, tests) => { it.each([...tests])( "parses %s to be %p", (exp, meta: ExpirationDateVerification) => { expect(expirationDate(exp)).toEqual(meta); }, ); }); describe("maxElapsedYear", () => { it("defaults maxElapsedYear is 19", () => { expect(expirationDate(`${currentMonth} / ${yearsFromNow(19)}`)).toEqual({ isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: yearsFromNow(19).toString(), }); expect(expirationDate(`${currentMonth} / ${yearsFromNow(20)}`)).toEqual({ isValid: false, isPotentiallyValid: false, month: null, year: null, }); }); it("accepts maxElapsedYear", () => { expect( expirationDate(`${currentMonth} / ${yearsFromNow(20)}`, 20), ).toEqual({ isValid: true, isPotentiallyValid: true, month: currentMonth.toString(), year: yearsFromNow(20).toString(), }); expect( expirationDate(`${currentMonth} / ${yearsFromNow(21)}`, 20), ).toEqual({ isValid: false, isPotentiallyValid: false, month: null, year: null, }); }); }); });