Issue #21172: Refactor UI tests accessing awesomebar suggestions.

This commit is contained in:
Sebastian Kaspari 2021-09-08 16:53:34 +02:00 committed by mergify[bot]
parent 6d99c34f12
commit cd61ef1c1d
7 changed files with 139 additions and 144 deletions

View File

@ -201,6 +201,8 @@ android {
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
exclude 'META-INF/AL2.0'
exclude 'META-INF/LGPL2.1'
}
testOptions {
@ -535,11 +537,11 @@ dependencies {
implementation Deps.google_play_store // Required for in-app reviews
androidTestImplementation Deps.uiautomator
// Removed pending AndroidX fixes
androidTestImplementation "tools.fastlane:screengrab:2.0.0"
// This Falcon version is added to maven central now required for Screengrab
implementation 'com.jraska:falcon:2.2.0'
// androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1"
androidTestImplementation Deps.androidx_compose_ui_test
androidTestImplementation Deps.espresso_core, {
exclude group: 'com.android.support', module: 'support-annotations'

View File

@ -1,36 +0,0 @@
package org.mozilla.fenix.helpers.assertions
import android.view.View
import androidx.test.espresso.ViewAssertion
import mozilla.components.browser.awesomebar.BrowserAwesomeBar
class AwesomeBarAssertion {
companion object {
fun suggestionsAreGreaterThan(minimumSuggestions: Int): ViewAssertion {
return ViewAssertion { view, noViewFoundException ->
if (noViewFoundException != null) throw noViewFoundException
val suggestionsCount = getSuggestionCountFromView(view)
if (suggestionsCount <= minimumSuggestions)
throw AssertionError("The suggestion count is less than or equal to the minimum suggestions")
}
}
fun suggestionsAreEqualTo(expectedItemCount: Int): ViewAssertion {
return ViewAssertion { view, noViewFoundException ->
if (noViewFoundException != null) throw noViewFoundException
val suggestionsCount = getSuggestionCountFromView(view)
if (suggestionsCount != expectedItemCount)
throw AssertionError("The expected item count is $expectedItemCount, and the suggestions count within the AwesomeBar is $suggestionsCount")
}
}
private fun getSuggestionCountFromView(view: View): Int {
return (view as BrowserAwesomeBar).adapter?.itemCount
?: throw AssertionError("This view is not of type BrowserAwesomeBar")
}
}
}

View File

@ -4,6 +4,7 @@
package org.mozilla.fenix.ui
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@ -23,7 +24,10 @@ import org.mozilla.fenix.ui.robots.homeScreen
class SearchTest {
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
@get:Rule
val activityTestRule = HomeActivityTestRule()
val activityTestRule = AndroidComposeTestRule(
HomeActivityTestRule(),
{ it.activity }
)
@Test
fun searchScreenItemsTest() {
@ -59,10 +63,10 @@ class SearchTest {
}.goBack {
}.openSearch {
// verifySearchWithText()
clickSearchEngineButton("DuckDuckGo")
clickSearchEngineButton(activityTestRule, "DuckDuckGo")
typeSearch("mozilla")
verifySearchEngineResults("DuckDuckGo")
clickSearchEngineResult("DuckDuckGo")
verifySearchEngineResults(activityTestRule, "DuckDuckGo", 4)
clickSearchEngineResult(activityTestRule, "DuckDuckGo")
verifySearchEngineURL("DuckDuckGo")
}
}
@ -77,8 +81,8 @@ class SearchTest {
}.goBack {
}.goBack {
}.openSearch {
scrollToSearchEngineSettings()
clickSearchEngineSettings()
scrollToSearchEngineSettings(activityTestRule)
clickSearchEngineSettings(activityTestRule)
verifySearchSettings()
}
}

View File

@ -5,8 +5,10 @@
package org.mozilla.fenix.ui
import android.view.View
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.onNodeWithText
import androidx.core.net.toUri
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.IdlingRegistry
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
@ -65,7 +67,6 @@ class SmokeTest {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private lateinit var mockWebServer: MockWebServer
private var awesomeBar: ViewVisibilityIdlingResource? = null
private var searchSuggestionsIdlingResource: RecyclerViewIdlingResource? = null
private var addonsListIdlingResource: RecyclerViewIdlingResource? = null
private var recentlyClosedTabsListIdlingResource: RecyclerViewIdlingResource? = null
private var readerViewNotification: ViewVisibilityIdlingResource? = null
@ -84,10 +85,14 @@ class SmokeTest {
return searchDialogFragment?.view?.findViewById(R.id.awesome_bar)
}
@get:Rule
val activityTestRule = HomeActivityIntentTestRule()
private lateinit var browserStore: BrowserStore
@get:Rule
val activityTestRule = AndroidComposeTestRule(
HomeActivityIntentTestRule(),
{ it.activity }
)
@get: Rule
val intentReceiverActivityTestRule = ActivityTestRule(
IntentReceiverActivity::class.java, true, false
@ -119,10 +124,6 @@ class SmokeTest {
IdlingRegistry.getInstance().unregister(awesomeBar!!)
}
if (searchSuggestionsIdlingResource != null) {
IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!)
}
if (addonsListIdlingResource != null) {
IdlingRegistry.getInstance().unregister(addonsListIdlingResource!!)
}
@ -477,38 +478,43 @@ class SmokeTest {
}.openSearch {
verifyKeyboardVisibility()
clickSearchEngineShortcutButton()
verifySearchEngineList()
changeDefaultSearchEngine("Amazon.com")
verifySearchEngineList(activityTestRule)
changeDefaultSearchEngine(activityTestRule, "Amazon.com")
verifySearchEngineIcon("Amazon.com")
}.goToSearchEngine {
mDevice.waitForIdle()
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openTabDrawer {
}.openNewTab {
clickSearchEngineShortcutButton()
mDevice.waitForIdle()
changeDefaultSearchEngine("Bing")
changeDefaultSearchEngine(activityTestRule, "Bing")
verifySearchEngineIcon("Bing")
}.goToSearchEngine {
mDevice.waitForIdle()
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openTabDrawer {
}.openNewTab {
clickSearchEngineShortcutButton()
mDevice.waitForIdle()
changeDefaultSearchEngine("DuckDuckGo")
changeDefaultSearchEngine(activityTestRule, "DuckDuckGo")
verifySearchEngineIcon("DuckDuckGo")
}.goToSearchEngine {
mDevice.waitForIdle()
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openTabDrawer {
}.openNewTab {
clickSearchEngineShortcutButton()
changeDefaultSearchEngine("Wikipedia")
changeDefaultSearchEngine(activityTestRule, "Wikipedia")
verifySearchEngineIcon("Wikipedia")
}.goToSearchEngine {
mDevice.waitForIdle()
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openTabDrawer {
// Checking whether the next search will be with default or not
}.openNewTab {
}.goToSearchEngine {
mDevice.waitForIdle()
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openNavigationToolbar {
}.clickUrlbar {
@ -532,7 +538,9 @@ class SmokeTest {
}.openSearch {
verifyKeyboardVisibility()
clickSearchEngineShortcutButton()
verifyEnginesListShortcutContains("YouTube")
mDevice.waitForIdle()
activityTestRule.waitForIdle()
verifyEnginesListShortcutContains(activityTestRule, "YouTube")
}
}
@ -550,11 +558,13 @@ class SmokeTest {
awesomeBar = ViewVisibilityIdlingResource(it, View.VISIBLE)
}
IdlingRegistry.getInstance().register(awesomeBar!!)
searchSuggestionsIdlingResource =
RecyclerViewIdlingResource(awesomeBarView as RecyclerView, 1)
IdlingRegistry.getInstance().register(searchSuggestionsIdlingResource!!)
verifySearchSuggestionsAreMoreThan(0)
IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!)
activityTestRule.waitForIdle()
activityTestRule
.onNodeWithText("mozilla firefox")
.assertExists()
.assertIsDisplayed()
}.goBack {
}.openThreeDotMenu {
}.openSettings {
@ -564,11 +574,12 @@ class SmokeTest {
}.goBack {
}.openNavigationToolbar {
typeSearchTerm("mozilla")
searchSuggestionsIdlingResource =
RecyclerViewIdlingResource(getAwesomebarView() as RecyclerView)
IdlingRegistry.getInstance().register(searchSuggestionsIdlingResource!!)
verifySearchSuggestionsAreEqualTo(0)
IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!)
activityTestRule.waitForIdle()
activityTestRule
.onNodeWithText("mozilla firefox")
.assertDoesNotExist()
}
}
@ -675,7 +686,7 @@ class SmokeTest {
IdlingRegistry.getInstance().register(addonsListIdlingResource!!)
clickInstallAddon(addonName)
acceptInstallAddon()
verifyDownloadAddonPrompt(addonName, activityTestRule)
verifyDownloadAddonPrompt(addonName, activityTestRule.activityRule)
IdlingRegistry.getInstance().unregister(addonsListIdlingResource!!)
}.goBack {
}.openNavigationToolbar {
@ -1407,7 +1418,7 @@ class SmokeTest {
clickAlwaysStartOnHomeToggle()
}
restartApp(activityTestRule)
restartApp(activityTestRule.activityRule)
homeScreen {
verifyHomeScreen()

View File

@ -39,8 +39,6 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.SessionLoadedIdlingResource
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.TestHelper.packageName
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreEqualTo
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreGreaterThan
import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull
@ -49,12 +47,6 @@ import org.mozilla.fenix.helpers.ext.waitNotNull
*/
class NavigationToolbarRobot {
fun verifySearchSuggestionsAreMoreThan(suggestionSize: Int) =
assertSuggestionsAreMoreThan(suggestionSize)
fun verifySearchSuggestionsAreEqualTo(suggestionSize: Int) =
assertSuggestionsAreEqualTo(suggestionSize)
fun verifyNoHistoryBookmarks() = assertNoHistoryBookmarks()
fun verifyTabButtonShortcutMenuItems() = assertTabButtonShortcutMenuItems()
@ -280,16 +272,6 @@ fun openEditURLView() {
)
}
private fun assertSuggestionsAreEqualTo(suggestionSize: Int) {
mDevice.waitForIdle()
onView(withId(R.id.awesome_bar)).check(suggestionsAreEqualTo(suggestionSize))
}
private fun assertSuggestionsAreMoreThan(suggestionSize: Int) {
mDevice.waitForIdle()
onView(withId(R.id.awesome_bar)).check(suggestionsAreGreaterThan(suggestionSize))
}
private fun assertNoHistoryBookmarks() {
onView(withId(R.id.container))
.check(matches(not(hasDescendant(withText("Test_Page_1")))))

View File

@ -6,19 +6,25 @@
package org.mozilla.fenix.ui.robots
import androidx.recyclerview.widget.RecyclerView
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
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollToIndex
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId
@ -52,24 +58,24 @@ class SearchRobot {
fun verifyScanButton() = assertScanButton()
fun verifySearchEngineButton() = assertSearchEngineButton()
fun verifySearchWithText() = assertSearchWithText()
fun verifySearchEngineResults(searchEngineName: String) =
assertSearchEngineResults(searchEngineName)
fun verifySearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) =
assertSearchEngineResults(rule, searchEngineName, count)
fun verifySearchEngineURL(searchEngineName: String) = assertSearchEngineURL(searchEngineName)
fun verifySearchSettings() = assertSearchSettings()
fun verifySearchBarEmpty() = assertSearchBarEmpty()
fun verifyKeyboardVisibility() = assertKeyboardVisibility(isExpectedToBeVisible = true)
fun verifySearchEngineList() = assertSearchEngineList()
fun verifySearchEngineList(rule: ComposeTestRule) = rule.assertSearchEngineList()
fun verifySearchEngineIcon(expectedText: String) {
onView(withContentDescription(expectedText))
}
fun verifyDefaultSearchEngine(expectedText: String) = assertDefaultSearchEngine(expectedText)
fun verifyEnginesListShortcutContains(searchEngineName: String) = assertEngineListShortcutContains(searchEngineName)
fun verifyEnginesListShortcutContains(rule: ComposeTestRule, searchEngineName: String) = rule.assertEngineListShortcutContains(searchEngineName)
fun changeDefaultSearchEngine(searchEngineName: String) =
selectDefaultSearchEngine(searchEngineName)
fun changeDefaultSearchEngine(rule: ComposeTestRule, searchEngineName: String) =
rule.selectDefaultSearchEngine(searchEngineName)
fun clickSearchEngineShortcutButton() {
val searchEnginesShortcutButton = mDevice.findObject(
@ -96,33 +102,45 @@ class SearchRobot {
browserToolbarEditView().perform(typeText(searchTerm))
}
fun clickSearchEngineButton(searchEngineName: String) {
searchEngineButton(searchEngineName).perform(click())
fun clickSearchEngineButton(rule: ComposeTestRule, searchEngineName: String) {
rule.onNodeWithText(searchEngineName)
.assertExists()
.assertHasClickAction()
.performClick()
}
fun clickSearchEngineResult(searchEngineName: String) {
fun clickSearchEngineResult(rule: ComposeTestRule, searchEngineName: String) {
mDevice.waitNotNull(
Until.findObjects(By.text(searchEngineName)),
TestAssetHelper.waitingTime
)
awesomeBar().perform(
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
0,
click()
)
)
rule.onAllNodesWithText(searchEngineName)
.onFirst()
.assertIsDisplayed()
.assertHasClickAction()
.performClick()
}
fun scrollToSearchEngineSettings() {
@OptIn(ExperimentalTestApi::class)
fun scrollToSearchEngineSettings(rule: ComposeTestRule) {
// Soft keyboard is visible on screen on view access; hide it
onView(allOf(withId(R.id.search_wrapper))).perform(
closeSoftKeyboard()
)
onView(allOf(withId(R.id.awesome_bar))).perform(ViewActions.swipeUp())
mDevice.findObject(UiSelector().text("Google"))
.waitForExists(waitingTime)
rule.onNodeWithTag("mozac.awesomebar.suggestions")
.performScrollToIndex(5)
}
fun clickSearchEngineSettings() {
onView(withText("Search engine settings")).perform(click())
fun clickSearchEngineSettings(rule: ComposeTestRule) {
rule.onNodeWithText("Search engine settings")
.assertIsDisplayed()
.assertHasClickAction()
.performClick()
}
fun clickClearButton() {
@ -187,16 +205,9 @@ class SearchRobot {
}
}
private fun awesomeBar() = onView(withId(R.id.awesome_bar))
private fun browserToolbarEditView() =
onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view)))
private fun searchEngineButton(searchEngineName: String): ViewInteraction {
mDevice.waitNotNull(Until.findObject(By.text(searchEngineName)), TestAssetHelper.waitingTime)
return onView(Matchers.allOf(withText(searchEngineName)))
}
private fun denyPermissionButton(): UiObject {
mDevice.waitNotNull(Until.findObjects(By.text("Deny")), TestAssetHelper.waitingTime)
return mDevice.findObject(UiSelector().text("Deny"))
@ -209,7 +220,7 @@ private fun allowPermissionButton(): UiObject {
private fun scanButton(): ViewInteraction {
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/search_scan_button")), TestAssetHelper.waitingTime)
return onView(allOf(withId(R.id.search_scan_button)))
return onView(allOf(withId(R.id.qr_scan_button)))
}
private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
@ -225,10 +236,9 @@ private fun assertSearchEngineURL(searchEngineName: String) {
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
}
private fun assertSearchEngineResults(searchEngineName: String) {
val count =
mDevice.wait(Until.findObjects(By.text((searchEngineName))), TestAssetHelper.waitingTime)
assert(count.size > 1)
private fun assertSearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) {
rule.onAllNodesWithText(searchEngineName)
.assertCountEquals(count)
}
private fun assertSearchView() {
@ -277,34 +287,54 @@ private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean) = {
)
}
private fun assertSearchEngineList() {
private fun ComposeTestRule.assertSearchEngineList() {
onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click()
onView(withText("Google"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(withText("Amazon.com"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(withText("Bing"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(withText("DuckDuckGo"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(withText("Wikipedia"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onNodeWithText("Google")
.assertExists()
.assertIsDisplayed()
onNodeWithText("Amazon.com")
.assertExists()
.assertIsDisplayed()
onNodeWithText("Bing")
.assertExists()
.assertIsDisplayed()
onNodeWithText("DuckDuckGo")
.assertExists()
.assertIsDisplayed()
onNodeWithText("Wikipedia")
.assertExists()
.assertIsDisplayed()
}
private fun assertEngineListShortcutContains(searchEngineName: String) {
@OptIn(ExperimentalTestApi::class)
private fun ComposeTestRule.assertEngineListShortcutContains(searchEngineName: String) {
mDevice.findObject(UiSelector().resourceId("$packageName:id/awesome_bar"))
.waitForExists(waitingTime)
onView(withId(R.id.awesome_bar))
.perform(swipeDown())
.check(matches(hasDescendant(withText(searchEngineName))))
mDevice.findObject(UiSelector().text("Google"))
.waitForExists(waitingTime)
onNodeWithTag("mozac.awesomebar.suggestions")
.performScrollToIndex(5)
onNodeWithText(searchEngineName)
.assertExists()
.assertIsDisplayed()
.assertHasClickAction()
}
private fun selectDefaultSearchEngine(searchEngine: String) {
private fun ComposeTestRule.selectDefaultSearchEngine(searchEngine: String) {
onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click()
onView(withText(searchEngine))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.perform(click())
onNodeWithText(searchEngine)
.assertExists()
.assertIsDisplayed()
.performClick()
}
private fun assertDefaultSearchEngine(expectedText: String) {

View File

@ -14,6 +14,7 @@ import mozilla.components.compose.browser.awesomebar.AwesomeBar
import mozilla.components.compose.browser.awesomebar.AwesomeBarDefaults
import mozilla.components.compose.browser.awesomebar.AwesomeBarOrientation
import mozilla.components.concept.awesomebar.AwesomeBar
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.theme.FirefoxTheme
@ -63,7 +64,8 @@ class AwesomeBarWrapper @JvmOverloads constructor(
},
onAutoComplete = { suggestion ->
onEditSuggestionListener?.invoke(suggestion.editSuggestion!!)
}
},
onScroll = { hideKeyboard() }
)
}
}