Commit 841efbea authored by bsheedy's avatar bsheedy Committed by Commit Bot

Automate VR omnibox text entry/navigation tests

Automates all the manual tests from https://crbug.com/887523, which all
relate to omnibox text entry and navigation while in the VR browser.

Bug: 887523
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:linux_vr;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I0db4cc10def31779b8a59f63e2a1f227cf0a6e29
Reviewed-on: https://chromium-review.googlesource.com/c/1263433Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#597168}
parent 75fb442a
...@@ -390,4 +390,26 @@ public class VrBrowserControllerInputTest { ...@@ -390,4 +390,26 @@ public class VrBrowserControllerInputTest {
> navigationTimestamp; > navigationTimestamp;
}); });
} }
/**
* Tests that pressing the app button on the Daydream controller exits omnibox text input mode.
*/
@Test
@MediumTest
public void testAppButtonExitsOmniboxTextInput() throws InterruptedException {
// We should always have the keyboard installed and up to date during automated testing, so
// this isn't strictly required. However, it may prevent weird issues when running locally
// if you don't have the keyboard installed for some reason.
NativeUiUtils.enableMockedKeyboard();
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// This acts as an assert that we're actually in omnibox text input mode. If the omnibox
// is not actually visible, we'll hit a DCHECK in the native code.
NativeUiUtils.clickElementAndWaitForUiQuiescence(
UserFriendlyElementName.OMNIBOX_TEXT_FIELD, new PointF());
NativeUiUtils.revertToRealInput();
// Wait for the URL bar to re-appear, which we take as a signal that we've exited omnibox
// text input mode.
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.URL, () -> { mController.pressReleaseAppButton(); });
}
} }
...@@ -9,6 +9,7 @@ import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S ...@@ -9,6 +9,7 @@ import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S
import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS; import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS;
import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE; import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE;
import android.graphics.PointF;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
...@@ -25,9 +26,11 @@ import org.chromium.chrome.browser.ChromeSwitches; ...@@ -25,9 +26,11 @@ import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.payments.ui.PaymentRequestUI; import org.chromium.chrome.browser.payments.ui.PaymentRequestUI;
import org.chromium.chrome.browser.payments.ui.PaymentRequestUI.PaymentRequestObserverForTest; import org.chromium.chrome.browser.payments.ui.PaymentRequestUI.PaymentRequestObserverForTest;
import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule; import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule;
import org.chromium.chrome.browser.vr.util.NativeUiUtils;
import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils; import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils;
import org.chromium.chrome.browser.vr.util.VrShellDelegateUtils; import org.chromium.chrome.browser.vr.util.VrShellDelegateUtils;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.EmbeddedTestServer;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
...@@ -123,4 +126,164 @@ public class VrBrowserNativeUiTest { ...@@ -123,4 +126,164 @@ public class VrBrowserNativeUiTest {
mVrBrowserTestFramework.endTest(); mVrBrowserTestFramework.endTest();
server.stopAndDestroyServer(); server.stopAndDestroyServer();
} }
/**
* Tests that the current URL is automatically populated when opening up the omnibox text
* entry mode.
*/
@Test
@MediumTest
public void testOmniboxContainsCurrentUrl() throws InterruptedException {
// This is a really roundabout way of checking the automatically populated text in the
// omnibox without having to add yet more native plumbing to read the current text.
// The idea is that by deleting the last four characters, we should be left with just
// "chrome://", so we can then input another chrome:// URL based off that. The only way
// the second navigation will complete successfully is if the omnibox had "chrome://gpu/"
// when we opened it.
NativeUiUtils.enableMockedKeyboard();
mVrTestRule.loadUrl("chrome://gpu/");
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// Click near the righthand side of the text input field so the cursor is at the end instead
// of selecting the existing text.
NativeUiUtils.clickElementAndWaitForUiQuiescence(
UserFriendlyElementName.OMNIBOX_TEXT_FIELD, new PointF(0.4f, 0.0f));
// Delete "gpu/".
for (int i = 0; i < 4; ++i) {
NativeUiUtils.inputBackspace();
}
// Wait for suggestions to change so that our navigation succeeds.
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("version/"); });
NativeUiUtils.inputEnter();
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://version/");
}
/**
* Tests that the the omnibox automatically scrolls the text when it is longer than the box
* can fit.
*/
@Test
@MediumTest
public void testOmniboxTextScrolls() throws InterruptedException {
// This is a roundabout way of checking that the text scrolls. By inputting a long string,
// clicking near the beginning and deleting a character, we can check that the text scrolled
// by checking whether a character at the beginning of the string was deleted or not - if
// the text scrolled, then a character later in the string should have been deleted.
NativeUiUtils.enableMockedKeyboard();
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
String expectedString = "chrome://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
NativeUiUtils.inputString(expectedString + "a");
// Click near the lefthand side of the input field to place the cursor near the beginning
// of the visible part of the string.
NativeUiUtils.clickElementAndWaitForUiQuiescence(
UserFriendlyElementName.OMNIBOX_TEXT_FIELD, new PointF(-0.45f, 0.0f));
// We expect this to delete an "a" instead of anything in "chrome://". Do so and wait for
// the suggestions to appear.
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX, () -> { NativeUiUtils.inputBackspace(); });
NativeUiUtils.inputEnter();
// Navigating automatically appends a "/".
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), expectedString + "/");
}
/**
* Tests that the omnibox automatically clears any text that gets input but not committed.
*/
@Test
@MediumTest
public void testOmniboxClearsUncommittedText() throws InterruptedException {
// Similar to testOmniboxContainsCurrentUrl, we check that the uncommitted text is not
// present the second time we open the omnibox by deleting a number of characters from
// the expected text and entering additional text.
NativeUiUtils.enableMockedKeyboard();
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// Input text and close the omnibox without committing.
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://version/"); });
NativeUiUtils.clickElementAndWaitForUiQuiescence(
UserFriendlyElementName.OMNIBOX_CLOSE_BUTTON, new PointF());
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// Click near the righthand side of the text input field so the cursor is at the end instead
// of selecting the existing text.
NativeUiUtils.clickElementAndWaitForUiQuiescence(
UserFriendlyElementName.OMNIBOX_TEXT_FIELD, new PointF(0.4f, 0.0f));
// Delete "about:blank".
for (int i = 0; i < 11; ++i) {
NativeUiUtils.inputBackspace();
}
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://version/"); });
NativeUiUtils.inputEnter();
// This should only succeed if the original "chrome://version/" we input is not present -
// if it is, we'll end up navigating to "chromechrome://version/".
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://version/");
}
/**
* Tests that omnibox autocompletion is functional.
*/
@Test
@MediumTest
public void testOmniboxAutocompletion() throws InterruptedException {
// At least with chrome:// URLs, autocompletion only kicks in when there's one valid option
// left. So, test that:
// 1. Autocompletion works if only one option is available.
// 2. Autocompletion updates successfully if additional characters are added.
// 3. Autocompletion doesn't work if multiple options are available.
// 4. Autocompletion cancels if a non-matching character is input.
NativeUiUtils.enableMockedKeyboard();
// Test that autocompletion works with only one option left.
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// This should autocomplete to "chrome://version".
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://v"); });
NativeUiUtils.inputEnter();
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://version/");
// Navigate away from chrome://version/ so waitForTabPageLoaded doesn't no-op the next time.
mVrTestRule.loadUrl("about:blank");
// Test that autocompletion updates successfully when entering more text.
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://v"); });
NativeUiUtils.inputString("e");
// Since suggestions are already visible, we need to wait for suggestions to update via
// a glorified sleep instead of waiting for suggestions to appear.
NativeUiUtils.waitNumFrames(NativeUiUtils.NUM_FRAMES_FOR_SUGGESTION_UPDATE);
NativeUiUtils.inputEnter();
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://version/");
// Test that autocompletion doesn't work with more than one option available.
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// This could be either "chrome://net-export" or "chrome://net-internals", so it shouldn't
// autocomplete to anything.
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://net-"); });
NativeUiUtils.inputEnter();
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://net-/");
// Test that autocompletion cancels if a non-matching character is input.
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// This should autocomplete to "chrome://version".
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://v"); });
NativeUiUtils.inputString("a");
NativeUiUtils.waitNumFrames(NativeUiUtils.NUM_FRAMES_FOR_SUGGESTION_UPDATE);
NativeUiUtils.inputEnter();
ChromeTabUtils.waitForTabPageLoaded(
mVrTestRule.getActivity().getActivityTab(), "chrome://va/");
}
} }
...@@ -664,6 +664,25 @@ public class VrBrowserNavigationTest { ...@@ -664,6 +664,25 @@ public class VrBrowserNavigationTest {
@Test @Test
@MediumTest @MediumTest
public void testUrlEntryTriggersNavigation() throws InterruptedException { public void testUrlEntryTriggersNavigation() throws InterruptedException {
testUrlEntryTriggersNavigationImpl();
}
/**
* Tests that inputting a URL into the URL bar in Incognito Mode results in a successful
* navigation.
*/
@Test
@MediumTest
public void testUrlEntryTriggersNavigationIncognito() throws InterruptedException {
ThreadUtils.runOnUiThreadBlocking(() -> {
mTestRule.getActivity()
.getTabCreator(true /* incognito */)
.launchUrl("about:blank", TabLaunchType.FROM_LINK);
});
testUrlEntryTriggersNavigationImpl();
}
private void testUrlEntryTriggersNavigationImpl() throws InterruptedException {
NativeUiUtils.enableMockedKeyboard(); NativeUiUtils.enableMockedKeyboard();
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF()); NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
// This is a roundabout solution for ensuring that the committing/pressing of enter actually // This is a roundabout solution for ensuring that the committing/pressing of enter actually
...@@ -680,4 +699,47 @@ public class VrBrowserNavigationTest { ...@@ -680,4 +699,47 @@ public class VrBrowserNavigationTest {
ChromeTabUtils.waitForTabPageLoaded( ChromeTabUtils.waitForTabPageLoaded(
mTestRule.getActivity().getActivityTab(), "chrome://version/"); mTestRule.getActivity().getActivityTab(), "chrome://version/");
} }
/**
* Tests that clicking on a suggestion results in a successful navigation.
*/
@Test
@MediumTest
public void testSuggestionClickTriggersNavigation() throws InterruptedException {
testSuggestionClickTriggersNavigationImpl();
}
/**
* Tests that clicking on a suggestion while in Incognito Mode results in a successful
* navigation.
*/
@Test
@MediumTest
public void testSuggestionClickTriggersNavigationIncognito() throws InterruptedException {
ThreadUtils.runOnUiThreadBlocking(() -> {
mTestRule.getActivity()
.getTabCreator(true /* incognito */)
.launchUrl("about:blank", TabLaunchType.FROM_LINK);
});
testSuggestionClickTriggersNavigationImpl();
}
private void testSuggestionClickTriggersNavigationImpl() throws InterruptedException {
NativeUiUtils.enableMockedKeyboard();
NativeUiUtils.clickElementAndWaitForUiQuiescence(UserFriendlyElementName.URL, new PointF());
NativeUiUtils.performActionAndWaitForVisibilityChange(
UserFriendlyElementName.SUGGESTION_BOX,
() -> { NativeUiUtils.inputString("chrome://"); });
// Blindly clicking in the center of the suggestion box should end up clicking the middle
// suggestion, which for "chrome://" should be a valid chrome:// URL.
NativeUiUtils.clickElement(UserFriendlyElementName.SUGGESTION_BOX, new PointF());
ChromeTabUtils.waitForTabPageLoaded(
mTestRule.getActivity().getActivityTab(), (String) null);
// We can't just wait for navigation to finish and then check because waitForTabPageLoaded
// only supports either exact URL matching or no URL matching, and no URL matching results
// in the URL still being about:blank when we check.
CriteriaHelper.pollInstrumentationThread(() -> {
return mTestRule.getActivity().getActivityTab().getUrl().startsWith("chrome://");
});
}
} }
...@@ -33,9 +33,14 @@ import java.util.concurrent.CountDownLatch; ...@@ -33,9 +33,14 @@ import java.util.concurrent.CountDownLatch;
* omnibox or back button. * omnibox or back button.
*/ */
public class NativeUiUtils { public class NativeUiUtils {
// How many frames to wait after entering text in the omnibox before we can assume that
// suggestions are updated. This should only be used if the workaround of inputting text and
// waiting for the suggestion box to appear doesn't work, e.g. if you need to input text, wait
// for autocomplete, then input more text before committing. 20 is arbitrary, but stable.
public static final int NUM_FRAMES_FOR_SUGGESTION_UPDATE = 20;
// Arbitrary but reasonable amount of time to expect the UI to stop updating after interacting // Arbitrary but reasonable amount of time to expect the UI to stop updating after interacting
// with an element. // with an element.
private static final int DEFAULT_UI_QUIESCENCE_TIMEOUT_MS = 1000; private static final int DEFAULT_UI_QUIESCENCE_TIMEOUT_MS = 2000;
/** /**
* Enables the use of both the mock head pose (locked forward) and Chrome-side mocked controller * Enables the use of both the mock head pose (locked forward) and Chrome-side mocked controller
......
...@@ -73,6 +73,10 @@ UiElementName UserFriendlyElementNameToUiElementName( ...@@ -73,6 +73,10 @@ UiElementName UserFriendlyElementNameToUiElementName(
return kExitPrompt; return kExitPrompt;
case UserFriendlyElementName::kSuggestionBox: case UserFriendlyElementName::kSuggestionBox:
return kOmniboxSuggestions; return kOmniboxSuggestions;
case UserFriendlyElementName::kOmniboxTextField:
return kOmniboxTextField;
case UserFriendlyElementName::kOmniboxCloseButton:
return kOmniboxCloseButton;
default: default:
NOTREACHED(); NOTREACHED();
return kNone; return kNone;
......
...@@ -27,6 +27,9 @@ enum class UserFriendlyElementName : int { ...@@ -27,6 +27,9 @@ enum class UserFriendlyElementName : int {
// menu // menu
kExitPrompt, // DOFF prompt/request to exit VR kExitPrompt, // DOFF prompt/request to exit VR
kSuggestionBox, // Box containing the omnibox suggestions kSuggestionBox, // Box containing the omnibox suggestions
kOmniboxTextField, // The Omnibox's text input field that shows up when the
// URL bar is clicked.
kOmniboxCloseButton, // The button the exits the omnibox's text input mode.
}; };
// These are the types of actions that Java can request callbacks for once // These are the types of actions that Java can request callbacks for once
......
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