Skip to content

Commit

Permalink
Add Analytics Event Params object (#1031)
Browse files Browse the repository at this point in the history
* Add Analytics Event Payload data class

* Update sendAnalyticsEvent: change multiple parameter with payload object

* Update LocalPayment UTs

* Update PayPalClient UTs

* Update VenmoClient UTs

* Update VisaCheckoutClient UTs

* Update AnalytisEventPayload to AnalytisEventParams

* Fix lint

* Add RestrictTo and remove public access level

* Remove Builder pattern

* Update BraintreeClient sendAnalyticsEvent method

* Fix UTs

* Add note

Co-authored-by: sshropshire <[email protected]>

---------

Co-authored-by: sshropshire <[email protected]>
  • Loading branch information
richherrera and sshropshire authored Jun 12, 2024
1 parent 1f14788 commit ed61372
Show file tree
Hide file tree
Showing 11 changed files with 640 additions and 138 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.braintreepayments.api

import androidx.annotation.RestrictTo

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class AnalyticsEventParams constructor(
var payPalContextId: String?,
var linkType: String?,
var isVaultRequest: Boolean,
) {
// TODO: this is a convenience constructor for Java; remove after Kotlin migration is complete
constructor() : this(null, null, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,20 +188,18 @@ open class BraintreeClient @VisibleForTesting internal constructor(
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun sendAnalyticsEvent(
eventName: String,
payPalContextId: String? = null,
linkType: String? = null,
isVaultRequest: Boolean = false
params: AnalyticsEventParams = AnalyticsEventParams()
) {
getAuthorization { authorization, _ ->
if (authorization != null) {
getConfiguration { configuration, _ ->
val isVenmoInstalled = deviceInspector.isVenmoInstalled(applicationContext)
val event = AnalyticsEvent(
eventName,
payPalContextId,
linkType,
params.payPalContextId,
params.linkType,
venmoInstalled = isVenmoInstalled,
isVaultRequest = isVaultRequest
isVaultRequest = params.isVaultRequest
)
sendAnalyticsEvent(event, configuration, authorization)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ public void onResult(@Nullable LocalPaymentNonce localPaymentNonce, @Nullable Ex

private void sendAnalyticsEvent(String paymentType, String eventSuffix) {
String eventPrefix = (paymentType == null) ? "unknown" : paymentType;
braintreeClient.sendAnalyticsEvent(String.format("%s.%s", eventPrefix, eventSuffix), payPalContextId);
AnalyticsEventParams eventParameters = new AnalyticsEventParams();
eventParameters.setPayPalContextId(payPalContextId);
braintreeClient.sendAnalyticsEvent(String.format("%s.%s", eventPrefix, eventSuffix), eventParameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,22 @@ public void startPayment_success_sendsAnalyticsEvents() {
LocalPaymentApi localPaymentApi = new MockLocalPaymentApiBuilder()
.createPaymentMethodSuccess(mock(LocalPaymentResult.class))
.build();
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
LocalPaymentRequest request = getIdealLocalPaymentRequest();
sut.startPayment(request, localPaymentStartCallback);

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.start-payment.selected", null);
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.create.succeeded", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.start-payment.selected"),
payloadCaptor.capture()
);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.create.succeeded"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand All @@ -229,16 +238,24 @@ public void startPayment_success_withEmptyPaymentId_sendsAnalyticsEvents() {
LocalPaymentApi localPaymentApi = new MockLocalPaymentApiBuilder()
.createPaymentMethodSuccess(localPaymentResult)
.build();
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
LocalPaymentRequest request = getIdealLocalPaymentRequest();
sut.startPayment(request, localPaymentStartCallback);

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.start-payment.selected", null);
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.create.succeeded", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.start-payment.selected"),
payloadCaptor.capture()
);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.create.succeeded"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}


@Test
public void startPayment_success__withPaymentId_sendsAnalyticsEvents() {
BraintreeClient braintreeClient = new MockBraintreeClientBuilder()
Expand All @@ -250,13 +267,23 @@ public void startPayment_success__withPaymentId_sendsAnalyticsEvents() {
LocalPaymentApi localPaymentApi = new MockLocalPaymentApiBuilder()
.createPaymentMethodSuccess(localPaymentResult)
.build();
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
expectedPayload.setPayPalContextId("some-paypal-context-id");
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
LocalPaymentRequest request = getIdealLocalPaymentRequest();
sut.startPayment(request, localPaymentStartCallback);

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.start-payment.selected", null);
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.create.succeeded", "some-paypal-context-id");
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.start-payment.selected"),
payloadCaptor.capture()
);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.create.succeeded"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}
@Test
public void startPayment_configurationFetchError_forwardsErrorToCallback() {
Expand All @@ -281,13 +308,22 @@ public void startPayment_onLocalPaymentApiError_sendsAnalyticsEvents() {
LocalPaymentApi localPaymentApi = new MockLocalPaymentApiBuilder()
.createPaymentMethodError(new Exception("error"))
.build();
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
LocalPaymentRequest request = getIdealLocalPaymentRequest();
sut.startPayment(request, localPaymentStartCallback);

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.start-payment.selected", null);
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.webswitch.initiate.failed", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.start-payment.selected"),
payloadCaptor.capture()
);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.webswitch.initiate.failed"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand Down Expand Up @@ -432,9 +468,15 @@ public void approvePayment_sendsAnalyticsEvents() {
LocalPaymentRequest request = getIdealLocalPaymentRequest();
String approvalUrl = "https://sample.com/approval?token=sample-token";
LocalPaymentResult transaction = new LocalPaymentResult(request, approvalUrl, "payment-id");
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

sut.approveLocalPayment(activity, transaction);
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.webswitch.initiate.succeeded", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.webswitch.initiate.succeeded"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand Down Expand Up @@ -489,6 +531,8 @@ public void onBrowserSwitchResult_whenResultOK_uriNull_notifiesListenerOfErrorAl
.put("payment-type", "ideal")
.put("merchant-account-id", "local-merchant-account-id"));

AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);
LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
sut.setListener(listener);

Expand All @@ -503,7 +547,11 @@ public void onBrowserSwitchResult_whenResultOK_uriNull_notifiesListenerOfErrorAl
String expectedMessage = "LocalPayment encountered an error, return URL is invalid.";
assertEquals(expectedMessage, exception.getMessage());

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.webswitch-response.invalid", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.webswitch-response.invalid"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand All @@ -524,6 +572,8 @@ public void onBrowserSwitchResult_whenPostFailure_notifiesListenerOfErrorAlongWi
.sessionId("sample-session-id")
.integration("sample-integration-type")
.build();
AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentApi localPaymentApi = new MockLocalPaymentApiBuilder()
.tokenizeError(postError)
Expand All @@ -537,7 +587,11 @@ public void onBrowserSwitchResult_whenPostFailure_notifiesListenerOfErrorAlongWi
sut.onBrowserSwitchResult(activity, browserSwitchResult);

verify(listener).onLocalPaymentFailure(same(postError));
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.tokenize.failed", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.tokenize.failed"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand Down Expand Up @@ -619,12 +673,19 @@ public void onBrowserSwitchResult_whenResultOKAndTokenizationSuccess_sendsAnalyt

when(payPalDataCollector.getClientMetadataId(any(Context.class), same(payPalEnabledConfig), anyBoolean())).thenReturn("client-metadata-id");

AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);

LocalPaymentClient sut = new LocalPaymentClient(activity, lifecycle, braintreeClient, payPalDataCollector, localPaymentApi);
sut.setListener(listener);

sut.onBrowserSwitchResult(activity, browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.tokenize.succeeded", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.tokenize.succeeded"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand Down Expand Up @@ -671,13 +732,19 @@ public void onBrowserSwitchResult_whenResultOKAndUserCancels_notifiesListenerAnd

sut.onBrowserSwitchResult(activity, browserSwitchResult);

AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);
ArgumentCaptor<Exception> exceptionCaptor = ArgumentCaptor.forClass(Exception.class);
verify(listener).onLocalPaymentFailure(exceptionCaptor.capture());

Exception cancelException = exceptionCaptor.getValue();
assertTrue(cancelException instanceof UserCanceledException);
assertEquals("User canceled Local Payment.", cancelException.getMessage());
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.webswitch.canceled", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.webswitch.canceled"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand All @@ -694,13 +761,19 @@ public void onBrowserSwitchResult_whenResultCANCELED_sendsAnalyticsEvent() throw

sut.onBrowserSwitchResult(activity, browserSwitchResult);

AnalyticsEventParams expectedPayload = new AnalyticsEventParams();
ArgumentCaptor<AnalyticsEventParams> payloadCaptor = ArgumentCaptor.forClass(AnalyticsEventParams.class);
ArgumentCaptor<Exception> exceptionCaptor = ArgumentCaptor.forClass(Exception.class);
verify(listener).onLocalPaymentFailure(exceptionCaptor.capture());

Exception cancelException = exceptionCaptor.getValue();
assertTrue(cancelException instanceof UserCanceledException);
assertEquals("User canceled Local Payment.", cancelException.getMessage());
verify(braintreeClient).sendAnalyticsEvent("ideal.local-payment.webswitch.canceled", null);
verify(braintreeClient).sendAnalyticsEvent(
eq("ideal.local-payment.webswitch.canceled"),
payloadCaptor.capture()
);
assertEquals(expectedPayload, payloadCaptor.getValue());
}

@Test
Expand Down
Loading

0 comments on commit ed61372

Please sign in to comment.