From 6845eef5c3560964cc52c70787fb5b1388be428b Mon Sep 17 00:00:00 2001 From: Oana Horvath Date: Mon, 21 Feb 2022 12:32:02 +0200 Subject: [PATCH] For #21002: Ads new search group UI tests Fixed and re-enabled editCustomSearchEngineTest with custom MockWebServer URL --- .../androidTest/assets/pages/generic4.html | 1 + .../mozilla/fenix/helpers/SearchDispatcher.kt | 64 ++++++ .../mozilla/fenix/helpers/TestAssetHelper.kt | 2 +- .../org/mozilla/fenix/helpers/TestHelper.kt | 9 + .../java/org/mozilla/fenix/ui/HistoryTest.kt | 6 +- .../java/org/mozilla/fenix/ui/SearchTest.kt | 186 +++++++++++++++++- .../mozilla/fenix/ui/SettingsSearchTest.kt | 14 +- .../mozilla/fenix/ui/robots/BrowserRobot.kt | 2 +- .../mozilla/fenix/ui/robots/HistoryRobot.kt | 21 +- .../fenix/ui/robots/HomeScreenRobot.kt | 54 ++++- .../mozilla/fenix/ui/robots/SearchRobot.kt | 33 ++-- .../ui/robots/SettingsSubMenuSearchRobot.kt | 5 + .../mozilla/fenix/ui/robots/TabDrawerRobot.kt | 26 ++- 13 files changed, 382 insertions(+), 41 deletions(-) create mode 100644 app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt diff --git a/app/src/androidTest/assets/pages/generic4.html b/app/src/androidTest/assets/pages/generic4.html index c7e64740c..368cfb927 100644 --- a/app/src/androidTest/assets/pages/generic4.html +++ b/app/src/androidTest/assets/pages/generic4.html @@ -1,5 +1,6 @@ + Test_Page_4 diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt new file mode 100644 index 000000000..3efe5025d --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt @@ -0,0 +1,64 @@ +/* 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.fenix.helpers + +import android.os.Handler +import android.os.Looper +import androidx.test.platform.app.InstrumentationRegistry +import java.io.IOException +import java.io.InputStream +import okhttp3.mockwebserver.Dispatcher +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import okhttp3.mockwebserver.RecordedRequest +import okio.Buffer +import okio.source + +/** + * A [MockWebServer] [Dispatcher] that will return a generic search results page in the body of + * requests and responds with status 200. + * + * If the dispatcher is unable to read a requested asset, it will fail the test by throwing an + * Exception on the main thread. + * + * @sample [org.mozilla.fenix.ui.SearchTest] + */ +class SearchDispatcher : Dispatcher() { + private val mainThreadHandler = Handler(Looper.getMainLooper()) + + override fun dispatch(request: RecordedRequest): MockResponse { + val assetManager = InstrumentationRegistry.getInstrumentation().context.assets + try { + // When we perform a search with the custom search engine, returns the generic4.html test page as search results + if (request.path!!.contains("searchResults.html?search=")) { + MockResponse().setResponseCode(HTTP_OK) + val path = "pages/generic4.html" + assetManager.open(path).use { inputStream -> + return fileToResponse(inputStream) + } + } + return MockResponse().setResponseCode(HTTP_NOT_FOUND) + } catch (e: IOException) { + // e.g. file not found. + // We're on a background thread so we need to forward the exception to the main thread. + mainThreadHandler.postAtFrontOfQueue { throw e } + return MockResponse().setResponseCode(HTTP_NOT_FOUND) + } + } +} + +@Throws(IOException::class) +private fun fileToResponse(file: InputStream): MockResponse { + return MockResponse() + .setResponseCode(HTTP_OK) + .setBody(fileToBytes(file)) +} + +@Throws(IOException::class) +private fun fileToBytes(file: InputStream): Buffer { + val result = Buffer() + result.writeAll(file.source()) + return result +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt index 32f380e7b..bef92460e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt @@ -15,7 +15,7 @@ import org.mozilla.fenix.helpers.ext.toUri object TestAssetHelper { @Suppress("MagicNumber") val waitingTime: Long = TimeUnit.SECONDS.toMillis(15) - val waitingTimeShort: Long = TimeUnit.SECONDS.toMillis(1) + val waitingTimeShort: Long = TimeUnit.SECONDS.toMillis(3) data class TestAsset(val url: Uri, val content: String, val title: String) diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt index 9ec4d8786..c662908bb 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt @@ -40,12 +40,14 @@ import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import java.io.File import kotlinx.coroutines.runBlocking +import mozilla.components.browser.state.search.SearchEngine import mozilla.components.support.ktx.android.content.appName import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matcher import org.junit.Assert import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.ext.waitNotNull @@ -252,4 +254,11 @@ object TestHelper { } fun getStringResource(id: Int) = appContext.resources.getString(id, appName) + + fun setCustomSearchEngine(searchEngine: SearchEngine) { + with(appContext.components.useCases.searchUseCases) { + addSearchEngine(searchEngine) + selectSearchEngine(searchEngine) + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt index 33c2a0cfb..11b40a2be 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt @@ -121,7 +121,7 @@ class HistoryTest { historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list), 1) IdlingRegistry.getInstance().register(historyListIdlingResource!!) - clickDeleteHistoryButton() + clickDeleteHistoryButton(firstWebPage.url.toString()) IdlingRegistry.getInstance().unregister(historyListIdlingResource!!) verifyDeleteSnackbarText("Deleted") verifyEmptyHistoryView() @@ -247,8 +247,8 @@ class HistoryTest { historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list), 2) IdlingRegistry.getInstance().register(historyListIdlingResource!!) - verifyHistoryItemExists(firstWebPage.url.toString()) - verifyHistoryItemExists(secondWebPage.url.toString()) + verifyHistoryItemExists(true, firstWebPage.url.toString()) + verifyHistoryItemExists(true, secondWebPage.url.toString()) longTapSelectItem(firstWebPage.url) longTapSelectItem(secondWebPage.url) openActionBarOverflowOrOptionsMenu(activityTestRule.activity) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index 47f479253..8dc237d4a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -5,12 +5,27 @@ package org.mozilla.fenix.ui import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.core.net.toUri +import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu +import mozilla.components.browser.icons.IconRequest +import mozilla.components.browser.icons.generator.DefaultIconGenerator +import mozilla.components.feature.search.ext.createSearchEngine +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest +import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.SearchDispatcher +import org.mozilla.fenix.helpers.TestHelper.appContext +import org.mozilla.fenix.helpers.TestHelper.exitMenu +import org.mozilla.fenix.helpers.TestHelper.longTapSelectItem +import org.mozilla.fenix.helpers.TestHelper.setCustomSearchEngine import org.mozilla.fenix.ui.robots.homeScreen +import org.mozilla.fenix.ui.robots.multipleSelectionToolbar /** * Tests for verifying the search fragment @@ -23,13 +38,31 @@ import org.mozilla.fenix.ui.robots.homeScreen */ class SearchTest { - /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. + private val featureSettingsHelper = FeatureSettingsHelper() + lateinit var searchMockServer: MockWebServer + @get:Rule val activityTestRule = AndroidComposeTestRule( HomeActivityTestRule(), { it.activity } ) + @Before + fun setUp() { + searchMockServer = MockWebServer().apply { + dispatcher = SearchDispatcher() + start() + } + featureSettingsHelper.setJumpBackCFREnabled(false) + featureSettingsHelper.setPocketEnabled(false) + } + + @After + fun tearDown() { + searchMockServer.shutdown() + featureSettingsHelper.resetAllFeatureFlags() + } + @Test fun searchScreenItemsTest() { homeScreen { @@ -67,7 +100,7 @@ class SearchTest { verifySearchBarEmpty() clickSearchEngineButton(activityTestRule, "DuckDuckGo") typeSearch("mozilla") - verifySearchEngineResults(activityTestRule, "DuckDuckGo", 4) + verifySearchEngineResults(2) clickSearchEngineResult(activityTestRule, "DuckDuckGo") verifySearchEngineURL("DuckDuckGo") } @@ -98,4 +131,153 @@ class SearchTest { verifySearchBarEmpty() } } + + @Ignore("Failure caused by bugs: https://github.com/mozilla-mobile/fenix/issues/23818") + @SmokeTest + @Test + fun searchGroupShowsInRecentlyVisitedTest() { + val firstPage = searchMockServer.url("generic1.html").toString() + val secondPage = searchMockServer.url("generic2.html").toString() + // setting our custom mockWebServer search URL + val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery("test search") { + longClickMatchingText("Link 1") + clickContextOpenLinkInNewTab() + longClickMatchingText("Link 2") + clickContextOpenLinkInNewTab() + }.goToHomescreen { + verifyJumpBackInSectionIsDisplayed() + verifyCurrentSearchGroupIsDisplayed(true, "test search", 3) + verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 3) + }.openTabDrawer { + }.openTabFromGroup(firstPage) { + }.openTabDrawer { + }.openTabFromGroup(secondPage) { + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, "test search", 3) + } + } + + @SmokeTest + @Test + fun noCurrentSearchGroupFromPrivateBrowsingTest() { + // setting our custom mockWebServer search URL + val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery("test search") { + longClickMatchingText("Link 1") + clickContextOpenLinkInPrivateTab() + longClickMatchingText("Link 2") + clickContextOpenLinkInPrivateTab() + }.goToHomescreen { + verifyCurrentSearchGroupIsDisplayed(false, "test search", 3) + }.openThreeDotMenu { + }.openHistory { + verifyHistoryItemExists(false, "3 sites") + } + } + + @SmokeTest + @Test + fun noRecentlyVisitedSearchGroupInPrivateBrowsingTest() { + val firstPage = searchMockServer.url("generic1.html").toString() + val secondPage = searchMockServer.url("generic2.html").toString() + // setting our custom mockWebServer search URL + val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.togglePrivateBrowsingMode() + homeScreen { + }.openSearch { + }.submitQuery("test search") { + longClickMatchingText("Link 1") + clickContextOpenLinkInPrivateTab() + longClickMatchingText("Link 2") + clickContextOpenLinkInPrivateTab() + }.openTabDrawer { + }.openTab(firstPage) { + }.openTabDrawer { + }.openTab(secondPage) { + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + homeScreen { + }.togglePrivateBrowsingMode() + verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 3) + } + } + + @Ignore("Failure caused by bugs: https://github.com/mozilla-mobile/fenix/issues/23818") + @SmokeTest + @Test + fun deleteItemsFromSearchGroupsHistoryTest() { + val firstPage = searchMockServer.url("generic1.html").toString() + val secondPage = searchMockServer.url("generic2.html").toString() + // setting our custom mockWebServer search URL + val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery("test search") { + longClickMatchingText("Link 1") + clickContextOpenLinkInNewTab() + longClickMatchingText("Link 2") + clickContextOpenLinkInNewTab() + }.openTabDrawer { + }.openTabFromGroup(firstPage) { + }.openTabDrawer { + }.openTabFromGroup(secondPage) { + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, "test search", 3) + }.openRecentlyVisitedSearchGroupHistoryList("test search") { + clickDeleteHistoryButton(firstPage) + longTapSelectItem(secondPage.toUri()) + multipleSelectionToolbar { + openActionBarOverflowOrOptionsMenu(activityTestRule.activity) + clickMultiSelectionDelete() + } + exitMenu() + } + homeScreen { + // checking that the group is removed when only 1 item is left + verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 1) + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt index d95a80d75..97c7d4b8a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt @@ -4,13 +4,13 @@ import androidx.compose.ui.test.junit4.AndroidComposeTestRule import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.SearchDispatcher import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset import org.mozilla.fenix.helpers.TestHelper.exitMenu import org.mozilla.fenix.ui.robots.homeScreen @@ -18,6 +18,7 @@ import org.mozilla.fenix.ui.robots.navigationToolbar class SettingsSearchTest { private lateinit var mockWebServer: MockWebServer + private lateinit var searchMockServer: MockWebServer private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule @@ -147,12 +148,15 @@ class SettingsSearchTest { @SmokeTest @Test // Verifies setting as default a customized search engine name and URL - @Ignore("Failing intermittently https://github.com/mozilla-mobile/fenix/issues/22256") fun editCustomSearchEngineTest() { + searchMockServer = MockWebServer().apply { + dispatcher = SearchDispatcher() + start() + } val searchEngine = object { - var title = "Elefant" - var url = "https://www.elefant.ro/search?SearchTerm=%s" - var newTitle = "Test" + val title = "TestSearchEngine" + val url = "http://localhost:${searchMockServer.port}/searchResults.html?search=%s" + val newTitle = "Test" } homeScreen { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index 6b8c766c2..e26b41af4 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -690,7 +690,7 @@ class BrowserRobot { fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { mDevice.findObject( - UiSelector().descriptionContains("open tab. Tap to switch tabs.") + UiSelector().descriptionContains("Tap to switch tabs.") ).waitForExists(waitingTime) tabsCounter().click() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt index a9731051f..93f5b0275 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt @@ -9,6 +9,7 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId @@ -19,10 +20,10 @@ import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import org.hamcrest.Matchers import org.hamcrest.Matchers.allOf +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime -import org.mozilla.fenix.helpers.TestHelper.waitForObjects import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull @@ -53,7 +54,7 @@ class HistoryRobot { assertVisitedTimeTitle() } - fun verifyHistoryItemExists(url: String) = assertHistoryItemExists(url) + fun verifyHistoryItemExists(shouldExist: Boolean, item: String) = assertHistoryItemExists(shouldExist, item) fun verifyFirstTestPageTitle(title: String) = assertTestPageTitle(title) @@ -65,8 +66,8 @@ class HistoryRobot { fun verifyHomeScreen() = HomeScreenRobot().verifyHomeScreen() - fun clickDeleteHistoryButton() { - deleteButton().click() + fun clickDeleteHistoryButton(item: String) { + deleteButton(item).click() } fun clickDeleteAllHistoryButton() = deleteAllButton().click() @@ -99,7 +100,8 @@ private fun testPageTitle() = onView(allOf(withId(R.id.title), withText("Test_Pa private fun pageUrl() = onView(withId(R.id.url)) -private fun deleteButton() = onView(withId(R.id.overflow_menu)) +private fun deleteButton(title: String) = + onView(allOf(withId(R.id.overflow_menu), hasSibling(withText(title)))) private fun deleteAllButton() = onView(withId(R.id.history_delete_all)) @@ -124,9 +126,12 @@ private fun assertEmptyHistoryView() = private fun assertHistoryListExists() = mDevice.findObject(UiSelector().resourceId("R.id.history_list")).waitForExists(waitingTime) -private fun assertHistoryItemExists(url: String) { - mDevice.waitForObjects(mDevice.findObject(UiSelector().textContains(url))) - assertTrue(mDevice.findObject(UiSelector().textContains(url)).waitForExists(waitingTime)) +private fun assertHistoryItemExists(shouldExist: Boolean, item: String) { + if (shouldExist) { + assertTrue(mDevice.findObject(UiSelector().textContains(item)).waitForExists(waitingTime)) + } else { + assertFalse(mDevice.findObject(UiSelector().textContains(item)).waitForExists(waitingTime)) + } } private fun assertVisitedTimeTitle() = diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt index f6090adac..365bb7948 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt @@ -33,7 +33,6 @@ import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until.findObject -import junit.framework.TestCase.assertTrue import mozilla.components.browser.state.state.searchEngines import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString @@ -42,6 +41,7 @@ import org.hamcrest.CoreMatchers.not import org.hamcrest.Matchers import org.junit.Assert import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime @@ -142,6 +142,43 @@ class HomeScreenRobot { fun verifyRecentBookmarksSectionIsDisplayed() = assertRecentBookmarksSectionIsDisplayed() fun verifyRecentBookmarksSectionIsNotDisplayed() = assertRecentBookmarksSectionIsNotDisplayed() + fun verifyRecentlyVisitedSearchGroupDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int) { + // checks if the search group exists in the Recently visited section + if (shouldBeDisplayed) { + recentlyVisitedList.waitForExists(waitingTime) + scrollToElementByText("Recently visited") + recentlyVisitedList.getChildByText(UiSelector().text(searchTerm), searchTerm, true) + .waitForExists(waitingTimeShort) + assertTrue( + mDevice.findObject(UiSelector().text(searchTerm)) + .getFromParent(UiSelector().text("$groupSize sites")) + .waitForExists(waitingTimeShort) + ) + } else { + assertFalse( + mDevice.findObject(UiSelector().text(searchTerm)) + .getFromParent(UiSelector().text("$groupSize sites")) + .waitForExists(waitingTimeShort) + ) + } + } + + fun verifyCurrentSearchGroupIsDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int = 0) { + // checks search group in the Jump back in section + if (shouldBeDisplayed) { + assertTrue( + mDevice.findObject(UiSelector().text("""Your search for "$searchTerm"""")) + .getFromParent(UiSelector().textContains("$groupSize sites")) + .waitForExists(waitingTimeShort) + ) + } else { + assertFalse( + mDevice.findObject(UiSelector().text("""Your search for "$searchTerm"""")) + .waitForExists(waitingTimeShort) + ) + } + } + // Collections elements fun verifyCollectionIsDisplayed(title: String, collectionExists: Boolean = true) { if (collectionExists) { @@ -366,6 +403,15 @@ class HomeScreenRobot { CollectionRobot().interact() return CollectionRobot.Transition() } + + fun openRecentlyVisitedSearchGroupHistoryList(title: String, interact: HistoryRobot.() -> Unit): HistoryRobot.Transition { + val searchGroup = recentlyVisitedList.getChildByText(UiSelector().text(title), title, true) + searchGroup.waitForExists(waitingTimeShort) + searchGroup.click() + + HistoryRobot().interact() + return HistoryRobot.Transition() + } } } @@ -672,3 +718,9 @@ val deleteFromHistory = withText(R.string.delete_from_history) ) ).inRoot(RootMatchers.isPlatformPopup()) + +private val recentlyVisitedList = + UiScrollable( + UiSelector() + .className("android.widget.HorizontalScrollView") + ).setAsHorizontalList() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index a6a862ed1..cfae227a8 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.ui.robots import androidx.compose.ui.test.ExperimentalTestApi -import androidx.compose.ui.test.assertCountEquals import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.ComposeTestRule @@ -33,6 +32,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject +import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers.allOf @@ -43,7 +43,6 @@ import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.Constants.LONG_CLICK_DURATION import org.mozilla.fenix.helpers.SessionLoadedIdlingResource -import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.TestHelper.packageName @@ -77,8 +76,8 @@ class SearchRobot { fun verifySearchEngineButton() = assertSearchButton() fun verifySearchWithText() = assertSearchWithText() - fun verifySearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) = - assertSearchEngineResults(rule, searchEngineName, count) + fun verifySearchEngineResults(count: Int) = + assertSearchEngineResults(count) fun verifySearchEngineSuggestionResults(rule: ComposeTestRule, searchSuggestion: String) = assertSearchEngineSuggestionResults(rule, searchSuggestion) fun verifyNoSuggestionsAreDisplayed(rule: ComposeTestRule, searchSuggestion: String) = @@ -149,7 +148,7 @@ class SearchRobot { fun clickSearchEngineResult(rule: ComposeTestRule, searchEngineName: String) { mDevice.waitNotNull( Until.findObjects(By.text(searchEngineName)), - TestAssetHelper.waitingTime + waitingTime ) rule.onAllNodesWithText(searchEngineName) @@ -263,17 +262,17 @@ private fun browserToolbarEditView() = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view")) private fun denyPermissionButton(): UiObject { - mDevice.waitNotNull(Until.findObjects(By.text("Deny")), TestAssetHelper.waitingTime) + mDevice.waitNotNull(Until.findObjects(By.text("Deny")), waitingTime) return mDevice.findObject(UiSelector().text("Deny")) } private fun allowPermissionButton(): UiObject { - mDevice.waitNotNull(Until.findObjects(By.text("Allow")), TestAssetHelper.waitingTime) + mDevice.waitNotNull(Until.findObjects(By.text("Allow")), waitingTime) return mDevice.findObject(UiSelector().text("Allow")) } private fun scanButton(): ViewInteraction { - mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/search_scan_button")), TestAssetHelper.waitingTime) + mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/search_scan_button")), waitingTime) return onView(allOf(withId(R.id.qr_scan_button))) } @@ -285,23 +284,18 @@ private fun searchWrapper() = mDevice.findObject(UiSelector().resourceId("$packa private fun assertSearchEngineURL(searchEngineName: String) { mDevice.waitNotNull( Until.findObject(By.textContains("${searchEngineName.lowercase()}.com/?q=mozilla")), - TestAssetHelper.waitingTime + waitingTime ) onView(allOf(withText(startsWith("${searchEngineName.lowercase()}.com")))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun assertSearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) { - rule.waitForIdle() - +private fun assertSearchEngineResults(minCount: Int) { mDevice.waitForObjects( - mDevice.findObject( - UiSelector().textContains(searchEngineName) - ) + searchSuggestionsList.getChild(UiSelector().index(minCount)) ) - rule.onAllNodesWithText(searchEngineName) - .assertCountEquals(count) + assertTrue(searchSuggestionsList.childCount >= minCount) } private fun assertSearchEngineSuggestionResults(rule: ComposeTestRule, searchResult: String) { @@ -472,3 +466,8 @@ private val awesomeBar = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view")) private val voiceSearchButton = mDevice.findObject(UiSelector().description("Voice search")) + +private val searchSuggestionsList = + UiScrollable( + UiSelector().className("android.widget.ScrollView") + ) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt index 6d78d8b13..072e34176 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt @@ -185,6 +185,11 @@ class SettingsSubMenuSearchRobot { } } +fun searchSettingsScreen(interact: SettingsSubMenuSearchRobot.() -> Unit): SettingsSubMenuSearchRobot.Transition { + SettingsSubMenuSearchRobot().interact() + return SettingsSubMenuSearchRobot.Transition() +} + private fun assertSearchToolbar() = onView( allOf( diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 6f0657356..6731ec117 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -29,6 +29,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import androidx.test.uiautomator.By.text import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until.findObject @@ -43,6 +44,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.TestHelper.packageName +import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.clickAtLocationInView import org.mozilla.fenix.helpers.ext.waitNotNull @@ -341,12 +343,30 @@ class TabDrawerRobot { } fun openTab(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - mDevice.waitNotNull(findObject(text(title))) - mDevice.findObject( + val tab = mDevice.findObject( UiSelector() .resourceId("$packageName:id/mozac_browser_tabstray_title") .textContains(title) - ).click() + ) + scrollToElementByText(title) + tab.waitForExists(waitingTime) + tab.click() + + BrowserRobot().interact() + return BrowserRobot.Transition() + } + + fun openTabFromGroup(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + val tab = UiScrollable(UiSelector().resourceId("$packageName:id/tab_group_list")) + .setAsHorizontalList() + .getChildByText( + UiSelector() + .resourceId("$packageName:id/mozac_browser_tabstray_title") + .textContains(title), + title, + true + ) + tab.click() BrowserRobot().interact() return BrowserRobot.Transition()