From e47b5a15fd56c973a31210fca93cebcc4616f860 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Thu, 2 Jan 2025 14:09:57 -0500 Subject: [PATCH] [PM-16667] Fix flaky card expiry tests (#12659) * fix improper date month subtraction * fix mishandling of 0 month value --- libs/common/src/autofill/utils.spec.ts | 4 +++- libs/common/src/autofill/utils.ts | 29 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/libs/common/src/autofill/utils.spec.ts b/libs/common/src/autofill/utils.spec.ts index b09dc723b8..516a09e03d 100644 --- a/libs/common/src/autofill/utils.spec.ts +++ b/libs/common/src/autofill/utils.spec.ts @@ -86,6 +86,8 @@ function getCardExpiryDateValues() { // `Date` months are zero-indexed, our expiry date month inputs are one-indexed const currentMonth = currentDate.getMonth() + 1; + const currentDateLastMonth = new Date(currentDate.setMonth(-1)); + return [ [null, null, false], // no month, no year [undefined, undefined, false], // no month, no year, invalid values @@ -103,7 +105,7 @@ function getCardExpiryDateValues() { [`${currentMonth + 36}`, `${currentYear - 1}`, true], // even though the month value would put the date 3 years into the future when calculated with `Date`, an explicit year in the past indicates the card is expired [`${currentMonth}`, `${currentYear}`, false], // this year, this month (not expired until the month is over) [`${currentMonth}`, `${currentYear}`.slice(-2), false], // This month, this year (not expired until the month is over) - [`${currentMonth - 1}`, `${currentYear}`, true], // last month + [`${currentDateLastMonth.getMonth() + 1}`, `${currentDateLastMonth.getFullYear()}`, true], // last month [`${currentMonth - 1}`, `${currentYear + 1}`, false], // 11 months from now ]; } diff --git a/libs/common/src/autofill/utils.ts b/libs/common/src/autofill/utils.ts index 271952e27d..d9276cdbc8 100644 --- a/libs/common/src/autofill/utils.ts +++ b/libs/common/src/autofill/utils.ts @@ -64,25 +64,32 @@ export function isCardExpired(cipherCard: CardView): boolean { const now = new Date(); const normalizedYear = normalizeExpiryYearFormat(expYear); + const parsedYear = parseInt(normalizedYear, 10); - // If the card year is before the current year, don't bother checking the month - if (normalizedYear && parseInt(normalizedYear, 10) < now.getFullYear()) { + const expiryYearIsBeforeThisYear = parsedYear < now.getFullYear(); + const expiryYearIsAfterThisYear = parsedYear > now.getFullYear(); + + // If the expiry year is before the current year, skip checking the month, since it must be expired + if (normalizedYear && expiryYearIsBeforeThisYear) { return true; } + // If the expiry year is after the current year, skip checking the month, since it cannot be expired + if (normalizedYear && expiryYearIsAfterThisYear) { + return false; + } + if (normalizedYear && expMonth) { const parsedMonthInteger = parseInt(expMonth, 10); + const parsedMonthIsInvalid = !parsedMonthInteger || isNaN(parsedMonthInteger); - const parsedMonth = isNaN(parsedMonthInteger) - ? 0 - : // Add a month floor of 0 to protect against an invalid low month value of "0" or negative integers - Math.max( - // `Date` months are zero-indexed - parsedMonthInteger - 1, - 0, - ); + // If the parsed month value is 0, we don't know when the expiry passes this year, so treat it as expired + if (parsedMonthIsInvalid) { + return true; + } - const parsedYear = parseInt(normalizedYear, 10); + // `Date` months are zero-indexed + const parsedMonth = parsedMonthInteger - 1; // First day of the next month const cardExpiry = new Date(parsedYear, parsedMonth + 1, 1);