1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.payments;
6 
7 import android.support.test.InstrumentationRegistry;
8 import android.view.View;
9 
10 import androidx.test.filters.MediumTest;
11 
12 import org.junit.After;
13 import org.junit.Assert;
14 import org.junit.Before;
15 import org.junit.ClassRule;
16 import org.junit.Rule;
17 import org.junit.Test;
18 import org.junit.runner.RunWith;
19 
20 import org.chromium.base.test.util.CallbackHelper;
21 import org.chromium.base.test.util.CommandLineFlags;
22 import org.chromium.base.test.util.DisabledTest;
23 import org.chromium.base.test.util.Feature;
24 import org.chromium.chrome.R;
25 import org.chromium.chrome.browser.flags.ChromeSwitches;
26 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
27 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
28 import org.chromium.net.test.EmbeddedTestServer;
29 import org.chromium.net.test.ServerCertificate;
30 import org.chromium.ui.test.util.DisableAnimationsTestRule;
31 
32 /** An integration test for shipping address and payer's contact information delegation. */
33 @RunWith(ChromeJUnit4ClassRunner.class)
34 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
35 @MediumTest
36 public class PaymentHandlerEnableDelegationsTest {
37     // Disable animations to reduce flakiness.
38     @ClassRule
39     public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
40 
41     // Open a tab on the blank page first to initiate the native bindings required by the test
42     // server.
43     @Rule
44     public PaymentRequestTestRule mRule = new PaymentRequestTestRule("about:blank", null, true);
45 
46     // Host the tests on https://127.0.0.1, because file:// URLs cannot have service workers.
47     private EmbeddedTestServer mServer;
48 
49     @Before
setUp()50     public void setUp() throws Throwable {
51         mServer = EmbeddedTestServer.createAndStartHTTPSServer(
52                 InstrumentationRegistry.getContext(), ServerCertificate.CERT_OK);
53         mRule.startMainActivityWithURL(
54                 mServer.getURL("/components/test/data/payments/payment_handler.html"));
55 
56         // Find the web contents where JavaScript will be executed and instrument the browser
57         // payment sheet.
58         mRule.openPage();
59     }
60 
installPaymentHandlerWithDelegations(String delegations)61     private void installPaymentHandlerWithDelegations(String delegations) throws Throwable {
62         Assert.assertEquals("\"success\"",
63                 JavaScriptUtils.runJavascriptWithAsyncResult(
64                         mRule.getActivity().getCurrentWebContents(),
65                         "install().then(result => {domAutomationController.send(result);});"));
66         Assert.assertEquals("\"success\"",
67                 JavaScriptUtils.runJavascriptWithAsyncResult(
68                         mRule.getActivity().getCurrentWebContents(),
69                         "enableDelegations(" + delegations
70                                 + ").then(result => {domAutomationController.send(result);});"));
71     }
72 
73     @After
tearDown()74     public void tearDown() {
75         mServer.stopAndDestroyServer();
76     }
77 
createPaymentRequestAndWaitFor(String paymentOptions, CallbackHelper helper)78     private void createPaymentRequestAndWaitFor(String paymentOptions, CallbackHelper helper)
79             throws Throwable {
80         int callCount = helper.getCallCount();
81         Assert.assertEquals("\"success\"",
82                 mRule.runJavaScriptCodeInCurrentTab(
83                         "paymentRequestWithOptions(" + paymentOptions + ");"));
84         helper.waitForCallback(callCount);
85     }
86 
87     @Test
88     @Feature({"Payments"})
89     @MediumTest
testShippingDelegation()90     public void testShippingDelegation() throws Throwable {
91         installPaymentHandlerWithDelegations("['shippingAddress']");
92         // The pay button should be enabled when shipping address is requested and the selected
93         // payment instrument can provide it.
94         createPaymentRequestAndWaitFor("{requestShipping: true}", mRule.getReadyToPay());
95 
96         // Click the pay button and wait for success.
97         mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
98     }
99 
100     @Test
101     @Feature({"Payments"})
102     @MediumTest
testContactDelegation()103     public void testContactDelegation() throws Throwable {
104         installPaymentHandlerWithDelegations("['payerName', 'payerEmail', 'payerPhone']");
105         // The pay button should be enabled when payer's contact information is requested and the
106         // selected payment instrument can provide it.
107         createPaymentRequestAndWaitFor(
108                 "{requestPayerName: true, requestPayerEmail: true, requestPayerPhone: true}",
109                 mRule.getReadyToPay());
110 
111         // Click the pay button and wait for success.
112         mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
113     }
114 
115     @Test
116     @Feature({"Payments"})
117     @MediumTest
118     @DisabledTest(message = "crbug.com/1131674")
testShippingAndContactInfoDelegation()119     public void testShippingAndContactInfoDelegation() throws Throwable {
120         installPaymentHandlerWithDelegations(
121                 "['shippingAddress', 'payerName', 'payerEmail', 'payerPhone']");
122         // The pay button should be enabled when shipping address and payer's contact information
123         // are requested and the selected payment instrument can provide them.
124         createPaymentRequestAndWaitFor(
125                 "{requestShipping: true, requestPayerName: true, requestPayerEmail: true,"
126                         + " requestPayerPhone: true}",
127                 mRule.getReadyToPay());
128 
129         // Click the pay button and wait for success.
130         mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
131     }
132 
133     @Test
134     @Feature({"Payments"})
135     @MediumTest
testPartialDelegationShippingNotSupported()136     public void testPartialDelegationShippingNotSupported() throws Throwable {
137         installPaymentHandlerWithDelegations("['payerName', 'payerEmail', 'payerPhone']");
138         createPaymentRequestAndWaitFor(
139                 "{requestShipping: true, requestPayerName: true, requestPayerEmail: true}",
140                 mRule.getReadyForInput());
141         // Shipping section must exist in payment sheet since shipping address is requested and
142         // won't be provided by the selected payment handler.
143         Assert.assertEquals(View.VISIBLE,
144                 mRule.getPaymentRequestUI().getShippingAddressSectionForTest().getVisibility());
145     }
146 
147     @Test
148     @Feature({"Payments"})
149     @MediumTest
testPartialDelegationContactInfoNotSupported()150     public void testPartialDelegationContactInfoNotSupported() throws Throwable {
151         installPaymentHandlerWithDelegations("['shippingAddress']");
152         createPaymentRequestAndWaitFor(
153                 "{requestShipping: true, requestPayerName: true, requestPayerEmail: true}",
154                 mRule.getReadyForInput());
155         // Contact section must exist in payment sheet since payer's name and email are requested
156         // and won't be provided by the selected payment handler.
157         Assert.assertEquals(View.VISIBLE,
158                 mRule.getPaymentRequestUI().getContactDetailsSectionForTest().getVisibility());
159     }
160 }
161