blob: 2f8fc04006c38b641f3f8c683d0988c7b416ba0b [file] [log] [blame]
// Copyright 2015 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.keyboard_accessory;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItem;
import static android.support.test.espresso.contrib.RecyclerViewActions.scrollTo;
import static android.support.test.espresso.matcher.ViewMatchers.withChild;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertTrue;
import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.waitToBeHidden;
import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
import android.app.Activity;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
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.RetryOnFailure;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeWindow;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.DOMUtils;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Integration tests for autofill keyboard accessory.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@RetryOnFailure
@EnableFeatures({ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY,
ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY})
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class AutofillKeyboardAccessoryIntegrationTest {
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
private ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mActivityTestRule);
/**
* This FakeKeyboard triggers as a regular keyboard but has no measurable height. This simulates
* being the upper half in multi-window mode.
*/
private static class MultiWindowKeyboard extends FakeKeyboard {
public MultiWindowKeyboard(WeakReference<Activity> activity) {
super(activity);
}
@Override
protected int getStaticKeyboardHeight() {
return 0;
}
}
private void loadTestPage(ChromeWindow.KeyboardVisibilityDelegateFactory keyboardDelegate)
throws InterruptedException, ExecutionException, TimeoutException {
mHelper.loadTestPage("/chrome/test/data/autofill/autofill_test_form.html", false, false,
keyboardDelegate);
ManualFillingTestHelper.createAutofillTestProfiles();
DOMUtils.waitForNonZeroNodeBounds(mHelper.getWebContents(), "NAME_FIRST");
}
/**
* Autofocused fields should not show a keyboard accessory.
*/
@Test
@MediumTest
public void testAutofocusedFieldDoesNotShowKeyboardAccessory()
throws ExecutionException, InterruptedException, TimeoutException {
loadTestPage(FakeKeyboard::new);
CriteriaHelper.pollUiThread(() -> {
View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
return accessory == null || !accessory.isShown();
});
}
/**
* Tapping on an input field should show a keyboard and its keyboard accessory.
*/
@Test
@MediumTest
public void testTapInputFieldShowsKeyboardAccessory()
throws ExecutionException, InterruptedException, TimeoutException {
loadTestPage(FakeKeyboard::new);
mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
mHelper.waitForKeyboardAccessoryToBeShown();
}
/**
* Switching fields should re-scroll the keyboard accessory to the left.
*/
@Test
@MediumTest
public void testSwitchFieldsRescrollsKeyboardAccessory()
throws ExecutionException, InterruptedException, TimeoutException {
loadTestPage(FakeKeyboard::new);
mHelper.clickNodeAndShowKeyboard("EMAIL_ADDRESS");
mHelper.waitForKeyboardAccessoryToBeShown();
// Scroll to the second position and check it actually happened.
TestThreadUtils.runOnUiThreadBlocking(() -> getSuggestionsComponent().scrollToPosition(2));
CriteriaHelper.pollUiThread(() -> {
return getSuggestionsComponent().computeHorizontalScrollOffset() > 0;
}, "Should keep the manual scroll position.");
// Clicking any other node should now scroll the items back to the initial position.
mHelper.clickNodeAndShowKeyboard("NAME_LAST");
CriteriaHelper.pollUiThread(() -> {
return getSuggestionsComponent().computeHorizontalScrollOffset() == 0;
}, "Should be scrolled back to position 0.");
}
/**
* Selecting a keyboard accessory suggestion should hide the keyboard and its keyboard
* accessory.
*/
@Test
@MediumTest
public void testSelectSuggestionHidesKeyboardAccessory()
throws ExecutionException, InterruptedException, TimeoutException {
loadTestPage(FakeKeyboard::new);
mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
mHelper.waitForKeyboardAccessoryToBeShown();
CriteriaHelper.pollUiThread(() -> getFirstSuggestion() != null);
TestThreadUtils.runOnUiThreadBlocking(() -> getFirstSuggestion().performClick());
mHelper.waitForKeyboardAccessoryToDisappear();
}
@Test
@MediumTest
public void testSuggestionsCloseAccessoryWhenClicked()
throws ExecutionException, InterruptedException, TimeoutException {
MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true);
loadTestPage(MultiWindowKeyboard::new);
mHelper.clickNode("NAME_FIRST");
mHelper.waitForKeyboardAccessoryToBeShown();
CriteriaHelper.pollUiThread(() -> getFirstSuggestion() != null);
TestThreadUtils.runOnUiThreadBlocking(() -> getFirstSuggestion().performClick());
mHelper.waitForKeyboardAccessoryToDisappear();
}
@Test
@SmallTest
public void testPressingBackButtonHidesAccessoryWithAutofillSuggestions()
throws InterruptedException, TimeoutException, ExecutionException {
loadTestPage(MultiWindowKeyboard::new);
mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
mHelper.waitForKeyboardAccessoryToBeShown();
whenDisplayed(withId(R.id.bar_items_view))
.perform(scrollTo(isKeyboardAccessoryTabLayout()))
.perform(actionOnItem(isKeyboardAccessoryTabLayout(), selectTabAtPosition(0)));
whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
assertTrue(TestThreadUtils.runOnUiThreadBlocking(
() -> mHelper.getManualFillingCoordinator().handleBackPress()));
waitToBeHidden(withChild(withId(R.id.keyboard_accessory_sheet)));
}
@Test
@MediumTest
public void testSheetHasMinimumSizeWhenTriggeredBySuggestion()
throws ExecutionException, InterruptedException, TimeoutException {
MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true);
loadTestPage(MultiWindowKeyboard::new);
mHelper.clickNode("NAME_FIRST");
mHelper.waitForKeyboardAccessoryToBeShown();
whenDisplayed(withId(R.id.bar_items_view))
.perform(scrollTo(isKeyboardAccessoryTabLayout()),
actionOnItem(isKeyboardAccessoryTabLayout(), selectTabAtPosition(0)));
CriteriaHelper.pollUiThread(() -> {
View sheetView =
mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_sheet);
return sheetView.isShown() && sheetView.getHeight() > 0;
});
// Click the back arrow.
whenDisplayed(withId(R.id.show_keyboard)).perform(click());
waitToBeHidden(withChild(withId(R.id.keyboard_accessory_sheet)));
CriteriaHelper.pollUiThread(() -> {
View sheetView =
mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_sheet);
return sheetView.getHeight() == 0 || !sheetView.isShown();
});
}
private RecyclerView getSuggestionsComponent() {
final ViewGroup keyboardAccessory = TestThreadUtils.runOnUiThreadBlockingNoException(
() -> mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory));
assert keyboardAccessory != null;
return (RecyclerView) keyboardAccessory.findViewById(R.id.bar_items_view);
}
private View getFirstSuggestion() {
ViewGroup recyclerView = getSuggestionsComponent();
assert recyclerView != null;
return recyclerView.getChildAt(0);
}
}