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 <58225613+sshropshire@users.noreply.github.com>

---------

Co-authored-by: sshropshire <58225613+sshropshire@users.noreply.github.com>
richherrera and sshropshire authored Jun 12, 2024
1 parent 1f14788 commit ed61372
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
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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
@@ -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
@@ -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()
@@ -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() {
@@ -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
@@ -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
@@ -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);

@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
69 changes: 56 additions & 13 deletions PayPal/src/main/java/com/braintreepayments/api/PayPalClient.java
Original file line number Diff line number Diff line change
@@ -214,9 +214,15 @@ public void requestBillingAgreement(@NonNull final FragmentActivity activity, @N
}

private void sendCheckoutRequest(final FragmentActivity activity, final PayPalCheckoutRequest payPalCheckoutRequest, final PayPalFlowStartedCallback callback) {
braintreeClient.sendAnalyticsEvent("paypal.single-payment.selected", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.single-payment.selected",
getAnalyticsParams()
);
if (payPalCheckoutRequest.getShouldOfferPayLater()) {
braintreeClient.sendAnalyticsEvent("paypal.single-payment.paylater.offered", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.single-payment.paylater.offered",
getAnalyticsParams()
);
}

braintreeClient.getConfiguration(new ConfigurationCallback() {
@@ -236,7 +242,10 @@ public void onResult(@Nullable final Configuration configuration, @Nullable Exce
try {
assertCanPerformBrowserSwitch(activity);
} catch (BrowserSwitchException browserSwitchException) {
braintreeClient.sendAnalyticsEvent("paypal.invalid-manifest", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.invalid-manifest",
getAnalyticsParams()
);
Exception manifestInvalidError =
createBrowserSwitchError(browserSwitchException);
callback.onResult(manifestInvalidError);
@@ -249,9 +258,15 @@ public void onResult(@Nullable final Configuration configuration, @Nullable Exce
}

private void sendVaultRequest(final FragmentActivity activity, final PayPalVaultRequest payPalVaultRequest, final PayPalFlowStartedCallback callback) {
braintreeClient.sendAnalyticsEvent("paypal.billing-agreement.selected", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.billing-agreement.selected",
getAnalyticsParams()
);
if (payPalVaultRequest.getShouldOfferCredit()) {
braintreeClient.sendAnalyticsEvent("paypal.billing-agreement.credit.offered", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.billing-agreement.credit.offered",
getAnalyticsParams()
);
}

braintreeClient.getConfiguration(new ConfigurationCallback() {
@@ -271,7 +286,10 @@ public void onResult(@Nullable final Configuration configuration, @Nullable Exce
try {
assertCanPerformBrowserSwitch(activity);
} catch (BrowserSwitchException browserSwitchException) {
braintreeClient.sendAnalyticsEvent("paypal.invalid-manifest", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.invalid-manifest",
getAnalyticsParams()
);
Exception manifestInvalidError =
createBrowserSwitchError(browserSwitchException);
callback.onResult(manifestInvalidError);
@@ -289,7 +307,10 @@ public void onResult(@Nullable PayPalResponse payPalResponse, @Nullable Exceptio
if (payPalResponse != null) {
String analyticsPrefix = getAnalyticsEventPrefix(payPalRequest);
payPalContextId = payPalResponse.getPairingId();
braintreeClient.sendAnalyticsEvent(String.format("%s.browser-switch.started", analyticsPrefix), payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
String.format("%s.browser-switch.started", analyticsPrefix),
getAnalyticsParams()
);

try {
startBrowserSwitch(activity, payPalResponse, payPalRequest.isAppLinkEnabled());
@@ -414,7 +435,10 @@ public void onBrowserSwitchResult(@NonNull BrowserSwitchResult browserSwitchResu
switch (result) {
case BrowserSwitchStatus.CANCELED:
callback.onResult(null, new UserCanceledException("User canceled PayPal."));
braintreeClient.sendAnalyticsEvent(String.format("%s.browser-switch.canceled", analyticsPrefix), payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
String.format("%s.browser-switch.canceled", analyticsPrefix),
getAnalyticsParams()
);
break;
case BrowserSwitchStatus.SUCCESS:
try {
@@ -440,22 +464,34 @@ public void onBrowserSwitchResult(@NonNull BrowserSwitchResult browserSwitchResu
@Override
public void onResult(@Nullable PayPalAccountNonce payPalAccountNonce, @Nullable Exception error) {
if (payPalAccountNonce != null && payPalAccountNonce.getCreditFinancing() != null) {
braintreeClient.sendAnalyticsEvent("paypal.credit.accepted", payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
"paypal.credit.accepted",
getAnalyticsParams()
);
}
callback.onResult(payPalAccountNonce, error);
}
});

braintreeClient.sendAnalyticsEvent(String.format("%s.browser-switch.succeeded", analyticsPrefix), payPalContextId, null, isVaultRequest);

braintreeClient.sendAnalyticsEvent(
String.format("%s.browser-switch.succeeded", analyticsPrefix),
getAnalyticsParams()
);
} else {
callback.onResult(null, new BraintreeException("Unknown error"));
}
} catch (UserCanceledException e) {
callback.onResult(null, e);
braintreeClient.sendAnalyticsEvent(String.format("%s.browser-switch.canceled", analyticsPrefix), payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
String.format("%s.browser-switch.canceled", analyticsPrefix),
getAnalyticsParams()
);
} catch (JSONException | PayPalBrowserSwitchException e) {
callback.onResult(null, e);
braintreeClient.sendAnalyticsEvent(String.format("%s.browser-switch.failed", analyticsPrefix), payPalContextId, null, isVaultRequest);
braintreeClient.sendAnalyticsEvent(
String.format("%s.browser-switch.failed", analyticsPrefix),
getAnalyticsParams()
);
}
break;
}
@@ -488,4 +524,11 @@ private JSONObject parseUrlResponseData(Uri uri, String successUrl, String appro
throw new PayPalBrowserSwitchException("The response contained inconsistent data.");
}
}

private AnalyticsEventParams getAnalyticsParams() {
AnalyticsEventParams eventParameters = new AnalyticsEventParams();
eventParameters.setPayPalContextId(payPalContextId);
eventParameters.setVaultRequest(isVaultRequest);
return eventParameters;
}
}
Original file line number Diff line number Diff line change
@@ -290,8 +290,20 @@ public void tokenizePayPalAccount_sendsAnalyticsEvents() {
PayPalClient sut = new PayPalClient(activity, lifecycle, braintreeClient, payPalInternalClient);
sut.tokenizePayPalAccount(activity, payPalVaultRequest);

verify(braintreeClient).sendAnalyticsEvent("paypal.billing-agreement.selected", null, null, true);
verify(braintreeClient).sendAnalyticsEvent("paypal.billing-agreement.browser-switch.started", "BA-1234", null, true);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setVaultRequest(true);

verify(braintreeClient).sendAnalyticsEvent(
"paypal.billing-agreement.selected",
eventParams
);

eventParams.setPayPalContextId("BA-1234");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.billing-agreement.browser-switch.started",
eventParams
);
}

@Test
@@ -430,8 +442,19 @@ public void requestOneTimePayment_sendsBrowserSwitchStartAnalyticsEvent() {
PayPalClient sut = new PayPalClient(activity, lifecycle, braintreeClient, payPalInternalClient);
sut.tokenizePayPalAccount(activity, payPalCheckoutRequest);

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.selected", null, null, false);
verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.started", "EC-1234", null, false);
AnalyticsEventParams eventParams = new AnalyticsEventParams();

verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.selected",
eventParams
);

eventParams.setPayPalContextId("EC-1234");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.started",
eventParams
);
}

@Test
@@ -444,7 +467,10 @@ public void requestOneTimePayment_sendsPayPalPayLaterOfferedAnalyticsEvent() {
request.setShouldOfferPayLater(true);
sut.tokenizePayPalAccount(activity, request);

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.paylater.offered", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.paylater.offered",
new AnalyticsEventParams()
);
}

@Test
@@ -490,7 +516,13 @@ public void tokenizePayPalAccount_sendsPayPalCreditOfferedAnalyticsEvent() {
PayPalClient sut = new PayPalClient(activity, lifecycle, braintreeClient, payPalInternalClient);
sut.tokenizePayPalAccount(activity, payPalRequest);

verify(braintreeClient).sendAnalyticsEvent("paypal.billing-agreement.credit.offered", null, null, true);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setVaultRequest(true);

verify(braintreeClient).sendAnalyticsEvent(
"paypal.billing-agreement.credit.offered",
eventParams
);
}

@Test
@@ -618,7 +650,13 @@ public void onBrowserSwitchResult_withBillingAgreement_sendsAnalyticsEvents() th

sut.onBrowserSwitchResult(browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("paypal.billing-agreement.browser-switch.succeeded", "EC-HERMES-SANDBOX-EC-TOKEN", null, false);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.billing-agreement.browser-switch.succeeded",
eventParams
);
}

@Test
@@ -649,7 +687,10 @@ public void onBrowserSwitchResult_withBillingAgreement_whenBATokenIsEmpty_sendsA

sut.onBrowserSwitchResult(browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("paypal.billing-agreement.browser-switch.succeeded", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.billing-agreement.browser-switch.succeeded",
new AnalyticsEventParams()
);
}

@Test
@@ -680,7 +721,13 @@ public void onBrowserSwitchResult_oneTimePayment_sendsAnalyticsEvents() throws J

sut.onBrowserSwitchResult(browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.succeeded", "EC-HERMES-SANDBOX-EC-TOKEN", null, false);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.succeeded",
eventParams
);
}

public void onBrowserSwitchResult_oneTimePayment_whenTokenIsNull_sendsAnalyticsEvents() throws JSONException {
@@ -772,7 +819,13 @@ public void onBrowserSwitchResult_whenPayPalCreditPresent_sendsAnalyticsEvents()

sut.onBrowserSwitchResult(browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("paypal.credit.accepted", "EC-HERMES-SANDBOX-EC-TOKEN", null, false);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.credit.accepted",
eventParams
);
}

@Test
@@ -804,7 +857,10 @@ public void onBrowserSwitchResult_whenPayPalCreditPresent_whenTokenIsEmpty_sends

sut.onBrowserSwitchResult(browserSwitchResult);

verify(braintreeClient).sendAnalyticsEvent("paypal.credit.accepted", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.credit.accepted",
new AnalyticsEventParams()
);
}

@Test
@@ -842,7 +898,10 @@ public void onBrowserSwitchResult_whenCancelUriReceived_notifiesCancellationAndS
assertEquals("User canceled PayPal.", exception.getMessage());
assertTrue(((UserCanceledException) exception).isExplicitCancelation());

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.canceled", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.canceled",
new AnalyticsEventParams()
);
}

@Test
@@ -880,7 +939,13 @@ public void onBrowserSwitchResult_whenCancelUriReceived_withToken_notifiesCancel
assertEquals("User canceled PayPal.", exception.getMessage());
assertTrue(((UserCanceledException) exception).isExplicitCancelation());

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.canceled", "EC-HERMES-SANDBOX-EC-TOKEN", null, false);
AnalyticsEventParams eventParams = new AnalyticsEventParams();
eventParams.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");

verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.canceled",
eventParams
);
}

