Commit ed84c8ea authored by Danyao Wang's avatar Danyao Wang Committed by Commit Bot

[Payment Request][Android] Enhance SkipToGPay experiment flow.

This patch splits the SkipToGPay experiment into two phases that can be
tested separately per request from early partners:

1) kSkipToGPayIfNoCard: enables skip-to-GPay if and only if user doesn't
   have a usable autofill instrument.
2) kSkipToGPay: enables skip-to-GPay regardless of availability of
   autofill instruments in the user's profile.

Part (1) required an extra lookup from the PersonalDataManager before
dispatching payment app creation. Manual profiling on a Nexus 5 showed
that this added 0.3-19ms extra main thread processing, with average
around 3ms for profiles that contain at least one credit card. This is a
relatively small performance penalty.

Bug: 877284
Change-Id: If465bb1fe0c1f79979cc3743af5474662bd6dd68
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1936107Reviewed-by: default avatarSahel Sharify <sahel@chromium.org>
Commit-Queue: Danyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719402}
parent 87083177
...@@ -306,6 +306,7 @@ chrome_test_java_sources = [ ...@@ -306,6 +306,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java", "javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java",
"javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java", "javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java",
"javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java", "javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
"javatests/src/org/chromium/chrome/browser/payments/SkipToGPayHelperTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerChangePaymentMethodTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerChangePaymentMethodTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerEnableDelegationsTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerEnableDelegationsTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java",
......
...@@ -301,6 +301,8 @@ public abstract class ChromeFeatureList { ...@@ -301,6 +301,8 @@ public abstract class ChromeFeatureList {
"PasswordManagerOnboardingAndroid"; "PasswordManagerOnboardingAndroid";
public static final String PAY_WITH_GOOGLE_V1 = "PayWithGoogleV1"; public static final String PAY_WITH_GOOGLE_V1 = "PayWithGoogleV1";
public static final String PAYMENT_REQUEST_SKIP_TO_GPAY = "PaymentRequestSkipToGPay"; public static final String PAYMENT_REQUEST_SKIP_TO_GPAY = "PaymentRequestSkipToGPay";
public static final String PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD =
"PaymentRequestSkipToGPayIfNoCard";
public static final String PERMISSION_DELEGATION = "PermissionDelegation"; public static final String PERMISSION_DELEGATION = "PermissionDelegation";
public static final String PER_METHOD_CAN_MAKE_PAYMENT_QUOTA = public static final String PER_METHOD_CAN_MAKE_PAYMENT_QUOTA =
"WebPaymentsPerMethodCanMakePaymentQuota"; "WebPaymentsPerMethodCanMakePaymentQuota";
......
...@@ -161,10 +161,14 @@ public class AutofillPaymentInstrument extends PaymentInstrument ...@@ -161,10 +161,14 @@ public class AutofillPaymentInstrument extends PaymentInstrument
public boolean canMakePayment() { public boolean canMakePayment() {
return PaymentsExperimentalFeatures.isEnabled( return PaymentsExperimentalFeatures.isEnabled(
ChromeFeatureList.STRICT_HAS_ENROLLED_AUTOFILL_INSTRUMENT) ChromeFeatureList.STRICT_HAS_ENROLLED_AUTOFILL_INSTRUMENT)
? getMissingFields() == CompletionStatus.COMPLETE && mHaveRequestedAutofillData ? strictCanMakePayment()
: mHasValidNumberAndName; : mHasValidNumberAndName;
} }
public boolean strictCanMakePayment() {
return getMissingFields() == CompletionStatus.COMPLETE && mHaveRequestedAutofillData;
}
@Override @Override
public boolean canPreselect() { public boolean canPreselect() {
return mIsComplete && mIsMatchingMerchantsRequestedCardType; return mIsComplete && mIsMatchingMerchantsRequestedCardType;
......
...@@ -611,8 +611,7 @@ public class PaymentRequestImpl ...@@ -611,8 +611,7 @@ public class PaymentRequestImpl
} }
boolean googlePayBridgeActivated = googlePayBridgeEligible boolean googlePayBridgeActivated = googlePayBridgeEligible
&& PaymentsExperimentalFeatures.isEnabled( && SkipToGPayHelper.canActivateExperiment(mWebContents, methodData);
ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY);
mMethodData = getValidatedMethodData(methodData, googlePayBridgeActivated, mCardEditor); mMethodData = getValidatedMethodData(methodData, googlePayBridgeActivated, mCardEditor);
if (googlePayBridgeActivated) { if (googlePayBridgeActivated) {
......
...@@ -4,17 +4,25 @@ ...@@ -4,17 +4,25 @@
package org.chromium.chrome.browser.payments; package org.chromium.chrome.browser.payments;
import android.support.v4.util.ArrayMap;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONTokener; import org.json.JSONTokener;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.components.payments.MethodStrings; import org.chromium.components.payments.MethodStrings;
import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.GooglePaymentMethodData; import org.chromium.payments.mojom.GooglePaymentMethodData;
import org.chromium.payments.mojom.PaymentAddress; import org.chromium.payments.mojom.PaymentAddress;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
import org.chromium.payments.mojom.PaymentMethodData;
import org.chromium.payments.mojom.PaymentOptions; import org.chromium.payments.mojom.PaymentOptions;
import org.chromium.payments.mojom.PaymentResponse; import org.chromium.payments.mojom.PaymentResponse;
import java.util.List;
import java.util.Map;
/** /**
* A helper to manage the request / response patching for the Skip-to-GPay experimental flow. * A helper to manage the request / response patching for the Skip-to-GPay experimental flow.
* TODO(crbug.com/984694): Retire this helper after general delegation of shipping and contact * TODO(crbug.com/984694): Retire this helper after general delegation of shipping and contact
...@@ -42,6 +50,55 @@ public class SkipToGPayHelper { ...@@ -42,6 +50,55 @@ public class SkipToGPayHelper {
*/ */
private String mSelectedShippingOptionId; private String mSelectedShippingOptionId;
/**
* Returns whether the skip-to-GPay experiment should be enabled.
* @param webContents The WebContents that triggered the PaymentRequest.
* @param rawMethodData The PaymentMethodData[] provided to PaymentRequest constructor.
* @return True if either of the two skip-to-GPay experiment flow can be enabled.
*/
public static boolean canActivateExperiment(
WebContents webContents, PaymentMethodData[] rawMethodData) {
if (rawMethodData == null || rawMethodData.length == 0) return false;
Map<String, PaymentMethodData> methodData = new ArrayMap<>();
for (int i = 0; i < rawMethodData.length; i++) {
String method = rawMethodData[i].supportedMethod;
if (method.equals(MethodStrings.BASIC_CARD)) {
methodData.put(method, rawMethodData[i]);
break;
}
}
if (methodData.isEmpty()) return false;
// V2 experiment: enable skip-to-GPay regardless of usable basic-card.
if (PaymentsExperimentalFeatures.isEnabled(
ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY)) {
return true;
}
// This check for autofill instrument is duplicate work if skip-to-GPay ends up not being
// enabled and adds a small delay (average ~3ms with first time ) to all hybrid request
// flows. However, this is the cleanest way to implement SKIP_TO_GPAY_IF_NO_CARD.
AutofillPaymentApp app = new AutofillPaymentApp(webContents);
List<PaymentInstrument> instruments =
app.getInstruments(methodData, /*forceReturnServerCards=*/false);
boolean hasUsableBasicCard = false;
for (int i = 0; i < instruments.size(); i++) {
PaymentInstrument instrument = instruments.get(i);
instrument.setHaveRequestedAutofillData(true);
if (instrument.isAutofillInstrument()
&& ((AutofillPaymentInstrument) instrument).strictCanMakePayment()) {
hasUsableBasicCard = true;
break;
}
}
// V1 experiment: only enable skip-to-GPay if no usable basic-card exists.
return !hasUsableBasicCard
&& PaymentsExperimentalFeatures.isEnabled(
ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD);
}
/** /**
* Constructs a SkipToGPayHeper. * Constructs a SkipToGPayHeper.
* @param options The PaymentOptions specified by the merchant when constructing the * @param options The PaymentOptions specified by the merchant when constructing the
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.payments;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.CardType;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.payments.MethodStrings;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.payments.mojom.PaymentMethodData;
import java.util.concurrent.TimeoutException;
/**
* An integration test for determining eligibility of SkipToGPay experimental flow.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public final class SkipToGPayHelperTest {
@Rule
public ChromeActivityTestRule<ChromeActivity> mRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
// A test PaymentMethodData[] shared by all test instances.
private PaymentMethodData[] mTestMethodData;
private AutofillTestHelper mHelper;
@Before
public void setUp() {
mRule.startMainActivityOnBlankPage();
mHelper = new AutofillTestHelper();
// Set up a test PaymentMethodData that requests "basic-card".
mTestMethodData = new PaymentMethodData[1];
mTestMethodData[0] = new PaymentMethodData();
mTestMethodData[0].supportedMethod = MethodStrings.BASIC_CARD;
}
private AutofillProfile makeCompleteProfile() {
return new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google",
"340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "650-253-0000",
"jon.doe@gmail.com", "en-US");
}
private CreditCard makeCreditCard(String billingAddressProfileId) {
return new CreditCard("", "https://example.com", true, true, "Jon Doe", "4111111111111111",
"1111", "12", "2050", "amex", R.drawable.amex_card, CardType.UNKNOWN,
billingAddressProfileId, /*serverId=*/"");
}
/**
* Helper function that runs canActivateExperiment() on the main thread and checks that it
* returns |expected|.
*/
void assertCanActivateExperiment(boolean expected) {
TestThreadUtils.runOnUiThreadBlocking(() -> {
Assert.assertEquals(expected,
SkipToGPayHelper.canActivateExperiment(
mRule.getWebContents(), mTestMethodData));
});
}
/**
* Verifies that when PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD is enabled, experiment is not
* activiated if user has a complete autofill instrument.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY,
"enable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD})
public void
testSkipToGPayIfNoCard_HasCard() throws TimeoutException {
String billingAddressProfileId = mHelper.setProfile(makeCompleteProfile());
mHelper.setCreditCard(makeCreditCard(billingAddressProfileId));
assertCanActivateExperiment(false);
}
/**
* Verifies that when PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD is enabled, experiment is
* activated if user doesn't have a complete autofill instrument.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY,
"enable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD})
public void
testSkipToGPayIfNoCard_IncompleteCard() throws TimeoutException {
mHelper.setCreditCard(makeCreditCard(/*billingAddressProfileId=*/""));
assertCanActivateExperiment(true);
}
/**
* Verifies that when PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD is enabled, experiment is
* activated if user doesn't have any autofill instrument.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY,
"enable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD})
public void
testSkipToGPayIfNoCard_NoCard() throws TimeoutException {
assertCanActivateExperiment(true);
}
/**
* Verifies that when PAYMENT_REQUEST_SKIP_TO_GPAY is enabled, experiment is activated
* regardless whether user has a complete autofill instrument or not.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY})
public void testSkipToGPay_AlwaysEnabled() throws TimeoutException {
// At this point, there is no card in the profile.
assertCanActivateExperiment(true);
// Add a credit card with a complete profile.
String billingAddressProfileId = mHelper.setProfile(makeCompleteProfile());
mHelper.setCreditCard(makeCreditCard(billingAddressProfileId));
assertCanActivateExperiment(true);
}
/**
* Verifies that when both experiment flags are disabled, experiment is not activated when user
* doesn't have any autofill instrument.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY
+ "," + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD})
public void
testSkipToGPayDisabled_NoCard() throws TimeoutException {
assertCanActivateExperiment(false);
}
/**
* Verifies that when both experiment flags are disabled, experiment is not activated when user
* has a complete autofill instrument.
*/
@Test
@SmallTest
@Feature({"Payments"})
@CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY
+ "," + ChromeFeatureList.PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD})
public void
testSkipToGPayDisabled_HasCard() throws TimeoutException {
String billingAddressProfileId = mHelper.setProfile(makeCompleteProfile());
mHelper.setCreditCard(makeCreditCard(billingAddressProfileId));
assertCanActivateExperiment(false);
}
}
...@@ -196,6 +196,7 @@ const base::Feature* kFeaturesExposedToJava[] = { ...@@ -196,6 +196,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&net::features::kCookiesWithoutSameSiteMustBeSecure, &net::features::kCookiesWithoutSameSiteMustBeSecure,
&payments::features::kAlwaysAllowJustInTimePaymentApp, &payments::features::kAlwaysAllowJustInTimePaymentApp,
&payments::features::kPaymentRequestSkipToGPay, &payments::features::kPaymentRequestSkipToGPay,
&payments::features::kPaymentRequestSkipToGPayIfNoCard,
&payments::features::kReturnGooglePayInBasicCard, &payments::features::kReturnGooglePayInBasicCard,
&payments::features::kStrictHasEnrolledAutofillInstrument, &payments::features::kStrictHasEnrolledAutofillInstrument,
&payments::features::kWebPaymentMicrotransaction, &payments::features::kWebPaymentMicrotransaction,
......
...@@ -6,7 +6,11 @@ ...@@ -6,7 +6,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/payments/personal_data_manager_test_util.h"
#include "chrome/test/base/chrome_test_utils.h" #include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/payments/payment_request_test_controller.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/test_event_waiter.h"
#include "components/network_session_configurator/common/network_switches.h" #include "components/network_session_configurator/common/network_switches.h"
#include "components/payments/content/service_worker_payment_app_finder.h" #include "components/payments/content/service_worker_payment_app_finder.h"
#include "components/payments/core/features.h" #include "components/payments/core/features.h"
...@@ -27,14 +31,48 @@ ...@@ -27,14 +31,48 @@
namespace payments { namespace payments {
class HybridRequestSkipUITest : public PlatformBrowserTest { enum SkipToGPayMode {
ALWAYS_SKIP_TO_GPAY,
SKIP_TO_GPAY_IF_NO_CARD,
};
enum SkipToGPayTestConfig {
TEST_HAS_COMPLETE_AUTOFILL_INSTRUMENT,
TEST_INCOMPLETE_AUTOFILL_INSTRUMENT,
TEST_NO_AUTOFILL_INSTRUMENT,
};
// Parameterized test fixture that tests the two skip-to-GPay modes (i.e.
// always-skip and skip-if-no-card) for all three cases of:
// - user has a complete autofill instrument
// - user has an incomplete autofill instrument
// - user doesn't have any autofill instrument
class HybridRequestSkipUITest
: public PlatformBrowserTest,
public PaymentRequestTestObserver,
public testing::WithParamInterface<
std::tuple<SkipToGPayMode, SkipToGPayTestConfig>> {
public: public:
// PaymentRequestTestObserver events that can be waited on by the EventWaiter.
enum TestEvent : int {
SHOW_APPS_READY,
};
HybridRequestSkipUITest() HybridRequestSkipUITest()
: gpay_server_(net::EmbeddedTestServer::TYPE_HTTPS), : gpay_server_(net::EmbeddedTestServer::TYPE_HTTPS),
https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
scoped_feature_list_.InitAndEnableFeature( test_controller_.SetObserver(this);
features::kPaymentRequestSkipToGPay);
if (GetTestMode() == ALWAYS_SKIP_TO_GPAY) {
scoped_feature_list_.InitAndEnableFeature(
features::kPaymentRequestSkipToGPay);
} else {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{features::kPaymentRequestSkipToGPayIfNoCard},
/*disabled_features=*/{features::kPaymentRequestSkipToGPay});
}
} }
~HybridRequestSkipUITest() override {} ~HybridRequestSkipUITest() override {}
void SetUpCommandLine(base::CommandLine* command_line) override { void SetUpCommandLine(base::CommandLine* command_line) override {
...@@ -70,9 +108,40 @@ class HybridRequestSkipUITest : public PlatformBrowserTest { ...@@ -70,9 +108,40 @@ class HybridRequestSkipUITest : public PlatformBrowserTest {
ASSERT_TRUE( ASSERT_TRUE(
NavigateTo(https_server_.GetURL("/hybrid_request_skip_ui_test.html"))); NavigateTo(https_server_.GetURL("/hybrid_request_skip_ui_test.html")));
// Inject autofill instrument based on test config.
if (GetTestConfig() == TEST_HAS_COMPLETE_AUTOFILL_INSTRUMENT) {
autofill::CreditCard card = autofill::test::GetCreditCard();
autofill::AutofillProfile address = autofill::test::GetFullProfile();
test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(),
address);
card.set_billing_address_id(address.guid());
test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), card);
} else if (GetTestConfig() == TEST_INCOMPLETE_AUTOFILL_INSTRUMENT) {
autofill::CreditCard card = autofill::test::GetCreditCard();
test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), card);
}
test_controller_.SetUpOnMainThread();
PlatformBrowserTest::SetUpOnMainThread(); PlatformBrowserTest::SetUpOnMainThread();
} }
// PaymentRequestTestObserver
void OnShowAppsReady() override {
if (event_waiter_)
event_waiter_->OnEvent(TestEvent::SHOW_APPS_READY);
}
void ResetEventWaiterForSequence(std::list<TestEvent> event_sequence) {
event_waiter_ = std::make_unique<autofill::EventWaiter<TestEvent>>(
std::move(event_sequence));
}
void WaitForObservedEvent() { event_waiter_->Wait(); }
// Convenience methods for accessing the test parameterization.
SkipToGPayMode GetTestMode() const { return std::get<0>(GetParam()); }
SkipToGPayTestConfig GetTestConfig() const { return std::get<1>(GetParam()); }
content::WebContents* GetActiveWebContents() { content::WebContents* GetActiveWebContents() {
return chrome_test_utils::GetActiveWebContents(this); return chrome_test_utils::GetActiveWebContents(this);
} }
...@@ -81,108 +150,112 @@ class HybridRequestSkipUITest : public PlatformBrowserTest { ...@@ -81,108 +150,112 @@ class HybridRequestSkipUITest : public PlatformBrowserTest {
return content::NavigateToURL(GetActiveWebContents(), url); return content::NavigateToURL(GetActiveWebContents(), url);
} }
void InstallPaymentApp() { // Runs a single test case and checks that |expected_result| is returned.
ASSERT_TRUE(NavigateTo(gpay_server_.GetURL("google.com", "/install.html"))); void RunTest(const char* js_snippet, const char* expected_result) {
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), "installPaymentApp()")); if (GetTestMode() == SKIP_TO_GPAY_IF_NO_CARD &&
GetTestConfig() == TEST_HAS_COMPLETE_AUTOFILL_INSTRUMENT) {
// Skip-to-GPay is not activated in this combination because user has a
// usable autofill instrument. Just verify that the payment sheet is
// shown.
ResetEventWaiterForSequence({TestEvent::SHOW_APPS_READY});
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), js_snippet));
WaitForObservedEvent();
return;
}
// Skip-to-GPay should have been activated. Verify result.
EXPECT_EQ(expected_result,
content::EvalJs(GetActiveWebContents(), js_snippet));
} }
protected: protected:
net::EmbeddedTestServer gpay_server_; net::EmbeddedTestServer gpay_server_;
net::EmbeddedTestServer https_server_; net::EmbeddedTestServer https_server_;
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
PaymentRequestTestController test_controller_;
std::unique_ptr<autofill::EventWaiter<TestEvent>> event_waiter_;
}; };
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, NothingRequested) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, NothingRequested) {
EXPECT_EQ( RunTest("buy({apiVersion: 1})",
"{\"details\":{\"apiVersion\":1},\"shippingAddress\":null," "{\"details\":{\"apiVersion\":1},\"shippingAddress\":null,"
"\"shippingOption\":null,\"payerName\":null,\"payerEmail\":null," "\"shippingOption\":null,\"payerName\":null,\"payerEmail\":null,"
"\"payerPhone\":null}", "\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(), "buy({apiVersion: 1})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, ShippingRequested_V1) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, ShippingRequested_V1) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 1, requestShipping: true})",
"{\"details\":{\"apiVersion\":1},\"shippingAddress\":{\"country\":\"CA\"," "{\"details\":{\"apiVersion\":1},\"shippingAddress\":{\"country\":\"CA\","
"\"addressLine\":[\"123 Main Street\",\"Unit " "\"addressLine\":[\"123 Main Street\",\"Unit "
"A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\"," "A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\","
"\"postalCode\":\"12345\",\"sortingCode\":\"\",\"organization\":\"\"," "\"postalCode\":\"12345\",\"sortingCode\":\"\",\"organization\":\"\","
"\"recipient\":\"Browser " "\"recipient\":\"Browser "
"Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\"," "Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\","
"\"payerName\":null,\"payerEmail\":null,\"payerPhone\":null}", "\"payerName\":null,\"payerEmail\":null,\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 1, requestShipping: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, ShippingRequested_V2) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, ShippingRequested_V2) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 2, requestShipping: true})",
"{\"details\":{\"apiVersion\":2},\"shippingAddress\":{\"country\":\"CA\"," "{\"details\":{\"apiVersion\":2},\"shippingAddress\":{\"country\":\"CA\","
"\"addressLine\":[\"123 Main Street\",\"Unit " "\"addressLine\":[\"123 Main Street\",\"Unit "
"A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\"," "A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\","
"\"postalCode\":\"12345\",\"sortingCode\":\"\",\"organization\":\"\"," "\"postalCode\":\"12345\",\"sortingCode\":\"\",\"organization\":\"\","
"\"recipient\":\"Browser " "\"recipient\":\"Browser "
"Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\"," "Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\","
"\"payerName\":null,\"payerEmail\":null,\"payerPhone\":null}", "\"payerName\":null,\"payerEmail\":null,\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 2, requestShipping: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, EmailRequested_V1) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, EmailRequested_V1) {
EXPECT_EQ( RunTest("buy({apiVersion: 1, requestEmail: true})",
"{\"details\":{\"apiVersion\":1},\"shippingAddress\":null," "{\"details\":{\"apiVersion\":1},\"shippingAddress\":null,"
"\"shippingOption\":null,\"payerName\":null,\"payerEmail\":" "\"shippingOption\":null,\"payerName\":null,\"payerEmail\":"
"\"paymentrequest@chromium.org\",\"payerPhone\":null}", "\"paymentrequest@chromium.org\",\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 1, requestEmail: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, EmailRequested_V2) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, EmailRequested_V2) {
EXPECT_EQ( RunTest("buy({apiVersion: 2, requestEmail: true})",
"{\"details\":{\"apiVersion\":2},\"shippingAddress\":null," "{\"details\":{\"apiVersion\":2},\"shippingAddress\":null,"
"\"shippingOption\":null,\"payerName\":null,\"payerEmail\":" "\"shippingOption\":null,\"payerName\":null,\"payerEmail\":"
"\"paymentrequest@chromium.org\",\"payerPhone\":null}", "\"paymentrequest@chromium.org\",\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 2, requestEmail: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, NameRequested_V1) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, NameRequested_V1) {
EXPECT_EQ( RunTest("buy({apiVersion: 1, requestName: true})",
"{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":" "{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":"
"null,\"shippingOption\":null,\"payerName\":\"Browser " "null,\"shippingOption\":null,\"payerName\":\"Browser "
"Test\",\"payerEmail\":null,\"payerPhone\":null}", "Test\",\"payerEmail\":null,\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 1, requestName: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, NameRequested_V2) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, NameRequested_V2) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 2, requestName: true})",
"{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\"," "{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\","
"\"info\":{}}},\"shippingAddress\":null,\"shippingOption\":null," "\"info\":{}}},\"shippingAddress\":null,\"shippingOption\":null,"
"\"payerName\":\"BrowserTest\",\"payerEmail\":null,\"payerPhone\":null}", "\"payerName\":\"BrowserTest\",\"payerEmail\":null,\"payerPhone\":null}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 2, requestName: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, PhoneRequested_V1) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, PhoneRequested_V1) {
EXPECT_EQ( RunTest("buy({apiVersion: 1, requestPhone: true})",
"{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":" "{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":"
"null,\"shippingOption\":null,\"payerName\":null,\"payerEmail\":null," "null,\"shippingOption\":null,\"payerName\":null,\"payerEmail\":null,"
"\"payerPhone\":\"+1 234-567-8900\"}", "\"payerPhone\":\"+1 234-567-8900\"}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 1, requestPhone: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, PhoneRequested_V2) { // stuck IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, PhoneRequested_V2) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 2, requestPhone: true})",
"{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\"," "{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\","
"\"info\":{}}},\"shippingAddress\":null,\"shippingOption\":null," "\"info\":{}}},\"shippingAddress\":null,\"shippingOption\":null,"
"\"payerName\":null,\"payerEmail\":null,\"payerPhone\":\"+1 " "\"payerName\":null,\"payerEmail\":null,\"payerPhone\":\"+1 "
"234-567-8900\"}", "234-567-8900\"}");
content::EvalJs(GetActiveWebContents(),
"buy({apiVersion: 2, requestPhone: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V1) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, AllRequested_V1) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 1, requestShipping: true, requestEmail: "
"true, requestName: true, requestPhone: true})",
"{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":{" "{\"details\":{\"apiVersion\":1,\"cardInfo\":{}},\"shippingAddress\":{"
"\"country\":\"CA\",\"addressLine\":[\"123 Main Street\",\"Unit " "\"country\":\"CA\",\"addressLine\":[\"123 Main Street\",\"Unit "
"A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\"," "A\"],\"region\":\"ON\",\"city\":\"Toronto\",\"dependentLocality\":\"\","
...@@ -191,15 +264,13 @@ IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V1) { ...@@ -191,15 +264,13 @@ IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V1) {
"Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\"," "Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\","
"\"payerName\":\"Browser " "\"payerName\":\"Browser "
"Test\",\"payerEmail\":\"paymentrequest@chromium.org\",\"payerPhone\":\"+" "Test\",\"payerEmail\":\"paymentrequest@chromium.org\",\"payerPhone\":\"+"
"1 234-567-8900\"}", "1 234-567-8900\"}");
content::EvalJs(
GetActiveWebContents(),
"buy({apiVersion: 1, requestShipping: true, requestEmail: "
"true, requestName: true, requestPhone: true})"));
} }
IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V2) { IN_PROC_BROWSER_TEST_P(HybridRequestSkipUITest, AllRequested_V2) {
EXPECT_EQ( RunTest(
"buy({apiVersion: 2, requestShipping: true, requestEmail: "
"true, requestName: true, requestPhone: true})",
"{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\"," "{\"details\":{\"apiVersion\":2,\"paymentMethodData\":{\"type\":\"CARD\","
"\"info\":{}}},\"shippingAddress\":{\"country\":\"CA\",\"addressLine\":[" "\"info\":{}}},\"shippingAddress\":{\"country\":\"CA\",\"addressLine\":["
"\"123 Main Street\",\"Unit " "\"123 Main Street\",\"Unit "
...@@ -208,11 +279,16 @@ IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V2) { ...@@ -208,11 +279,16 @@ IN_PROC_BROWSER_TEST_F(HybridRequestSkipUITest, AllRequested_V2) {
"\"recipient\":\"Browser " "\"recipient\":\"Browser "
"Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\"," "Test\",\"phone\":\"\"},\"shippingOption\":\"free-shipping\","
"\"payerName\":\"BrowserTest\",\"payerEmail\":\"paymentrequest@chromium." "\"payerName\":\"BrowserTest\",\"payerEmail\":\"paymentrequest@chromium."
"org\",\"payerPhone\":\"+1 234-567-8900\"}", "org\",\"payerPhone\":\"+1 234-567-8900\"}");
content::EvalJs(
GetActiveWebContents(),
"buy({apiVersion: 2, requestShipping: true, requestEmail: "
"true, requestName: true, requestPhone: true})"));
} }
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
HybridRequestSkipUITest,
::testing::Combine(::testing::Values(ALWAYS_SKIP_TO_GPAY,
SKIP_TO_GPAY_IF_NO_CARD),
::testing::Values(TEST_HAS_COMPLETE_AUTOFILL_INSTRUMENT,
TEST_INCOMPLETE_AUTOFILL_INSTRUMENT,
TEST_NO_AUTOFILL_INSTRUMENT)));
} // namespace payments } // namespace payments
...@@ -50,6 +50,9 @@ const base::Feature kStrictHasEnrolledAutofillInstrument{ ...@@ -50,6 +50,9 @@ const base::Feature kStrictHasEnrolledAutofillInstrument{
const base::Feature kPaymentRequestSkipToGPay{ const base::Feature kPaymentRequestSkipToGPay{
"PaymentRequestSkipToGPay", base::FEATURE_DISABLED_BY_DEFAULT}; "PaymentRequestSkipToGPay", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPaymentRequestSkipToGPayIfNoCard{
"PaymentRequestSkipToGPayIfNoCard", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kWebPaymentMicrotransaction{ const base::Feature kWebPaymentMicrotransaction{
"WebPaymentMicrotransaction", base::FEATURE_DISABLED_BY_DEFAULT}; "WebPaymentMicrotransaction", base::FEATURE_DISABLED_BY_DEFAULT};
......
...@@ -53,9 +53,13 @@ extern const base::Feature kWebPaymentsRedactShippingAddress; ...@@ -53,9 +53,13 @@ extern const base::Feature kWebPaymentsRedactShippingAddress;
// hasEnrolledInstrument() queries. // hasEnrolledInstrument() queries.
extern const base::Feature kStrictHasEnrolledAutofillInstrument; extern const base::Feature kStrictHasEnrolledAutofillInstrument;
// Used to enable skip-to-GPay experimental flow. // Enables skip-to-GPay experimental flow.
extern const base::Feature kPaymentRequestSkipToGPay; extern const base::Feature kPaymentRequestSkipToGPay;
// Enables skip-to-GPay experimental flow, but only if user doesn't have an
// eligible credit card.
extern const base::Feature kPaymentRequestSkipToGPayIfNoCard;
// Controls whether the microtransaction features are enabled. // Controls whether the microtransaction features are enabled.
extern const base::Feature kWebPaymentMicrotransaction; extern const base::Feature kWebPaymentMicrotransaction;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment