1
0
Fork 0

Adding UI tests for the Basic Menu settings. 🎲 !!!! (#6346)

* Added UI tests for the basic settings menu

* Disabled toggleSearchSuggestions test
master
Kadeem M 2020-02-06 15:58:47 -05:00 committed by GitHub
parent 6019adafac
commit 095477e0ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 599 additions and 159 deletions

View File

@ -4,9 +4,11 @@
package org.mozilla.fenix.helpers package org.mozilla.fenix.helpers
import android.graphics.Bitmap
import android.view.View import android.view.View
import org.hamcrest.CoreMatchers.not import org.hamcrest.CoreMatchers.not
import org.hamcrest.Matcher import org.hamcrest.Matcher
import org.mozilla.fenix.helpers.matchers.BitmapDrawableMatcher
import androidx.test.espresso.matcher.ViewMatchers.isChecked as espressoIsChecked import androidx.test.espresso.matcher.ViewMatchers.isChecked as espressoIsChecked
import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled
import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected
@ -30,3 +32,5 @@ private fun maybeInvertMatcher(matcher: Matcher<View>, useUnmodifiedMatcher: Boo
useUnmodifiedMatcher -> matcher useUnmodifiedMatcher -> matcher
else -> not(matcher) else -> not(matcher)
} }
fun withBitmapDrawable(bitmap: Bitmap, name: String): Matcher<View>? = BitmapDrawableMatcher(bitmap, name)

View File

@ -0,0 +1,36 @@
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

@ -0,0 +1,35 @@
package org.mozilla.fenix.helpers.matchers
import android.graphics.Bitmap
import android.view.View
import android.widget.ImageView
import androidx.test.espresso.matcher.BoundedMatcher
import org.hamcrest.Description
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.StateListDrawable
import android.graphics.drawable.Drawable
class BitmapDrawableMatcher(private val bitmap: Bitmap, private val name: String) :
BoundedMatcher<View, ImageView>(ImageView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has image drawable resource $name")
}
override fun matchesSafely(item: ImageView): Boolean {
return sameBitmap(item.drawable, bitmap)
}
private fun sameBitmap(drawable: Drawable?, otherBitmap: Bitmap): Boolean {
var currentDrawable = drawable ?: return false
if (currentDrawable is StateListDrawable) {
currentDrawable = currentDrawable.current
}
if (currentDrawable is BitmapDrawable) {
val bitmap = currentDrawable.bitmap
return bitmap.sameAs(otherBitmap)
}
return false
}
}

View File

@ -52,11 +52,11 @@ class SearchTest {
homeScreen { homeScreen {
}.openSearch { }.openSearch {
verifySearchWithText() verifySearchWithText()
clickDuckDuckGoEngineButton() clickSearchEngineButton("DuckDuckGo")
typeSearch("mozilla") typeSearch("mozilla")
verifyDuckDuckGoResults() verifySearchEngineResults("DuckDuckGo")
clickDuckDuckGoResult() clickSearchEngineResult("DuckDuckGo")
verifyDuckDuckGoURL() verifySearchEngineURL("DuckDuckGo")
} }
} }

View File

@ -10,12 +10,17 @@ import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.MockWebServer
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.Ignore
import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset
import org.mozilla.fenix.helpers.TestAssetHelper.getLoremIpsumAsset
import org.mozilla.fenix.ui.robots.checkTextSizeOnWebsite
import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.navigationToolbar
/** /**
* Tests for verifying the main three dot menu options * Tests for verifying the main three dot menu options
@ -29,7 +34,7 @@ class SettingsBasicsTest {
private lateinit var mockWebServer: MockWebServer private lateinit var mockWebServer: MockWebServer
@get:Rule @get:Rule
val activityTestRule = HomeActivityTestRule() val activityIntentTestRule = HomeActivityIntentTestRule()
@Before @Before
fun setUp() { fun setUp() {
@ -45,7 +50,8 @@ class SettingsBasicsTest {
} }
private fun getUiTheme(): Boolean { private fun getUiTheme(): Boolean {
val mode = activityTestRule.activity.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) val mode =
activityIntentTestRule.activity.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK)
return when (mode) { return when (mode) {
Configuration.UI_MODE_NIGHT_YES -> true // dark theme is set Configuration.UI_MODE_NIGHT_YES -> true // dark theme is set
@ -68,6 +74,7 @@ class SettingsBasicsTest {
verifySearchEngineList() verifySearchEngineList()
verifyShowSearchSuggestions() verifyShowSearchSuggestions()
verifyShowSearchShortcuts() verifyShowSearchShortcuts()
verifyShowClipboardSuggestions() verifyShowClipboardSuggestions()
verifySearchBrowsingHistory() verifySearchBrowsingHistory()
verifySearchBookmarks() verifySearchBookmarks()
@ -76,7 +83,7 @@ class SettingsBasicsTest {
verifyThemes() verifyThemes()
}.goBack { }.goBack {
}.openAccessibilitySubMenu { }.openAccessibilitySubMenu {
verifyAutomaticFontSizing() verifyAutomaticFontSizingMenuItems()
}.goBack { }.goBack {
// drill down to submenu // drill down to submenu
}.openDefaultBrowserSubMenu { }.openDefaultBrowserSubMenu {
@ -86,49 +93,75 @@ class SettingsBasicsTest {
} }
} }
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun selectNewDefaultSearchEngine() { fun selectNewDefaultSearchEngine() {
// Open 3dot (main) menu // Goes through the settings and changes the default search engine, then verifies it has changed.
// Select settings homeScreen {
// Select "Search engine" }.openThreeDotMenu {
// Choose: DuckDuckGo }.openSettings {
// Back arrow to Home }.openSearchSubMenu {
// Verify DuckDuckGo icon in Navigation bar changeDefaultSearchEngine("DuckDuckGo")
}.goBack {
}.goBack {
verifyDefaultSearchEngine("DuckDuckGo")
}
} }
@Ignore("This is a stub test, ignore for now") @Ignore("This test works locally, fails on firebase. https://github.com/mozilla-mobile/fenix/issues/8174")
@Test @Test
fun toggleSearchSuggestions() { fun toggleSearchSuggestions() {
// Enter: "mozilla" in navigation bar // Goes through the settings and changes the search suggestion toggle, then verifies it changes.
// Verify more than one suggesion provided homeScreen {
// Open 3dot (main) menu }.openNavigationToolbar {
// Select settings verifySearchSuggestionsAreMoreThan(1, "mozilla")
// Select "Search engine" }.goBack {
// Toggle 'Show search suggestions' to 'off' }.openThreeDotMenu {
// Back arrow twice to home screen }.openSettings {
// Enter: "mozilla" in navigation bar }.openSearchSubMenu {
// Verify no suggestions provided disableShowSearchSuggestions()
}.goBack {
}.goBack {
}.openNavigationToolbar {
verifySearchSuggestionsAreEqualTo(0, "mozilla")
}
} }
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun toggleShowVisitedSitesAndBookmarks() { fun toggleShowVisitedSitesAndBookmarks() {
// Visit 3 static sites // Bookmarks a few websites, toggles the history and bookmarks setting to off, then verifies if the visited and bookmarked websites do not show in the suggestions.
// Bookmark 2 of them val page1 = getGenericAsset(mockWebServer, 1)
// Open 3dot (main) menu val page2 = getGenericAsset(mockWebServer, 2)
// Enter navigation bar and verify visited sites appear val page3 = getGenericAsset(mockWebServer, 3)
// Verify bookmarks exist
// Open 3dot (main) menu homeScreen {
// Select settings }.openNavigationToolbar {
// Select "Search engine" }.enterURLAndEnterToBrowser(page1.url) {
// Toggle off "Show visited sites and bookmarks" verifyPageContent(page1.content)
// Back arrow twice to home screen }.openThreeDotMenu {
// Verify history and bookmarks are gone clickAddBookmarkButton()
}
navigationToolbar {
}.enterURLAndEnterToBrowser(page2.url) {
verifyPageContent(page2.content)
}.openThreeDotMenu {
clickAddBookmarkButton()
}
navigationToolbar {
}.enterURLAndEnterToBrowser(page3.url) {
verifyPageContent(page3.content)
}
navigationToolbar {
verifyNoHistoryBookmarks()
}
} }
@Test @Test
fun changeThemeSetting() { fun changeThemeSetting() {
// Goes through the settings and changes the default search engine, then verifies it changes.
homeScreen { homeScreen {
}.openThreeDotMenu { }.openThreeDotMenu {
}.openSettings { }.openSettings {
@ -141,40 +174,48 @@ class SettingsBasicsTest {
} }
} }
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun changeAccessibiltySettings() { fun changeAccessibiltySettings() {
// Open 3dot (main) menu // Goes through the settings and changes the default text on a webpage, then verifies if the text has changed.
// Select settings val fenixApp = activityIntentTestRule.activity.applicationContext as FenixApplication
// Select Accessibility val webpage = getLoremIpsumAsset(mockWebServer).url
// Verify header: "Automatic Font Sizing"
// Verify description: "Font size will match your Android settings. Disable to manage font size here" // This value will represent the text size percentage the webpage will scale to. The default value is 100%.
// Verify toggle is set to 'on' by default val textSizePercentage = 180
// Toggle font size to off
// Verify that new sub-menu items appear.... homeScreen {
// Verify header: "Font Size" }.openThreeDotMenu {
// Verify description: "Make text on websites larger or smaller" }.openSettings {
// Verify slider bar exists }.openAccessibilitySubMenu {
// Verify slider bar default value set to 100% clickFontSizingSwitch()
// Verify sample text "The quick brown fox..." appears 4 times verifyNewMenuItems()
// Move slider bar to 180% changeTextSizeSlider(textSizePercentage)
// Verify that text grows to 180% verifyTextSizePercentage(textSizePercentage)
// Back error twice to home screen }.goBack {
// Open static website in navigation bar }.goBack {
// Verify that text is now at 180% }.openNavigationToolbar {
// Select settings }.enterURLAndEnterToBrowser(webpage) {
// Select Accessibility checkTextSizeOnWebsite(textSizePercentage, fenixApp.components)
// Toggle font size back to 'off' }.openHomeScreen {
// Verify that "Font Size" header, description, slider bar and sample text all disappear }.openThreeDotMenu {
}.openSettings {
}.openAccessibilitySubMenu {
clickFontSizingSwitch()
verifyNewMenuItemsAreGone()
}
} }
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun changeDefaultBrowserSetting() { fun changeDefaultBrowserSetting() {
// Open 3dot (main) menu // Opens settings and toggles the default browser setting to on. The device settings open and allows the user to set a default browser.
// Select settings homeScreen {
// Verify that "Set as default browser toggle is set to 'off' (default) }.openThreeDotMenu {
// Turn default browser toggle 'on' }.openSettings {
// Verify that Andrdoid "Default Apps" menu appears }.openDefaultBrowserSubMenu {
verifyDefaultBrowserIsDisabled()
clickDefaultBrowserSwitch()
verifyAndroidDefaultAppsMenuAppears()
}
} }
} }

View File

@ -7,6 +7,7 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.graphics.Bitmap
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
@ -14,12 +15,12 @@ import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
@ -34,6 +35,8 @@ import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.ext.waitNotNull
import org.mozilla.fenix.components.Search
import org.mozilla.fenix.helpers.withBitmapDrawable
/** /**
* Implementation of Robot Pattern for the home screen menu. * Implementation of Robot Pattern for the home screen menu.
@ -53,6 +56,7 @@ class HomeScreenRobot {
fun verifyHomeWordmark() = assertHomeWordmark() fun verifyHomeWordmark() = assertHomeWordmark()
fun verifyHomeToolbar() = assertHomeToolbar() fun verifyHomeToolbar() = assertHomeToolbar()
fun verifyHomeComponent() = assertHomeComponent() fun verifyHomeComponent() = assertHomeComponent()
fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine)
// First Run elements // First Run elements
fun verifyWelcomeHeader() = assertWelcomeHeader() fun verifyWelcomeHeader() = assertWelcomeHeader()
@ -81,6 +85,7 @@ class HomeScreenRobot {
// Private mode elements // Private mode elements
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader() fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible) fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton() fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton()
@ -114,7 +119,6 @@ class HomeScreenRobot {
fun typeCollectionName(name: String) { fun typeCollectionName(name: String) {
mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime) mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime)
collectionNameTextField().perform(ViewActions.replaceText(name)) collectionNameTextField().perform(ViewActions.replaceText(name))
collectionNameTextField().perform(ViewActions.pressImeActionButton()) collectionNameTextField().perform(ViewActions.pressImeActionButton())
} }
@ -206,6 +210,13 @@ class HomeScreenRobot {
HomeScreenRobot().interact() HomeScreenRobot().interact()
return Transition() return Transition()
} }
fun openNavigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {
assertNavigationToolbar().perform(click())
NavigationToolbarRobot().interact()
return NavigationToolbarRobot.Transition()
}
} }
} }
@ -215,6 +226,7 @@ fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition
} }
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
private fun navigationToolbar() = private fun navigationToolbar() =
onView(CoreMatchers.allOf(withText("Search or enter address"))) onView(CoreMatchers.allOf(withText("Search or enter address")))
@ -279,6 +291,19 @@ private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("sessio
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton))) private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
private fun verifySearchEngineIcon(searchEngineIcon: Bitmap, searchEngineName: String) {
onView(withId(R.id.search_engine_icon))
.check(matches(withBitmapDrawable(searchEngineIcon, searchEngineName)))
}
private fun getSearchEngine(searchEngineName: String) =
Search(appContext).searchEngineManager.getDefaultSearchEngine(appContext, searchEngineName)
private fun verifySearchEngineIcon(searchEngineName: String) {
val ddgSearchEngine = getSearchEngine(searchEngineName)
verifySearchEngineIcon(ddgSearchEngine.icon, ddgSearchEngine.name)
}
// First Run elements // First Run elements
private fun assertWelcomeHeader() = private fun assertWelcomeHeader() =
onView(CoreMatchers.allOf(withText("Welcome to Firefox Preview!"))) onView(CoreMatchers.allOf(withText("Welcome to Firefox Preview!")))
@ -418,7 +443,8 @@ private fun assertExistingOpenTabs(title: String) =
private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button))) private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button)))
private fun collectionThreeDotButton() = onView(allOf(withId(R.id.collection_overflow_button))) private fun collectionThreeDotButton() =
onView(allOf(withId(R.id.collection_overflow_button)))
private fun collectionNameTextField() = private fun collectionNameTextField() =
onView(allOf(ViewMatchers.withResourceName("name_collection_edittext"))) onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))

View File

@ -10,26 +10,49 @@ import android.net.Uri
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.pressImeActionButton import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.action.ViewActions.replaceText import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers.not
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.ext.waitNotNull
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreEqualTo
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreGreaterThan
/** /**
* Implementation of Robot Pattern for the URL toolbar. * Implementation of Robot Pattern for the URL toolbar.
*/ */
class NavigationToolbarRobot { class NavigationToolbarRobot {
fun verifySearchSuggestionsAreMoreThan(suggestionSize: Int, searchTerm: String) =
assertSuggestionsAreMoreThan(suggestionSize, searchTerm)
fun verifySearchSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) =
assertSuggestionsAreEqualTo(suggestionSize, searchTerm)
fun verifyNoHistoryBookmarks() = assertNoHistoryBookmarks()
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun enterURLAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { fun enterURLAndEnterToBrowser(
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), waitingTime) url: Uri,
interact: BrowserRobot.() -> Unit
): BrowserRobot.Transition {
mDevice.waitNotNull(
Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")),
waitingTime
)
urlBar().click() urlBar().click()
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton()) awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
@ -45,7 +68,10 @@ class NavigationToolbarRobot {
return ThreeDotMenuMainRobot.Transition() return ThreeDotMenuMainRobot.Transition()
} }
fun openNewTabAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { fun openNewTabAndEnterToBrowser(
url: Uri,
interact: BrowserRobot.() -> Unit
): BrowserRobot.Transition {
mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime) mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime)
newTab().click() newTab().click()
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton()) awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
@ -75,6 +101,13 @@ class NavigationToolbarRobot {
BrowserRobot().interact() BrowserRobot().interact()
return BrowserRobot.Transition() return BrowserRobot.Transition()
} }
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
goBackButton()
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
} }
} }
@ -83,10 +116,34 @@ fun navigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationTo
return NavigationToolbarRobot.Transition() return NavigationToolbarRobot.Transition()
} }
private fun dismissOnboardingButton() = onView(ViewMatchers.withId(R.id.close_onboarding)) private fun assertSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) {
private fun urlBar() = onView(ViewMatchers.withId(R.id.toolbar)) mDevice.waitForIdle()
private fun awesomeBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_edit_url_view)) awesomeBar().perform(typeText(searchTerm))
private fun threeDotButton() = onView(ViewMatchers.withContentDescription("Menu"))
private fun newTab() = onView(ViewMatchers.withContentDescription("Add tab")) mDevice.waitForIdle()
private fun fillLinkButton() = onView(ViewMatchers.withId(R.id.clipboard_url)) onView(withId(R.id.awesomeBar)).check(suggestionsAreEqualTo(suggestionSize))
private fun clearAddressBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_clear_view)) }
private fun assertSuggestionsAreMoreThan(suggestionSize: Int, searchTerm: String) {
mDevice.waitForIdle()
awesomeBar().perform(typeText(searchTerm))
mDevice.waitForIdle()
onView(withId(R.id.awesomeBar)).check(suggestionsAreGreaterThan(suggestionSize))
}
private fun assertNoHistoryBookmarks() {
onView(withId(R.id.container))
.check(matches(not(hasDescendant(withText("Test_Page_1")))))
.check(matches(not(hasDescendant(withText("Test_Page_2")))))
.check(matches(not(hasDescendant(withText("Test_Page_3")))))
}
private fun dismissOnboardingButton() = onView(withId(R.id.close_onboarding))
private fun urlBar() = onView(withId(R.id.toolbar))
private fun awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
private fun threeDotButton() = onView(withContentDescription("Menu"))
private fun newTab() = onView(withContentDescription("Add tab"))
private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard))
private fun clearAddressBar() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
private fun goBackButton() = mDevice.pressBack()