@Test
@@ -918,7 +983,10 @@ public void onBrowserSwitchResult_whenCancelUriReceived_whitEmptyToken_notifiesC
assertEquals("User canceled PayPal.", exception.getMessage());
assertTrue(((UserCanceledException) exception).isExplicitCancelation());

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.canceled", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.canceled",
new AnalyticsEventParams()
);
}

@Test
@@ -942,7 +1010,10 @@ public void onBrowserSwitchResult_whenBrowserSwitchCanceled_forwardsExceptionAnd
assertEquals("User canceled PayPal.", exception.getMessage());
assertFalse(((UserCanceledException) exception).isExplicitCancelation());

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.canceled", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.canceled",
new AnalyticsEventParams()
);
}

@Test
@@ -970,7 +1041,10 @@ public void onBrowserSwitchResult_whenBrowserSwitchCanceled_whitEmptyToken_forwa
assertEquals("User canceled PayPal.", exception.getMessage());
assertFalse(((UserCanceledException) exception).isExplicitCancelation());

verify(braintreeClient).sendAnalyticsEvent("paypal.single-payment.browser-switch.canceled", null, null, false);
verify(braintreeClient).sendAnalyticsEvent(
"paypal.single-payment.browser-switch.canceled",
new AnalyticsEventParams()
);
}

