Skip to content

Commit 65120ba

Browse files
committed
Add CardFields Analytic events
1 parent a453091 commit 65120ba

3 files changed

Lines changed: 70 additions & 3 deletions

File tree

UIComponents/src/main/java/com/braintreepayments/api/uicomponents/UIComponentsAnalytics.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ internal object UIComponentsAnalytics {
88
const val VENMO_BUTTON_PRESENTED = "ui-components:venmo-button:presented"
99
const val VENMO_BUTTON_SELECTED = "ui-components:venmo-button:selected"
1010

11+
const val CARD_FIELDS_PRESENTED = "ui-components:card-fields:presented"
12+
const val CARD_FIELDS_VALIDATED = "ui-components:card-fields:validated"
13+
1114
const val UI_TYPE_COMPOSE = "compose"
1215
const val UI_TYPE_XML_VIEW = "xml"
1316
}

UIComponents/src/main/java/com/braintreepayments/api/uicomponents/cardfields/CardFields.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import android.widget.FrameLayout
99
import com.braintreepayments.api.card.Card
1010
import com.braintreepayments.api.card.CardClient
1111
import com.braintreepayments.api.card.CardResult
12+
import com.braintreepayments.api.core.AnalyticsClient
13+
import com.braintreepayments.api.core.AnalyticsEventParams
1214
import com.braintreepayments.api.core.BraintreeException
1315
import com.braintreepayments.api.uicomponents.R
16+
import com.braintreepayments.api.uicomponents.UIComponentsAnalytics
1417
import kotlinx.coroutines.CoroutineScope
1518
import kotlinx.coroutines.MainScope
1619
import kotlinx.coroutines.cancel
@@ -23,7 +26,8 @@ class CardFields internal constructor(
2326
attrs: AttributeSet? = null,
2427
defStyleAttr: Int = 0,
2528
private val viewModel: CardFieldsViewModel = CardFieldsViewModel(),
26-
private var cardClient: CardClient? = null
29+
private var cardClient: CardClient? = null,
30+
private val analyticsClient: AnalyticsClient = AnalyticsClient.lazyInstance.value
2731
) : FrameLayout(context, attrs, defStyleAttr) {
2832

2933
@JvmOverloads
@@ -91,6 +95,10 @@ class CardFields internal constructor(
9195
*/
9296
fun initialize(authorization: String) {
9397
cardClient = CardClient(context, authorization)
98+
analyticsClient.sendEvent(
99+
UIComponentsAnalytics.CARD_FIELDS_PRESENTED,
100+
AnalyticsEventParams(uiType = UIComponentsAnalytics.UI_TYPE_XML_VIEW)
101+
)
94102
}
95103

96104
/**
@@ -127,6 +135,10 @@ class CardFields internal constructor(
127135
)
128136
return
129137
}
138+
analyticsClient.sendEvent(
139+
UIComponentsAnalytics.CARD_FIELDS_VALIDATED,
140+
AnalyticsEventParams(uiType = UIComponentsAnalytics.UI_TYPE_XML_VIEW)
141+
)
130142
client.tokenize(buildCard()) { cardResult ->
131143
val result = when (cardResult) {
132144
is CardResult.Success -> {

UIComponents/src/test/java/com/braintreepayments/api/uicomponents/cardfields/CardFieldsUnitTest.kt

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ import com.braintreepayments.api.card.CardClient
1010
import com.braintreepayments.api.card.CardNonce
1111
import com.braintreepayments.api.card.CardResult
1212
import com.braintreepayments.api.card.CardTokenizeCallback
13+
import com.braintreepayments.api.core.AnalyticsClient
14+
import com.braintreepayments.api.core.AnalyticsEventParams
1315
import com.braintreepayments.api.core.BraintreeException
1416
import com.braintreepayments.api.uicomponents.R
17+
import com.braintreepayments.api.uicomponents.UIComponentsAnalytics
1518
import com.braintreepayments.api.uicomponents.util.CoroutineTestRule
1619
import io.mockk.Runs
1720
import io.mockk.every
@@ -44,6 +47,7 @@ class CardFieldsUnitTest {
4447
private lateinit var activity: Activity
4548
private lateinit var viewModel: CardFieldsViewModel
4649
private val cardClient: CardClient = mockk(relaxed = true)
50+
private val analyticsClient: AnalyticsClient = mockk(relaxed = true)
4751

4852
// Controllable backing flows so each test can drive the ViewModel's outputs directly.
4953
private val cardNumberValidation = MutableStateFlow<ValidationResult>(ValidationResult.Validating)
@@ -64,10 +68,11 @@ class CardFieldsUnitTest {
6468
every { viewModel.isFormValid } returns isFormValid
6569
}
6670

67-
private fun createCardFields() = CardFields(activity, viewModel = viewModel)
71+
private fun createCardFields() =
72+
CardFields(activity, viewModel = viewModel, analyticsClient = analyticsClient)
6873

6974
private fun createCardFieldsWithClient() =
70-
CardFields(activity, viewModel = viewModel, cardClient = cardClient)
75+
CardFields(activity, viewModel = viewModel, cardClient = cardClient, analyticsClient = analyticsClient)
7176

7277
private fun CardFields.attach() = activity.setContentView(this)
7378

@@ -476,6 +481,53 @@ class CardFieldsUnitTest {
476481

477482
// endregion
478483

484+
// region Analytics
485+
486+
@Test
487+
fun `initialize sends the card fields presented event`() {
488+
val cardFields = createCardFields()
489+
490+
cardFields.initialize("fake-authorization")
491+
492+
verify {
493+
analyticsClient.sendEvent(
494+
UIComponentsAnalytics.CARD_FIELDS_PRESENTED,
495+
AnalyticsEventParams(uiType = UIComponentsAnalytics.UI_TYPE_XML_VIEW)
496+
)
497+
}
498+
}
499+
500+
@Test
501+
fun `submit sends the card fields validated event`() {
502+
val cardFields = createCardFieldsWithClient()
503+
504+
cardFields.submit()
505+
506+
verify {
507+
analyticsClient.sendEvent(
508+
UIComponentsAnalytics.CARD_FIELDS_VALIDATED,
509+
AnalyticsEventParams(uiType = UIComponentsAnalytics.UI_TYPE_XML_VIEW)
510+
)
511+
}
512+
}
513+
514+
@Test
515+
fun `submit before initialize does not send the validated event`() {
516+
val cardFields = createCardFields()
517+
cardFields.setCardFieldsResultCallback { }
518+
519+
cardFields.submit()
520+
521+
verify(exactly = 0) {
522+
analyticsClient.sendEvent(
523+
UIComponentsAnalytics.CARD_FIELDS_VALIDATED,
524+
any()
525+
)
526+
}
527+
}
528+
529+
// endregion
530+
479531
private fun EditText.lengthFilterMax(): Int =
480532
filters.filterIsInstance<InputFilter.LengthFilter>().first().max
481533
}

0 commit comments

Comments
 (0)