Skip to content

Commit

Permalink
Support 3 digit AMEX CVC input.
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-stripe committed Apr 10, 2018
1 parent ce103f3 commit 71fac7c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ public Card getCard() {
}

// CVC/CVV is the only field not validated by the entry control itself, so we check here.
int requiredLength = mIsAmEx ? Card.CVC_LENGTH_AMERICAN_EXPRESS : Card.CVC_LENGTH_COMMON;
String cvcValue = mCvcNumberEditText.getText().toString();
if (StripeTextUtils.isBlank(cvcValue) || cvcValue.length() != requiredLength) {
String cvcValue = mCvcNumberEditText.getText().toString().trim();
int cvcLength = cvcValue.length();
if (!(cvcLength == Card.CVC_LENGTH_COMMON
|| (mIsAmEx && cvcLength == Card.CVC_LENGTH_AMERICAN_EXPRESS))) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import android.support.design.widget.TextInputLayout;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.text.InputFilter;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
Expand Down Expand Up @@ -139,8 +140,9 @@ public boolean validateAllFields() {
CardUtils.isValidCardNumber(mCardNumberEditText.getCardNumber());
boolean expiryIsValid = mExpiryDateEditText.getValidDateFields() != null &&
mExpiryDateEditText.isDateValid();
boolean cvcIsValid = ViewUtils.isCvcMaximalLength(
mCardBrand, mCvcEditText.getText().toString());
int cvcLength = mCvcEditText.getText().toString().trim().length();
boolean cvcIsValid = cvcLength == Card.CVC_LENGTH_COMMON
|| (TextUtils.equals(Card.AMERICAN_EXPRESS, mCardBrand) && cvcLength == Card.CVC_LENGTH_AMERICAN_EXPRESS);
mCardNumberEditText.setShouldShowError(!cardNumberIsValid);
mExpiryDateEditText.setShouldShowError(!expiryIsValid);
mCvcEditText.setShouldShowError(!cvcIsValid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public void getCard_whenIncompleteCvCForVisa_returnsNull() {
}

@Test
public void getCard_whenIncompleteCvCForAmEx_returnsNull() {
public void getCard_when3DigitCvCForAmEx_returnsCard() {
// The test will be testing the wrong variable after 2050. Please update the test.
assertTrue(Calendar.getInstance().get(Calendar.YEAR) < 2050);

Expand All @@ -230,6 +230,20 @@ public void getCard_whenIncompleteCvCForAmEx_returnsNull() {
mExpiryEditText.append("50");
mCvcEditText.append("123");

Card card = mCardInputWidget.getCard();
assertNotNull(card);
}

@Test
public void getCard_whenIncompleteCvCForAmEx_returnsNull() {
// The test will be testing the wrong variable after 2050. Please update the test.
assertTrue(Calendar.getInstance().get(Calendar.YEAR) < 2050);

mCardNumberEditText.setText(VALID_AMEX_WITH_SPACES);
mExpiryEditText.append("12");
mExpiryEditText.append("50");
mCvcEditText.append("12");

Card card = mCardInputWidget.getCard();
assertNull(card);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static com.stripe.android.view.CardInputListener.FocusField.FOCUS_CVC;
import static com.stripe.android.view.CardInputListener.FocusField.FOCUS_EXPIRY;
import static com.stripe.android.view.CardInputListener.FocusField.FOCUS_POSTAL;
import static com.stripe.android.view.CardInputTestActivity.VALID_AMEX_NO_SPACES;
import static com.stripe.android.view.CardInputTestActivity.VALID_AMEX_WITH_SPACES;
import static com.stripe.android.view.CardInputTestActivity.VALID_DINERS_CLUB_WITH_SPACES;
import static com.stripe.android.view.CardInputTestActivity.VALID_VISA_NO_SPACES;
Expand Down Expand Up @@ -199,6 +200,50 @@ public void getCard_whenInputIsValidVisaAndNoZipRequired_returnsFullCardAndExpec
assertArrayEquals(EXPECTED_LOGGING_ARRAY, card.getLoggingTokens().toArray());
}

@Test
public void getCard_whenInputIsValidAmexAndNoZipRequiredAnd4DigitCvc_returnsFullCardAndExpectedLogging() {
// The input date here will be invalid after 2050. Please update the test.
assertTrue(Calendar.getInstance().get(Calendar.YEAR) < 2050);

mNoZipGroup.cardNumberEditText.setText(VALID_AMEX_WITH_SPACES);
mNoZipGroup.expiryDateEditText.append("12");
mNoZipGroup.expiryDateEditText.append("50");
mNoZipGroup.cvcEditText.append("1234");
Card card = mNoZipCardMultilineWidget.getCard();
assertNotNull(card);
assertEquals(VALID_AMEX_NO_SPACES, card.getNumber());
assertNotNull(card.getExpMonth());
assertNotNull(card.getExpYear());
assertEquals(12, card.getExpMonth().intValue());
assertEquals(2050, card.getExpYear().intValue());
assertEquals("1234", card.getCVC());
assertNull(card.getAddressZip());
assertTrue(card.validateCard());
assertArrayEquals(EXPECTED_LOGGING_ARRAY, card.getLoggingTokens().toArray());
}

@Test
public void getCard_whenInputIsValidAmexAndNoZipRequiredAnd3DigitCvc_returnsFullCardAndExpectedLogging() {
// The input date here will be invalid after 2050. Please update the test.
assertTrue(Calendar.getInstance().get(Calendar.YEAR) < 2050);

mNoZipGroup.cardNumberEditText.setText(VALID_AMEX_WITH_SPACES);
mNoZipGroup.expiryDateEditText.append("12");
mNoZipGroup.expiryDateEditText.append("50");
mNoZipGroup.cvcEditText.append("123");
Card card = mNoZipCardMultilineWidget.getCard();
assertNotNull(card);
assertEquals(VALID_AMEX_NO_SPACES, card.getNumber());
assertNotNull(card.getExpMonth());
assertNotNull(card.getExpYear());
assertEquals(12, card.getExpMonth().intValue());
assertEquals(2050, card.getExpYear().intValue());
assertEquals("123", card.getCVC());
assertNull(card.getAddressZip());
assertTrue(card.validateCard());
assertArrayEquals(EXPECTED_LOGGING_ARRAY, card.getLoggingTokens().toArray());
}

@Test
public void initView_whenZipRequired_secondRowContainsThreeVisibleElements() {
assertEquals(View.VISIBLE, mFullGroup.expiryDateEditText.getVisibility());
Expand Down

0 comments on commit 71fac7c

Please sign in to comment.