@Test
Original file line number Diff line number Diff line change
@@ -85,7 +85,10 @@ public void setListener(PayPalNativeCheckoutListener listener) {
*/
@Deprecated
public void tokenizePayPalAccount(@NonNull final FragmentActivity activity, @NonNull final PayPalNativeRequest payPalRequest) throws Exception {
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.started", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.started",
getAnalyticsParams()
);
// NEXT_MAJOR_VERSION: remove tokenizePayPalAccount method and refactor tests to center
// around launchNativeCheckout in the future. Keeping the tests as they are for now allows
// us to maintain test coverage across both the tokenizePayPalAccount and launchNativeCheckout methods
@@ -94,7 +97,10 @@ public void tokenizePayPalAccount(@NonNull final FragmentActivity activity, @Non
if (isCheckoutRequest || isVaultRequest) {
launchNativeCheckout(activity, payPalRequest);
} else {
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.invalid-request.failed", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.invalid-request.failed",
getAnalyticsParams()
);
String message = "Unsupported request type. Please use either a "
+ "PayPalNativeCheckoutRequest or a PayPalNativeCheckoutVaultRequest.";
throw new Exception(message);
@@ -111,25 +117,43 @@ public void tokenizePayPalAccount(@NonNull final FragmentActivity activity, @Non
* @param payPalRequest a {@link PayPalNativeRequest} used to customize the request.
*/
public void launchNativeCheckout(@NonNull final FragmentActivity activity, @NonNull final PayPalNativeRequest payPalRequest) {
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.started", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.started",
getAnalyticsParams()
);
if (payPalRequest instanceof PayPalNativeCheckoutRequest) {
sendCheckoutRequest(activity, (PayPalNativeCheckoutRequest) payPalRequest);
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.succeeded", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.succeeded",
getAnalyticsParams()
);
} else if (payPalRequest instanceof PayPalNativeCheckoutVaultRequest) {
sendVaultRequest(activity, (PayPalNativeCheckoutVaultRequest) payPalRequest);
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.succeeded", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.succeeded",
getAnalyticsParams()
);
} else if (listener != null) {
braintreeClient.sendAnalyticsEvent("paypal-native.tokenize.invalid-request.failed", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.tokenize.invalid-request.failed",
getAnalyticsParams()
);
String message = "Unsupported request type. Please use either a "
+ "PayPalNativeCheckoutRequest or a PayPalNativeCheckoutVaultRequest.";
listener.onPayPalFailure(new BraintreeException(message));
}
}

