/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.tests; import java.util.ArrayList; import org.mozilla.gecko.Actions; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TabWidget; import android.widget.TextView; import com.jayway.android.robotium.solo.Condition; /** * This class is an extension of BaseTest that helps with interaction with about:home * This class contains methods that access the different tabs from about:home, methods that get information like history and bookmarks from the database, edit and remove bookmarks and history items * The purpose of this class is to collect all the logically connected methods that deal with about:home * To use any of these methods in your test make sure it extends AboutHomeTest instead of BaseTest */ abstract class AboutHomeTest extends PixelTest { protected enum AboutHomeTabs {HISTORY, MOST_RECENT, TABS_FROM_LAST_TIME, TOP_SITES, BOOKMARKS, READING_LIST}; private ArrayList aboutHomeTabs = new ArrayList() {{ add("TOP_SITES"); add("BOOKMARKS"); add("READING_LIST"); }}; @Override public void setUp() throws Exception { super.setUp(); if (aboutHomeTabs.size() < 4) { // Update it for tablets vs. phones. if (mDevice.type.equals("phone")) { aboutHomeTabs.add(0, AboutHomeTabs.HISTORY.toString()); } else { aboutHomeTabs.add(AboutHomeTabs.HISTORY.toString()); } } } /** * FIXME: Write new versions of these methods and update their consumers to use the new about:home pages. */ protected ListView getHistoryList(String waitText, int expectedChildCount) { return null; } protected ListView getHistoryList(String waitText) { return null; } // Returns true if the bookmark is displayed in the bookmarks tab, false otherwise - does not check in folders protected void isBookmarkDisplayed(final String url) { boolean isCorrect = waitForTest(new BooleanTest() { @Override public boolean test() { View bookmark = getDisplayedBookmark(url); return bookmark != null; } }, MAX_WAIT_MS); mAsserter.ok(isCorrect, "Checking that " + url + " displayed as a bookmark", url + " displayed"); } // Loads a bookmark by tapping on the bookmark view in the Bookmarks tab protected void loadBookmark(String url) { View bookmark = getDisplayedBookmark(url); if (bookmark != null) { Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded"); mSolo.clickOnView(bookmark); contentEventExpecter.blockForEvent(); contentEventExpecter.unregisterListener(); } else { mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked"); } } // Opens the bookmark context menu by long-tapping on it protected void openBookmarkContextMenu(String url) { View bookmark = getDisplayedBookmark(url); if (bookmark != null) { mSolo.waitForView(bookmark); mSolo.clickLongOnView(bookmark, LONG_PRESS_TIME); mSolo.waitForDialogToOpen(); } else { mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked"); } } // @return the View associated with bookmark for the provided url or null if the link is not bookmarked protected View getDisplayedBookmark(String url) { openAboutHomeTab(AboutHomeTabs.BOOKMARKS); mSolo.hideSoftKeyboard(); getInstrumentation().waitForIdleSync(); ListView bookmarksTabList = findListViewWithTag("bookmarks"); waitForNonEmptyListToLoad(bookmarksTabList); ListAdapter adapter = bookmarksTabList.getAdapter(); if (adapter != null) { for (int i = 0; i < adapter.getCount(); i++ ) { // I am unable to click the view taken with getView for some reason so getting the child at i bookmarksTabList.smoothScrollToPosition(i); View bookmarkView = bookmarksTabList.getChildAt(i); if (bookmarkView instanceof android.widget.LinearLayout) { ViewGroup bookmarkItemView = (ViewGroup) bookmarkView; for (int j = 0 ; j < bookmarkItemView.getChildCount(); j++) { View bookmarkContent = bookmarkItemView.getChildAt(j); if (bookmarkContent instanceof android.widget.LinearLayout) { ViewGroup bookmarkItemLayout = (ViewGroup) bookmarkContent; for (int k = 0 ; k < bookmarkItemLayout.getChildCount(); k++) { // Both the title and url are represented as text views so we can cast the view without any issues TextView bookmarkTextContent = (TextView)bookmarkItemLayout.getChildAt(k); if (url.equals(bookmarkTextContent.getText().toString())) { return bookmarkView; } } } } } } } return null; } /** * Waits for the given ListView to have a non-empty adapter and be populated * with a minimum number of items. * * This method will return false if the given ListView or its adapter is null, * or if the ListView does not have the minimum number of items. */ protected boolean waitForListToLoad(final ListView listView, final int minSize) { Condition listWaitCondition = new Condition() { @Override public boolean isSatisfied() { if (listView == null) { return false; } final ListAdapter adapter = listView.getAdapter(); if (adapter == null) { return false; } return (listView.getCount() - listView.getHeaderViewsCount() >= minSize); } }; return waitForCondition(listWaitCondition, MAX_WAIT_MS); } protected boolean waitForNonEmptyListToLoad(final ListView listView) { return waitForListToLoad(listView, 1); } /** * Get an active ListView with the specified tag . * * This method uses the predefined tags in HomePager. */ protected final ListView findListViewWithTag(String tag) { for (ListView listView : mSolo.getCurrentViews(ListView.class)) { final String listTag = (String) listView.getTag(); if (TextUtils.isEmpty(listTag)) { continue; } if (TextUtils.equals(listTag, tag)) { return listView; } } return null; } // A wait in order for the about:home tab to be rendered after drag/tab selection private void waitForAboutHomeTab(final int tabIndex) { boolean correctTab = waitForCondition(new Condition() { @Override public boolean isSatisfied() { ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0); return (pager.getCurrentItem() == tabIndex); } }, MAX_WAIT_MS); mAsserter.ok(correctTab, "Checking that the correct tab is displayed", "The " + aboutHomeTabs.get(tabIndex) + " tab is displayed"); } private void clickAboutHomeTab(AboutHomeTabs tab) { mSolo.clickOnText(tab.toString().replace("_", " ")); } /** * Swipes to an about:home tab. * @param int swipeVector Value and direction to swipe (go left for negative, right for positive). */ private void swipeAboutHome(int swipeVector) { // Increase swipe width, which will especially impact tablets. int swipeWidth = mDriver.getGeckoWidth() - 1; int swipeHeight = mDriver.getGeckoHeight() / 2; if (swipeVector >= 0) { // Emulate swipe motion from right to left. for (int i = 0; i < swipeVector; i++) { mActions.drag(swipeWidth, 0, swipeHeight, swipeHeight); mSolo.sleep(100); } } else { // Emulate swipe motion from left to right. for (int i = 0; i > swipeVector; i--) { mActions.drag(0, swipeWidth, swipeHeight, swipeHeight); mSolo.sleep(100); } } } /** * This method can be used to open the different tabs of about:home. * * @param AboutHomeTabs enum item {MOST_RECENT, TABS_FROM_LAST_TIME, TOP_SITES, BOOKMARKS, READING_LIST} */ protected void openAboutHomeTab(AboutHomeTabs tab) { focusUrlBar(); ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0); final int currentTabIndex = pager.getCurrentItem(); int tabOffset; // Handle tablets by just clicking the visible tab title. if (mDevice.type.equals("tablet")) { if (AboutHomeTabs.MOST_RECENT == tab || AboutHomeTabs.TABS_FROM_LAST_TIME == tab) { tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); switch (tab) { case MOST_RECENT: { mSolo.clickOnView(tabwidget.getChildAt(0)); // We can determine if we are on the MOST_RECENT tab only if pages were first visited during the test mAsserter.ok(waitForText(StringHelper.TODAY_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab"); break; } case TABS_FROM_LAST_TIME: { mSolo.clickOnView(tabwidget.getChildAt(1)); mAsserter.ok(waitForText(StringHelper.TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab"); break; } } } else { clickAboutHomeTab(tab); } return; } // Handle phones (non-tablets). tabOffset = aboutHomeTabs.indexOf(tab.toString()) - currentTabIndex; switch (tab) { case TOP_SITES : { swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); break; } case BOOKMARKS : { swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); break; } case MOST_RECENT: { // MOST_RECENT is contained in the HISTORY tab. tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); mSolo.clickOnView(tabwidget.getChildAt(0)); // We can determine if we are on the MOST_RECENT tab only if pages were first visited during the test mAsserter.ok(waitForText(StringHelper.TODAY_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab"); break; } case TABS_FROM_LAST_TIME: { // TABS_FROM_LAST_TIME is contained in the HISTORY tab. tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); mSolo.clickOnView(tabwidget.getChildAt(1)); mAsserter.ok(waitForText(StringHelper.TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab"); break; } case READING_LIST: { swipeAboutHome(tabOffset); waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); break; } } } }