diff --git a/app/src/androidTest/assets/pages/generic4.html b/app/src/androidTest/assets/pages/generic4.html
index c7e64740c1c1..368cfb927089 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 000000000000..3efe5025d950
--- /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 32f380e7b731..bef92460e83a 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 9ec4d8786af9..c662908bb116 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 33c2a0cfbbef..11b40a2bea4e 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 47f4792532a8..8dc237d4a276 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 d95a80d7584b..97c7d4b8abfd 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 6b8c766c24ee..e26b41af4fbc 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 a9731051fdda..93f5b0275c07 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 f6090adac80a..365bb794841a 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 a6a862ed1b47..cfae227a8a10 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 6d78d8b13be8..072e34176bf0 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 6f06573567fb..6731ec117951 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()