private void sendCheckoutRequest(final FragmentActivity activity, final PayPalNativeCheckoutRequest payPalCheckoutRequest) {
braintreeClient.sendAnalyticsEvent("paypal-native.single-payment.selected", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.single-payment.selected",
getAnalyticsParams()
);
if (payPalCheckoutRequest.getShouldOfferPayLater()) {
braintreeClient.sendAnalyticsEvent("paypal-native.single-payment.paylater.offered", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.single-payment.paylater.offered",
getAnalyticsParams()
);
}

braintreeClient.getConfiguration((configuration, error) -> {
@@ -138,9 +162,15 @@ private void sendCheckoutRequest(final FragmentActivity activity, final PayPalNa
}

private void sendVaultRequest(final FragmentActivity activity, final PayPalNativeCheckoutVaultRequest payPalVaultRequest) {
braintreeClient.sendAnalyticsEvent("paypal-native.billing-agreement.selected", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.billing-agreement.selected",
getAnalyticsParams()
);
if (payPalVaultRequest.getShouldOfferCredit()) {
braintreeClient.sendAnalyticsEvent("paypal-native.billing-agreement.credit.offered", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.billing-agreement.credit.offered",
getAnalyticsParams()
);
}

braintreeClient.getConfiguration((configuration, error) -> {
@@ -160,7 +190,10 @@ private void sendPayPalRequest(
payPalContextId = pairingId;
}
String analyticsPrefix = payPalRequest instanceof PayPalNativeCheckoutVaultRequest ? "billing-agreement" : "single-payment";
braintreeClient.sendAnalyticsEvent(String.format("paypal-native.%s.started", analyticsPrefix), payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
String.format("paypal-native.%s.started", analyticsPrefix),
getAnalyticsParams()
);

Environment environment;
if ("sandbox".equals(configuration.getEnvironment())) {
@@ -213,10 +246,16 @@ private void sendPayPalRequest(
PayPalCheckout.startCheckout(createOrderActions -> {
if (payPalRequest instanceof PayPalNativeCheckoutRequest) {
createOrderActions.set(payPalResponse.getPairingId());
braintreeClient.sendAnalyticsEvent("paypal-native.single-payment.succeeded", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.single-payment.succeeded",
getAnalyticsParams()
);
} else if (payPalRequest instanceof PayPalNativeCheckoutVaultRequest) {
createOrderActions.setBillingAgreementId(payPalResponse.getPairingId());
braintreeClient.sendAnalyticsEvent("paypal-native.billing-agreement.succeeded", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.billing-agreement.succeeded",
getAnalyticsParams()
);
}
}, payPalRequest.hasUserLocationConsent());
} else {
@@ -232,25 +271,40 @@ private void registerCallbacks(
) {
PayPalCheckout.registerCallbacks(
approval -> {
braintreeClient.sendAnalyticsEvent("paypal-native.on-approve.started", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.on-approve.started",
getAnalyticsParams()
);
PayPalNativeCheckoutAccount payPalAccount = setupAccount(payPalRequest, approval.getData());
internalPayPalClient.tokenize(payPalAccount, (payPalAccountNonce, error) -> {
if (payPalAccountNonce != null) {
braintreeClient.sendAnalyticsEvent("paypal-native.on-approve.succeeded", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.on-approve.succeeded",
getAnalyticsParams()
);
listener.onPayPalSuccess(payPalAccountNonce);
} else {
braintreeClient.sendAnalyticsEvent("paypal-native.on-approve.failed", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.on-approve.failed",
getAnalyticsParams()
);
listener.onPayPalFailure(new Exception("PaypalAccountNonce is null"));
}
});
},
null,
() -> {
braintreeClient.sendAnalyticsEvent("paypal-native.canceled", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.canceled",
getAnalyticsParams()
);
listener.onPayPalFailure(new Exception("User has canceled"));
},
errorInfo -> {
braintreeClient.sendAnalyticsEvent("paypal-native.on-error.failed", payPalContextId, null, false);
braintreeClient.sendAnalyticsEvent(
"paypal-native.on-error.failed",
getAnalyticsParams()
);
listener.onPayPalFailure(new Exception(errorInfo.getError().getMessage()));
}
);
@@ -306,4 +360,10 @@ PayPalNativeCheckoutAccount setupAccount(

return payPalAccount;
}

private AnalyticsEventParams getAnalyticsParams() {
AnalyticsEventParams eventParameters = new AnalyticsEventParams();
eventParameters.setPayPalContextId(payPalContextId);
return eventParameters;
}
}
153 changes: 124 additions & 29 deletions Venmo/src/main/java/com/braintreepayments/api/VenmoClient.java

Large diffs are not rendered by default.

216 changes: 180 additions & 36 deletions Venmo/src/test/java/com/braintreepayments/api/VenmoClientUnitTest.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -108,13 +108,13 @@ public void onResult(JSONObject tokenizationResponse, Exception exception) {
try {
VisaCheckoutNonce visaCheckoutNonce = VisaCheckoutNonce.fromJSON(tokenizationResponse);
callback.onResult(visaCheckoutNonce, null);
braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.succeeded", null, null, false);
braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.succeeded", new AnalyticsEventParams());
} catch (JSONException e) {
callback.onResult(null, e);
}
} else {
callback.onResult(null, exception);
braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.failed", null, null, false);
braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.failed", new AnalyticsEventParams());
}
}
});
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ class VisaCheckoutClientUnitTest {
val sut = VisaCheckoutClient(braintreeClient, apiClient)
val listener = mockk<VisaCheckoutTokenizeCallback>(relaxed = true)
sut.tokenize(visaPaymentSummary, listener)
verify { braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.succeeded", null, null, false) }
verify { braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.succeeded", AnalyticsEventParams()) }
}

@Test
@@ -165,6 +165,6 @@ class VisaCheckoutClientUnitTest {
val sut = VisaCheckoutClient(braintreeClient, apiClient)
val listener = mockk<VisaCheckoutTokenizeCallback>(relaxed = true)
sut.tokenize(visaPaymentSummary, listener)
verify { braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.failed", null, null,false) }
verify { braintreeClient.sendAnalyticsEvent("visacheckout.tokenize.failed", AnalyticsEventParams()) }
}
}

0 comments on commit ed61372

Please sign in to comment.