View File

@ -39,8 +39,10 @@ class SearchRobot {
fun verifyBrowserToolbar() = assertBrowserToolbarEditView() fun verifyBrowserToolbar() = assertBrowserToolbarEditView()
fun verifyScanButton() = assertScanButton() fun verifyScanButton() = assertScanButton()
fun verifySearchWithText() = assertSearchWithText() fun verifySearchWithText() = assertSearchWithText()
fun verifyDuckDuckGoResults() = assertDuckDuckGoResults() fun verifySearchEngineResults(searchEngineName: String) =
fun verifyDuckDuckGoURL() = assertDuckDuckGoURL() assertSearchEngineResults(searchEngineName)
fun verifySearchEngineURL(searchEngineName: String) = assertSearchEngineURL(searchEngineName)
fun verifySearchSettings() = assertSearchSettings() fun verifySearchSettings() = assertSearchSettings()
fun verifySearchBarEmpty() = assertSearchBarEmpty() fun verifySearchBarEmpty() = assertSearchBarEmpty()
@ -60,13 +62,21 @@ class SearchRobot {
browserToolbarEditView().perform(typeText(searchTerm)) browserToolbarEditView().perform(typeText(searchTerm))
} }
fun clickDuckDuckGoEngineButton() { fun clickSearchEngineButton(searchEngineName: String) {
duckDuckGoEngineButton().perform(click()) searchEngineButton(searchEngineName).perform(click())
} }
fun clickDuckDuckGoResult() { fun clickSearchEngineResult(searchEngineName: String) {
mDevice.waitNotNull(Until.findObjects(By.text("DuckDuckGo")), TestAssetHelper.waitingTime) mDevice.waitNotNull(
awesomeBar().perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) Until.findObjects(By.text(searchEngineName)),
TestAssetHelper.waitingTime
)
awesomeBar().perform(
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
0,
click()
)
)
} }
fun scrollToSearchEngineSettings(): UiScrollable { fun scrollToSearchEngineSettings(): UiScrollable {
@ -88,7 +98,7 @@ class SearchRobot {
fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle() mDevice.waitForIdle()
browserToolbarEditView().perform(typeText("Mozilla\n")) browserToolbarEditView().perform(typeText("mozilla\n"))
BrowserRobot().interact() BrowserRobot().interact()
return BrowserRobot.Transition() return BrowserRobot.Transition()
@ -98,11 +108,12 @@ class SearchRobot {
private fun awesomeBar() = onView(withId(R.id.awesomeBar)) private fun awesomeBar() = onView(withId(R.id.awesomeBar))
private fun browserToolbarEditView() = onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view))) private fun browserToolbarEditView() =
onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view)))
private fun duckDuckGoEngineButton(): ViewInteraction { private fun searchEngineButton(searchEngineName: String): ViewInteraction {
mDevice.waitNotNull(Until.findObject(By.text("DuckDuckGo")), TestAssetHelper.waitingTime) mDevice.waitNotNull(Until.findObject(By.text(searchEngineName)), TestAssetHelper.waitingTime)
return onView(Matchers.allOf(withText("DuckDuckGo"))) return onView(Matchers.allOf(withText(searchEngineName)))
} }
private fun denyPermissionButton(): UiObject { private fun denyPermissionButton(): UiObject {
@ -122,14 +133,18 @@ private fun scanButton(): ViewInteraction {
private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view)) private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
private fun assertDuckDuckGoURL() { private fun assertSearchEngineURL(searchEngineName: String) {
mDevice.waitNotNull(Until.findObject(By.textContains("https://duckduckgo.com/?q=mozilla")), TestAssetHelper.waitingTime) mDevice.waitNotNull(
onView(allOf(withText(startsWith("https://duckduckgo.com")))) Until.findObject(By.textContains("https://${searchEngineName.toLowerCase()}.com/?q=mozilla")),
TestAssetHelper.waitingTime
)
onView(allOf(withText(startsWith("https://${searchEngineName.toLowerCase()}.com"))))
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }
private fun assertDuckDuckGoResults() { private fun assertSearchEngineResults(searchEngineName: String) {
val count = mDevice.wait(Until.findObjects(By.text(("DuckDuckGo"))), TestAssetHelper.waitingTime) val count =
mDevice.wait(Until.findObjects(By.text((searchEngineName))), TestAssetHelper.waitingTime)
assert(count.size > 1) assert(count.size > 1)
} }

View File

@ -6,27 +6,67 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers import android.view.KeyEvent
import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
import android.view.KeyEvent.ACTION_DOWN
import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewAssertion
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import org.hamcrest.CoreMatchers.allOf
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
import org.hamcrest.Matcher
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.DECIMAL_CONVERSION
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.MIN_VALUE
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.STEP_SIZE
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.TEXT_SIZE
import kotlin.math.roundToInt
/** /**
* Implementation of Robot Pattern for the settings Accessibility sub menu. * Implementation of Robot Pattern for the settings Accessibility sub menu.
*/ */
class SettingsSubMenuAccessibilityRobot { class SettingsSubMenuAccessibilityRobot {
fun verifyAutomaticFontSizing() = assertAutomaticFontSizing() companion object {
const val STEP_SIZE = 5
const val MIN_VALUE = 50
const val DECIMAL_CONVERSION = 100f
const val TEXT_SIZE = 16f
}
fun verifyAutomaticFontSizingMenuItems() = assertAutomaticFontSizingMenuItems()
fun clickFontSizingSwitch() = toggleFontSizingSwitch()
fun verifyNewMenuItems() = assertNewMenuItems()
fun verifyNewMenuItemsAreGone() = assertNewMenuItemsAreGone()
fun changeTextSizeSlider(seekBarPercentage: Int) = adjustTextSizeSlider(seekBarPercentage)
fun verifyTextSizePercentage(textSize: Int) = assertTextSizePercentage(textSize)
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
mDevice.waitForIdle() mDevice.waitForIdle()
goBackButton().perform(ViewActions.click()) goBackButton().perform(click())
SettingsRobot().interact() SettingsRobot().interact()
return SettingsRobot.Transition() return SettingsRobot.Transition()
@ -34,13 +74,127 @@ class SettingsSubMenuAccessibilityRobot {
} }
} }
private fun assertAutomaticFontSizing() { val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
Espresso.onView(ViewMatchers.withText("Automatic Font Sizing"))
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) private fun assertAutomaticFontSizingMenuItems() {
onView(withText("Automatic Font Sizing"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
val strFont = "Font size will match your Android settings. Disable to manage font size here." val strFont = "Font size will match your Android settings. Disable to manage font size here."
Espresso.onView(ViewMatchers.withText(strFont)) onView(withText(strFont))
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun toggleFontSizingSwitch() {
// Toggle font size to off
onView(withText("Automatic Font Sizing"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.perform(click())
}
private fun assertNewMenuItems() {
assertFontSize()
assertSliderBar()
}
private fun assertFontSize() {
val view = onView(withText("Font Size"))
view.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
val strFont = "Make text on websites larger or smaller"
onView(withText(strFont))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertSliderBar() {
onView(withId(org.mozilla.fenix.R.id.sampleText))
.check(matches(withText("This is sample text. It is here to show how text will appear when you increase or decrease the size with this setting.")))
onView(withId(org.mozilla.fenix.R.id.seekbar_value))
.check(matches(withText("100%")))
onView(withId(org.mozilla.fenix.R.id.seekbar))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun adjustTextSizeSlider(seekBarPercentage: Int) {
onView(withId(org.mozilla.fenix.R.id.seekbar))
.perform(SeekBarChangeProgressViewAction(seekBarPercentage))
}
private fun assertTextSizePercentage(textSize: Int) {
onView(withId(org.mozilla.fenix.R.id.sampleText))
.check(textSizePercentageEquals(textSize))
}
private fun assertNewMenuItemsAreGone() {
onView(withText("Font Size")).check(doesNotExist())
val strFont = "Make text on websites larger or smaller"
onView(withText(strFont))
.check(doesNotExist())
onView(withId(org.mozilla.fenix.R.id.sampleText))
.check(doesNotExist())
onView(withId(org.mozilla.fenix.R.id.seekbar_value))
.check(doesNotExist())
onView(withId(org.mozilla.fenix.R.id.seekbar))
.check(doesNotExist())
} }
private fun goBackButton() = private fun goBackButton() =
Espresso.onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) onView(allOf(withContentDescription("Navigate up")))
class SeekBarChangeProgressViewAction(val seekBarPercentage: Int) : ViewAction {
override fun getConstraints(): Matcher<View> {
return isAssignableFrom(SeekBar::class.java)
}
override fun perform(uiController: UiController?, view: View?) {
val targetStepSize = calculateStepSizeFromPercentage(seekBarPercentage)
val seekbar = view as SeekBar
var progress = seekbar.progress
if (targetStepSize > progress) {
for (i in progress until targetStepSize) {
seekbar.onKeyDown(KEYCODE_DPAD_RIGHT, KeyEvent(ACTION_DOWN, KEYCODE_DPAD_RIGHT))
}
} else if (progress > targetStepSize) {
for (i in progress downTo targetStepSize) {
seekbar.onKeyDown(KEYCODE_DPAD_LEFT, KeyEvent(ACTION_DOWN, KEYCODE_DPAD_LEFT))
}
}
}
override fun getDescription(): String {
return "Changes the progress on a SeekBar, based on the percentage value."
}
}
fun textSizePercentageEquals(textSizePercentage: Int): ViewAssertion {
return ViewAssertion { view, noViewFoundException ->
if (noViewFoundException != null) throw noViewFoundException
val textView = view as TextView
val scaledPixels =
textView.textSize / InstrumentationRegistry.getInstrumentation().context.resources.displayMetrics.scaledDensity
val currentTextSizePercentage = calculateTextPercentageFromTextSize(scaledPixels)
if (currentTextSizePercentage != textSizePercentage) throw AssertionError("The textview has a text size percentage of $currentTextSizePercentage, and does not match $textSizePercentage")
}
}
fun calculateTextPercentageFromTextSize(textSize: Float): Int {
val decimal = textSize / TEXT_SIZE
return (decimal * DECIMAL_CONVERSION).roundToInt()
}
fun calculateStepSizeFromPercentage(textSizePercentage: Int): Int {
return ((textSizePercentage - MIN_VALUE) / STEP_SIZE)
}
fun checkTextSizeOnWebsite(textSizePercentage: Int, components: Components): Boolean {
// Checks the Gecko engine settings for the font size
val textSize = calculateStepSizeFromPercentage(textSizePercentage)
val newTextScale = ((textSize * STEP_SIZE) + MIN_VALUE).toFloat() / DECIMAL_CONVERSION
return components.core.engine.settings.fontSizeFactor == newTextScale
}

View File

@ -8,18 +8,37 @@ package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
import androidx.test.espresso.matcher.ViewMatchers.withParent
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.not
import org.mozilla.fenix.R
import org.mozilla.fenix.ui.robots.SettingsSubMenuDefaultBrowserRobot.Companion.DEFAULT_APPS_SETTINGS_ACTION
/** /**
* Implementation of Robot Pattern for the settings DefaultBrowser sub menu. * Implementation of Robot Pattern for the settings DefaultBrowser sub menu.
*/ */
class SettingsSubMenuDefaultBrowserRobot { class SettingsSubMenuDefaultBrowserRobot {
companion object {
const val DEFAULT_APPS_SETTINGS_ACTION = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"
}
fun verifyOpenLinksInPrivateTab() = assertOpenLinksInPrivateTab() fun verifyOpenLinksInPrivateTab() = assertOpenLinksInPrivateTab()
fun verifyDefaultBrowserIsDisabled() = assertDefaultBrowserIsDisabled()
fun clickDefaultBrowserSwitch() = toggleDefaultBrowserSwitch()
fun verifyAndroidDefaultAppsMenuAppears() = assertAndroidDefaultAppsMenuAppears()
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@ -34,10 +53,29 @@ class SettingsSubMenuDefaultBrowserRobot {
} }
} }
fun assertDefaultBrowserIsDisabled() {
onView(withId(R.id.switch_widget))
.check(matches(isNotChecked()))
}
fun toggleDefaultBrowserSwitch() {
onView(
allOf(
withParent(not(withId(R.id.navigationToolbar))),
withText("Set as default browser")
)
)
.perform(click())
}
private fun assertAndroidDefaultAppsMenuAppears() {
intended(hasAction(DEFAULT_APPS_SETTINGS_ACTION))
}
private fun assertOpenLinksInPrivateTab() { private fun assertOpenLinksInPrivateTab() {
onView(ViewMatchers.withText("Open links in private tab")) onView(withText("Open links in private tab"))
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun goBackButton() = private fun goBackButton() =
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) onView(allOf(withContentDescription("Navigate up")))

View File

@ -8,14 +8,15 @@ package org.mozilla.fenix.ui.robots
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions 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.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
@ -31,13 +32,17 @@ class SettingsSubMenuSearchRobot {
fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions() fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions()
fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory() fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory()
fun verifySearchBookmarks() = assertSearchBookmarks() fun verifySearchBookmarks() = assertSearchBookmarks()
fun changeDefaultSearchEngine(searchEngineName: String) =
selectDefaultSearchEngine(searchEngineName)
fun disableShowSearchSuggestions() = toggleShowSearchSuggestions()
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
mDevice.waitForIdle() mDevice.waitForIdle()
goBackButton().perform(ViewActions.click()) goBackButton().perform(click())
SettingsRobot().interact() SettingsRobot().interact()
return SettingsRobot.Transition() return SettingsRobot.Transition()
@ -46,24 +51,24 @@ class SettingsSubMenuSearchRobot {
} }
private fun assertDefaultSearchEngineHeader() = private fun assertDefaultSearchEngineHeader() =
onView(ViewMatchers.withText("Default search engine")) onView(withText("Default search engine"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertSearchEngineList() { private fun assertSearchEngineList() {
onView(ViewMatchers.withText("Google")) onView(withText("Google"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("Amazon.com")) onView(withText("Amazon.com"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("Bing")) onView(withText("Bing"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("DuckDuckGo")) onView(withText("DuckDuckGo"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("Twitter")) onView(withText("Twitter"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("Wikipedia")) onView(withText("Wikipedia"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
onView(ViewMatchers.withText("Add search engine")) onView(withText("Add search engine"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertShowSearchSuggestions() { private fun assertShowSearchSuggestions() {
@ -72,8 +77,8 @@ private fun assertShowSearchSuggestions() {
hasDescendant(withText("Show search suggestions")) hasDescendant(withText("Show search suggestions"))
) )
) )
onView(ViewMatchers.withText("Show search suggestions")) onView(withText("Show search suggestions"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertShowSearchShortcuts() { private fun assertShowSearchShortcuts() {
@ -82,8 +87,8 @@ private fun assertShowSearchShortcuts() {
hasDescendant(withText("Show search shortcuts")) hasDescendant(withText("Show search shortcuts"))
) )
) )
onView(ViewMatchers.withText("Show search shortcuts")) onView(withText("Show search shortcuts"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertShowClipboardSuggestions() { private fun assertShowClipboardSuggestions() {
@ -92,8 +97,8 @@ private fun assertShowClipboardSuggestions() {
hasDescendant(withText("Show clipboard suggestions")) hasDescendant(withText("Show clipboard suggestions"))
) )
) )
onView(ViewMatchers.withText("Show clipboard suggestions")) onView(withText("Show clipboard suggestions"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertSearchBrowsingHistory() { private fun assertSearchBrowsingHistory() {
@ -102,8 +107,8 @@ private fun assertSearchBrowsingHistory() {
hasDescendant(withText("Search browsing history")) hasDescendant(withText("Search browsing history"))
) )
) )
onView(ViewMatchers.withText("Search browsing history")) onView(withText("Search browsing history"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertSearchBookmarks() { private fun assertSearchBookmarks() {
@ -112,9 +117,30 @@ private fun assertSearchBookmarks() {
hasDescendant(withText("Search bookmarks")) hasDescendant(withText("Search bookmarks"))
) )
) )
onView(ViewMatchers.withText("Search bookmarks")) onView(withText("Search bookmarks"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun selectDefaultSearchEngine(searchEngine: String) {
onView(withText(searchEngine))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.perform(click())
}
private fun selectDuckDuckGoAsSearchEngine() {
selectDefaultSearchEngine("DuckDuckGo")
}
private fun toggleShowSearchSuggestions() {
onView(withId(androidx.preference.R.id.recycler_view)).perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText("Show search suggestions"))
)
)
onView(withText("Show search suggestions"))
.perform(click())
} }
private fun goBackButton() = private fun goBackButton() =
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) onView(CoreMatchers.allOf(withContentDescription("Navigate up")))

View File

@ -6,7 +6,9 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import android.os.Build
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
@ -25,7 +27,8 @@ class SettingsSubMenuThemeRobot {
fun verifyThemes() = assertThemes() fun verifyThemes() = assertThemes()
fun verifyLightThemeApplied(expected: Boolean) = assertFalse("Light theme not selected", expected) fun verifyLightThemeApplied(expected: Boolean) =
assertFalse("Light theme not selected", expected)
fun verifyDarkThemeApplied(expected: Boolean) = assertTrue("Dark theme not selected", expected) fun verifyDarkThemeApplied(expected: Boolean) = assertTrue("Dark theme not selected", expected)
@ -47,18 +50,23 @@ class SettingsSubMenuThemeRobot {
} }
private fun assertThemes() { private fun assertThemes() {
onView(withText("Light")) lightModeToggle()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
onView(withText("Dark")) darkModeToggle()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
deviceModeToggle()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
// Conditionally unavailable on API 25
// onView(ViewMatchers.withText("Follow device theme"))
// .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }
private fun goBackButton() =
onView(allOf(ViewMatchers.withContentDescription("Navigate up")))
private fun darkModeToggle() = onView(withText("Dark")) private fun darkModeToggle() = onView(withText("Dark"))
private fun lightModeToggle() = onView(withText("Light")) private fun lightModeToggle() = onView(withText("Light"))
private fun deviceModeToggle(): ViewInteraction {
val followDeviceThemeText =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "Follow device theme" else "Set by Battery Saver"
return onView(withText(followDeviceThemeText))
}
private fun goBackButton() =
onView(allOf(ViewMatchers.withContentDescription("Navigate up")))