Commit de183138 authored by Liquan (Max) Gu's avatar Liquan (Max) Gu Committed by Commit Bot

[ExpandablePaymentHandler] Test UI appearance and user interaction

This CL adds test coverage for the appearance of the Expandable
Payment Handler UI and its user interaction.

Changes:
* Moved the original content of ExpandablePaymentHandlerTest.java into
ExpandablePaymentHandlerCoordinatorTest.java (and change to small-test).
* Added test cases in ExpandablePaymentHandlerTest.java.
* Changed payment method from "/pay" to the "payment_method.json".
This is because /pay was not pointing to a payment method manifest, so
JIT installation was disabled.
* merchant.html: given ids to the buttons so that the tests can
simulate users' clicking on the buttons.

Bug: 1042892, 1084705, 1084707, 1084708, 1084711, 1084721, 1068741

Change-Id: I4943932632cc446c75144bcdf7f9d9f9e06881be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2227512Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#775203}
parent 85d78e60
......@@ -327,6 +327,7 @@ chrome_test_java_sources = [
"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/ExpandablePaymentHandlerChangePaymentMethodTest.java",
"javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerCoordinatorTest.java",
"javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java",
"javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java",
"javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
......
// Copyright 2020 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.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.browser.ChromeActivity;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator;
import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.url.GURL;
/**
* An integration test for {@link PaymentHandlerCoordinator}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class ExpandablePaymentHandlerCoordinatorTest {
@Rule
public ChromeActivityTestRule<ChromeActivity> mRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
private boolean mUiShown = false;
@Before
public void setUp() {
mRule.startMainActivityOnBlankPage();
}
@Test
@SmallTest
@Feature({"Payments"})
public void testShow() throws Throwable {
PaymentHandlerCoordinator paymentHandler = new PaymentHandlerCoordinator();
PaymentHandlerUiObserver uiObserver = new PaymentHandlerUiObserver() {
@Override
public void onPaymentHandlerUiClosed() {}
@Override
public void onPaymentHandlerUiShown() {
mUiShown = true;
}
};
mRule.runOnUiThread(
()
-> paymentHandler.show(mRule.getActivity(),
new GURL("https://maxpay.com/pay"), /*isIncognito=*/false,
/*webContentsObserver=*/(webContents) -> {}, uiObserver));
CriteriaHelper.pollInstrumentationThread(new Criteria() {
@Override
public boolean isSatisfied() {
return mUiShown;
}
});
mRule.runOnUiThread(() -> paymentHandler.hide());
}
}
\ No newline at end of file
package org.chromium.chrome.browser.payments;
// Copyright 2020 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.
import android.support.test.filters.MediumTest;
package org.chromium.chrome.browser.payments;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.startsWith;
import android.os.RemoteException;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
......@@ -13,59 +30,187 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator;
import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.components.payments.PaymentFeatureList;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.url.GURL;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import java.util.concurrent.TimeoutException;
/**
* A test for the Expandable PaymentHandler {@link PaymentHandlerCoordinator}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
"enable-features=" + PaymentFeatureList.SCROLL_TO_EXPAND_PAYMENT_HANDLER})
public class ExpandablePaymentHandlerTest {
private static final long MAX_WAIT_UNTIL_EXISTS = 3000L;
// Open a tab on the blank page first to initiate the native bindings required by the test
// server.
@Rule
public ChromeActivityTestRule<ChromeActivity> mRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
public PaymentRequestTestRule mRule = new PaymentRequestTestRule("about:blank");
// Host the tests on https://127.0.0.1, because file:// URLs cannot have service workers.
private EmbeddedTestServer mServer;
private boolean mUiShown = false;
private UiDevice mDevice;
@Before
public void setUp() {
mRule.startMainActivityOnBlankPage();
public void setUp() throws Throwable {
mServer = EmbeddedTestServer.createAndStartHTTPSServer(
InstrumentationRegistry.getContext(), ServerCertificate.CERT_OK);
mRule.startMainActivityWithURL(
mServer.getURL("/components/test/data/payments/maxpay.com/merchant.html"));
// Find the web contents where JavaScript will be executed and instrument the browser
// payment sheet.
mRule.openPage();
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
}
private UiObject showPaymentHandlerUi() throws TimeoutException {
mRule.clickNode("launch");
UiObject bottomSheet = mDevice.findObject(
new UiSelector().description("Payment handler sheet. Swipe down to close."));
Assert.assertTrue(bottomSheet.waitForExists(MAX_WAIT_UNTIL_EXISTS));
return bottomSheet;
}
private UiObject waitForTitleExists() {
UiObject title = mDevice.findObject(new UiSelector().text("Max Pay"));
Assert.assertTrue(title.waitForExists(MAX_WAIT_UNTIL_EXISTS));
return title;
}
private void clickCloseButton() {
onView(withId(org.chromium.chrome.R.id.close)).perform(click());
}
@Test
@MediumTest
@SmallTest
@Feature({"Payments"})
public void testShow() throws Throwable {
PaymentHandlerCoordinator paymentHandler = new PaymentHandlerCoordinator();
PaymentHandlerUiObserver uiObserver = new PaymentHandlerUiObserver() {
@Override
public void onPaymentHandlerUiClosed() {}
@Override
public void onPaymentHandlerUiShown() {
mUiShown = true;
public void testCloseButtonCloseUi() throws TimeoutException {
UiObject bottomSheet = showPaymentHandlerUi();
Assert.assertTrue(bottomSheet.exists());
clickCloseButton();
Assert.assertFalse(bottomSheet.exists());
}
};
mRule.runOnUiThread(
()
-> paymentHandler.show(mRule.getActivity(),
new GURL("https://maxpay.com/pay"), /*isIncognito=*/false,
/*webContentsObserver=*/(webContents) -> {}, uiObserver));
CriteriaHelper.pollInstrumentationThread(new Criteria() {
@Override
public boolean isSatisfied() {
return mUiShown;
@Test
@SmallTest
@Feature({"Payments"})
public void testSwipeDownCloseUi() throws TimeoutException, UiObjectNotFoundException {
UiObject bottomSheet = showPaymentHandlerUi();
UiObject title = waitForTitleExists();
Assert.assertTrue(bottomSheet.exists());
title.swipeDown(/*steps=*/10);
Assert.assertFalse(bottomSheet.exists());
}
});
mRule.runOnUiThread(() -> paymentHandler.hide());
@Test
@SmallTest
@Feature({"Payments"})
public void testPressSystemBackAtFirstPageNotCloseUi() throws TimeoutException {
UiObject bottomSheet = showPaymentHandlerUi();
waitForTitleExists();
Assert.assertTrue(bottomSheet.exists());
Assert.assertFalse(mDevice.pressBack());
mDevice.waitForIdle();
Assert.assertTrue(bottomSheet.exists());
clickCloseButton();
}
@Test
@SmallTest
@Feature({"Payments"})
public void testOrientationChange() throws TimeoutException, RemoteException {
UiObject bottomSheet = showPaymentHandlerUi();
waitForTitleExists();
Assert.assertTrue(bottomSheet.exists());
mDevice.setOrientationLeft();
mDevice.waitForIdle();
Assert.assertTrue(bottomSheet.exists());
mDevice.setOrientationRight();
mDevice.waitForIdle();
Assert.assertTrue(bottomSheet.exists());
mDevice.setOrientationNatural();
mDevice.waitForIdle();
Assert.assertTrue(bottomSheet.exists());
clickCloseButton();
}
@Test
@SmallTest
@Feature({"Payments"})
public void testWebContentsExist() throws TimeoutException {
showPaymentHandlerUi();
CriteriaHelper.pollUiThread(
() -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() != null);
clickCloseButton();
CriteriaHelper.pollUiThread(
() -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() == null);
}
@Test
@SmallTest
@Feature({"Payments"})
public void testUiElementsExist() throws TimeoutException {
showPaymentHandlerUi();
waitForTitleExists();
CriteriaHelper.pollUiThread(
() -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() != null);
onView(withId(org.chromium.chrome.R.id.title))
.check(matches(isDisplayed()))
.check(matches(withText("Max Pay")));
onView(withId(org.chromium.chrome.R.id.bottom_sheet))
.check(matches(isDisplayed()))
.check(matches(
withContentDescription("Payment handler sheet. Swipe down to close.")));
onView(withId(org.chromium.chrome.R.id.close))
.check(matches(isDisplayed()))
.check(matches(withContentDescription("Close")));
onView(withId(org.chromium.chrome.R.id.security_icon))
.check(matches(isDisplayed()))
.check(matches(withContentDescription("Connection is secure. Site information")));
// Not verifying the port number because it's indefinite in tests.
onView(withId(org.chromium.chrome.R.id.origin))
.check(matches(isDisplayed()))
.check(matches(withText(startsWith("127.0.0.1:"))));
clickCloseButton();
}
@Test
@SmallTest
@Feature({"Payments"})
public void testPageInfoButtonClickable() throws TimeoutException {
UiObject bottomSheet = showPaymentHandlerUi();
waitForTitleExists();
onView(withId(org.chromium.chrome.R.id.security_icon)).perform(click());
mDevice.waitForIdle();
String paymentAppUrl = mServer.getURL(
"/components/test/data/payments/maxpay.com/payment_handler_window.html");
onView(withId(org.chromium.chrome.R.id.page_info_url))
.check(matches(isDisplayed()))
.check(matches(withText(paymentAppUrl)));
Assert.assertFalse(bottomSheet.exists());
mDevice.pressBack();
Assert.assertTrue(bottomSheet.waitForExists(MAX_WAIT_UNTIL_EXISTS));
clickCloseButton();
}
}
{
"name": "Max Pay",
"icons": [{
"src": "../icon.png",
"sizes": "40x40",
"type": "image/png"
}],
"serviceworker": {
"src": "payment_handler_sw.js"
}
}
......@@ -4,7 +4,8 @@
* found in the LICENSE file.
*/
const methodName = window.location.origin + '/pay';
const methodName = window.location.origin +
'/components/test/data/payments/maxpay.com/payment_method.json';
const swSrcUrl = './payment_handler_sw.js';
let resultPromise;
......
......@@ -47,9 +47,9 @@ found in the LICENSE file.
</script>
<h1>Use Max Pay</h1>
<div id="controllers">
<button onclick="onInstallClicked()">Install</button>
<button onclick="onUninstallClicked()">Uninstall</button>
<button onclick="onLaunchClicked()">Launch</button>
<button id="install" onclick="onInstallClicked()">Install</button>
<button id="uninstall" onclick="onUninstallClicked()">Uninstall</button>
<button id="launch" onclick="onLaunchClicked()">Launch</button>
<button onclick="onLaunchClicked('http://info.cern.ch')">Launch http app</button>
</div>
<div>
......
......@@ -4,9 +4,13 @@ Copyright 2020 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.
-->
<meta
<head>
<meta charset="utf-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<title>Max Pay</title>
</head>
<body>
<button onclick="confirm()">confirm</button>
<button onclick="cancel()">cancel</button>
......
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