Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix spacing for AMEX and Discover cards #4672

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ internal object CardNumberFixtures {
const val UNIONPAY_WITH_SPACES = "6200 0000 0000 0005"
val UNIONPAY_BIN = UNIONPAY_NO_SPACES.take(6)
val UNIONPAY = CardNumber.Unvalidated(UNIONPAY_NO_SPACES)

const val UNIONPAY_19_NO_SPACES = "6200500000000000004"
const val UNIONPAY_19_WITH_SPACES = "6200 5000 0000 0000 004"
val UNIONPAY_19_BIN = UNIONPAY_19_NO_SPACES.take(6)
val UNIONPAY_19 = CardNumber.Unvalidated(UNIONPAY_19_NO_SPACES)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal class CardNumberVisualTransformation(private val separator: Char) :
var out = ""
for (i in text.indices) {
out += text[i]
if (i == 3 || i == 10) out += separator
if (i == 3 || i == 9) out += separator
}

/**
Expand All @@ -44,7 +44,7 @@ internal class CardNumberVisualTransformation(private val separator: Char) :
val creditCardOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 3) return offset
if (offset <= 10) return offset + 1
if (offset <= 9) return offset + 1
return offset + 2
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.stripe.android.ui.core

import com.stripe.android.cards.CardNumber

/**
* See [Basic test card numbers](https://stripe.com/docs/testing#cards)
*/
internal object CardNumberFixtures {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 This is fantastic! Thanks Elena!

const val AMEX_NO_SPACES = "378282246310005"
const val AMEX_WITH_SPACES = "3782 822463 10005"
val AMEX_BIN = AMEX_NO_SPACES.take(6)
val AMEX = CardNumber.Unvalidated(AMEX_NO_SPACES)

const val VISA_NO_SPACES = "4242424242424242"
const val VISA_WITH_SPACES = "4242 4242 4242 4242"
val VISA_BIN = VISA_NO_SPACES.take(6)
val VISA = CardNumber.Unvalidated(VISA_NO_SPACES)

const val VISA_DEBIT_NO_SPACES = "4000056655665556"
const val VISA_DEBIT_WITH_SPACES = "4000 0566 5566 5556"
val VISA_DEBIT = CardNumber.Unvalidated(VISA_DEBIT_NO_SPACES)

const val MASTERCARD_NO_SPACES = "5555555555554444"
const val MASTERCARD_WITH_SPACES = "5555 5555 5555 4444"
val MASTERCARD_BIN = MASTERCARD_NO_SPACES.take(6)
val MASTERCARD = CardNumber.Unvalidated(MASTERCARD_NO_SPACES)

const val DINERS_CLUB_14_NO_SPACES = "36227206271667"
const val DINERS_CLUB_14_WITH_SPACES = "3622 720627 1667"
val DINERS_CLUB_14_BIN = DINERS_CLUB_14_NO_SPACES.take(6)
val DINERS_CLUB_14 = CardNumber.Unvalidated(DINERS_CLUB_14_NO_SPACES)

const val DINERS_CLUB_16_NO_SPACES = "3056930009020004"
const val DINERS_CLUB_16_WITH_SPACES = "3056 9300 0902 0004"
val DINERS_CLUB_16_BIN = DINERS_CLUB_16_NO_SPACES.take(6)
val DINERS_CLUB_16 = CardNumber.Unvalidated(DINERS_CLUB_16_NO_SPACES)

const val DISCOVER_NO_SPACES = "6011000990139424"
const val DISCOVER_WITH_SPACES = "6011 0009 9013 9424"
val DISCOVER_BIN = DISCOVER_NO_SPACES.take(6)
val DISCOVER = CardNumber.Unvalidated(DISCOVER_NO_SPACES)

const val JCB_NO_SPACES = "3566002020360505"
const val JCB_WITH_SPACES = "3566 0020 2036 0505"
val JCB_BIN = JCB_NO_SPACES.take(6)
val JCB = CardNumber.Unvalidated(JCB_NO_SPACES)

const val UNIONPAY_NO_SPACES = "6200000000000005"
const val UNIONPAY_WITH_SPACES = "6200 0000 0000 0005"
val UNIONPAY_BIN = UNIONPAY_NO_SPACES.take(6)
val UNIONPAY = CardNumber.Unvalidated(UNIONPAY_NO_SPACES)

const val UNIONPAY_19_NO_SPACES = "6200500000000000004"
const val UNIONPAY_19_WITH_SPACES = "6200 5000 0000 0000 004"
val UNIONPAY_19_BIN = UNIONPAY_19_NO_SPACES.take(6)
val UNIONPAY_19 = CardNumber.Unvalidated(UNIONPAY_19_NO_SPACES)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.stripe.android.ui.core.elements
import androidx.compose.ui.text.AnnotatedString
import com.google.common.truth.Truth
import com.stripe.android.model.CardBrand
import com.stripe.android.ui.core.CardNumberFixtures
import com.stripe.android.ui.core.R
import org.junit.Test

Expand All @@ -11,8 +12,26 @@ class CardNumberConfigTest {

@Test
fun `visualTransformation formats entered value`() {
Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString("1234567890123456")).text)
.isEqualTo(AnnotatedString("1234 5678 9012 3456"))
Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.VISA_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.VISA_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.AMEX_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.AMEX_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.DISCOVER_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.DISCOVER_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.DINERS_CLUB_14_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.DINERS_CLUB_14_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.DINERS_CLUB_16_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.DINERS_CLUB_16_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.JCB_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.JCB_WITH_SPACES))

Truth.assertThat(cardNumberConfig.visualTransformation.filter(AnnotatedString(CardNumberFixtures.UNIONPAY_NO_SPACES)).text)
.isEqualTo(AnnotatedString(CardNumberFixtures.UNIONPAY_WITH_SPACES))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class DateConfigTest {
.isInstanceOf(TextFieldStateConstants.Error.Invalid::class.java)
Truth.assertThat(
state.getError()?.errorMessage
).isEqualTo(R.string.incomplete_expiry_date)
).isEqualTo(R.string.invalid_expiry_year)
}

@Test
Expand Down Expand Up @@ -123,10 +123,10 @@ class DateConfigTest {
)
)
Truth.assertThat(state)
.isInstanceOf(TextFieldStateConstants.Error.Incomplete::class.java)
.isInstanceOf(TextFieldStateConstants.Error.Invalid::class.java)
Truth.assertThat(
state.getError()?.errorMessage
).isEqualTo(R.string.incomplete_expiry_date)
).isEqualTo(R.string.invalid_expiry_month)
}

@Test
Expand All @@ -142,7 +142,7 @@ class DateConfigTest {
.isInstanceOf(TextFieldStateConstants.Error.Invalid::class.java)
Truth.assertThat(
state.getError()?.errorMessage
).isEqualTo(R.string.incomplete_expiry_date)
).isEqualTo(R.string.invalid_expiry_year)
}

@Test
Expand Down Expand Up @@ -209,7 +209,7 @@ class DateConfigTest {

@Test
fun `date is valid 2X month and 2 digit year`() {
val state = dateConfig.determineState("222")
val state = dateConfig.determineState("223")
Truth.assertThat(state)
.isInstanceOf(TextFieldStateConstants.Valid.Full::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object TestUtils {
fun idleLooper() = ShadowLooper.idleMainLooper()

fun viewModelFactoryFor(viewModel: ViewModel) = object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return viewModel as T
}
}
Expand Down