From 095477e0ef7b9710e997fdbbbd4eb3a87609b5eb Mon Sep 17 00:00:00 2001 From: Kadeem M Date: Thu, 6 Feb 2020 15:58:47 -0500 Subject: [PATCH] =?UTF-8?q?Adding=20UI=20tests=20for=20the=20=20Basic=20Me?= =?UTF-8?q?nu=20settings.=20=F0=9F=8E=B2=20!!!!=20(#6346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added UI tests for the basic settings menu * Disabled toggleSearchSuggestions test --- .../org/mozilla/fenix/helpers/Matchers.kt | 4 + .../helpers/assertions/AwesomeBarAssertion.kt | 36 ++++ .../helpers/matchers/BitmapDrawableMatcher.kt | 35 ++++ .../java/org/mozilla/fenix/ui/SearchTest.kt | 8 +- .../mozilla/fenix/ui/SettingsBasicsTest.kt | 167 ++++++++++------ .../fenix/ui/robots/HomeScreenRobot.kt | 38 +++- .../fenix/ui/robots/NavigationToolbarRobot.kt | 79 ++++++-- .../mozilla/fenix/ui/robots/SearchRobot.kt | 49 +++-- .../SettingsSubMenuAccessibilityRobot.kt | 180 ++++++++++++++++-- .../SettingsSubMenuDefaultBrowserRobot.kt | 50 ++++- .../ui/robots/SettingsSubMenuSearchRobot.kt | 86 ++++++--- .../ui/robots/SettingsSubMenuThemeRobot.kt | 26 ++- 12 files changed, 599 insertions(+), 159 deletions(-) create mode 100644 app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt create mode 100644 app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/Matchers.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/Matchers.kt index 5368e8d4c..694fa784a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/Matchers.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Matchers.kt @@ -4,9 +4,11 @@ package org.mozilla.fenix.helpers +import android.graphics.Bitmap import android.view.View import org.hamcrest.CoreMatchers.not 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.isEnabled as espressoIsEnabled import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected @@ -30,3 +32,5 @@ private fun maybeInvertMatcher(matcher: Matcher, useUnmodifiedMatcher: Boo useUnmodifiedMatcher -> matcher else -> not(matcher) } + +fun withBitmapDrawable(bitmap: Bitmap, name: String): Matcher? = BitmapDrawableMatcher(bitmap, name) diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt new file mode 100644 index 000000000..9e30988d9 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt @@ -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") + } + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt new file mode 100644 index 000000000..73266796a --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt @@ -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(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 + } +} 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 e5d34b3d2..0fbd785c3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -52,11 +52,11 @@ class SearchTest { homeScreen { }.openSearch { verifySearchWithText() - clickDuckDuckGoEngineButton() + clickSearchEngineButton("DuckDuckGo") typeSearch("mozilla") - verifyDuckDuckGoResults() - clickDuckDuckGoResult() - verifyDuckDuckGoURL() + verifySearchEngineResults("DuckDuckGo") + clickSearchEngineResult("DuckDuckGo") + verifySearchEngineURL("DuckDuckGo") } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index c414cd5d9..9d0d22bd3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -10,12 +10,17 @@ import androidx.test.uiautomator.UiDevice 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.junit.Ignore +import org.mozilla.fenix.FenixApplication 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.navigationToolbar /** * Tests for verifying the main three dot menu options @@ -29,7 +34,7 @@ class SettingsBasicsTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityTestRule = HomeActivityTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule() @Before fun setUp() { @@ -45,7 +50,8 @@ class SettingsBasicsTest { } 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) { Configuration.UI_MODE_NIGHT_YES -> true // dark theme is set @@ -68,6 +74,7 @@ class SettingsBasicsTest { verifySearchEngineList() verifyShowSearchSuggestions() verifyShowSearchShortcuts() + verifyShowClipboardSuggestions() verifySearchBrowsingHistory() verifySearchBookmarks() @@ -76,7 +83,7 @@ class SettingsBasicsTest { verifyThemes() }.goBack { }.openAccessibilitySubMenu { - verifyAutomaticFontSizing() + verifyAutomaticFontSizingMenuItems() }.goBack { // drill down to submenu }.openDefaultBrowserSubMenu { @@ -86,49 +93,75 @@ class SettingsBasicsTest { } } - @Ignore("This is a stub test, ignore for now") @Test fun selectNewDefaultSearchEngine() { - // Open 3dot (main) menu - // Select settings - // Select "Search engine" - // Choose: DuckDuckGo - // Back arrow to Home - // Verify DuckDuckGo icon in Navigation bar + // Goes through the settings and changes the default search engine, then verifies it has changed. + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + 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 fun toggleSearchSuggestions() { - // Enter: "mozilla" in navigation bar - // Verify more than one suggesion provided - // Open 3dot (main) menu - // Select settings - // Select "Search engine" - // Toggle 'Show search suggestions' to 'off' - // Back arrow twice to home screen - // Enter: "mozilla" in navigation bar - // Verify no suggestions provided + // Goes through the settings and changes the search suggestion toggle, then verifies it changes. + homeScreen { + }.openNavigationToolbar { + verifySearchSuggestionsAreMoreThan(1, "mozilla") + }.goBack { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + disableShowSearchSuggestions() + }.goBack { + }.goBack { + }.openNavigationToolbar { + verifySearchSuggestionsAreEqualTo(0, "mozilla") + } } - @Ignore("This is a stub test, ignore for now") @Test fun toggleShowVisitedSitesAndBookmarks() { - // Visit 3 static sites - // Bookmark 2 of them - // Open 3dot (main) menu - // Enter navigation bar and verify visited sites appear - // Verify bookmarks exist - // Open 3dot (main) menu - // Select settings - // Select "Search engine" - // Toggle off "Show visited sites and bookmarks" - // Back arrow twice to home screen - // Verify history and bookmarks are gone + // 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. + val page1 = getGenericAsset(mockWebServer, 1) + val page2 = getGenericAsset(mockWebServer, 2) + val page3 = getGenericAsset(mockWebServer, 3) + + homeScreen { + }.openNavigationToolbar { + }.enterURLAndEnterToBrowser(page1.url) { + verifyPageContent(page1.content) + }.openThreeDotMenu { + clickAddBookmarkButton() + } + + navigationToolbar { + }.enterURLAndEnterToBrowser(page2.url) { + verifyPageContent(page2.content) + }.openThreeDotMenu { + clickAddBookmarkButton() + } + + navigationToolbar { + }.enterURLAndEnterToBrowser(page3.url) { + verifyPageContent(page3.content) + } + + navigationToolbar { + verifyNoHistoryBookmarks() + } + } @Test fun changeThemeSetting() { + // Goes through the settings and changes the default search engine, then verifies it changes. homeScreen { }.openThreeDotMenu { }.openSettings { @@ -141,40 +174,48 @@ class SettingsBasicsTest { } } - @Ignore("This is a stub test, ignore for now") @Test fun changeAccessibiltySettings() { - // Open 3dot (main) menu - // Select settings - // Select Accessibility - // Verify header: "Automatic Font Sizing" - // Verify description: "Font size will match your Android settings. Disable to manage font size here" - // Verify toggle is set to 'on' by default - // Toggle font size to off - // Verify that new sub-menu items appear.... - // Verify header: "Font Size" - // Verify description: "Make text on websites larger or smaller" - // Verify slider bar exists - // Verify slider bar default value set to 100% - // Verify sample text "The quick brown fox..." appears 4 times - // Move slider bar to 180% - // Verify that text grows to 180% - // Back error twice to home screen - // Open static website in navigation bar - // Verify that text is now at 180% - // Select settings - // Select Accessibility - // Toggle font size back to 'off' - // Verify that "Font Size" header, description, slider bar and sample text all disappear + // Goes through the settings and changes the default text on a webpage, then verifies if the text has changed. + val fenixApp = activityIntentTestRule.activity.applicationContext as FenixApplication + val webpage = getLoremIpsumAsset(mockWebServer).url + + // This value will represent the text size percentage the webpage will scale to. The default value is 100%. + val textSizePercentage = 180 + + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openAccessibilitySubMenu { + clickFontSizingSwitch() + verifyNewMenuItems() + changeTextSizeSlider(textSizePercentage) + verifyTextSizePercentage(textSizePercentage) + }.goBack { + }.goBack { + }.openNavigationToolbar { + }.enterURLAndEnterToBrowser(webpage) { + checkTextSizeOnWebsite(textSizePercentage, fenixApp.components) + }.openHomeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openAccessibilitySubMenu { + clickFontSizingSwitch() + verifyNewMenuItemsAreGone() + } } - @Ignore("This is a stub test, ignore for now") @Test fun changeDefaultBrowserSetting() { - // Open 3dot (main) menu - // Select settings - // Verify that "Set as default browser toggle is set to 'off' (default) - // Turn default browser toggle 'on' - // Verify that Andrdoid "Default Apps" menu appears + // Opens settings and toggles the default browser setting to on. The device settings open and allows the user to set a default browser. + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openDefaultBrowserSubMenu { + verifyDefaultBrowserIsDisabled() + clickDefaultBrowserSwitch() + verifyAndroidDefaultAppsMenuAppears() + } + } } 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 46136cb49..ecf982021 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 @@ -7,6 +7,7 @@ package org.mozilla.fenix.ui.robots import androidx.recyclerview.widget.RecyclerView +import android.graphics.Bitmap import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions 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.contrib.RecyclerViewActions 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.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.uiautomator.By 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.click 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. @@ -53,6 +56,7 @@ class HomeScreenRobot { fun verifyHomeWordmark() = assertHomeWordmark() fun verifyHomeToolbar() = assertHomeToolbar() fun verifyHomeComponent() = assertHomeComponent() + fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine) // First Run elements fun verifyWelcomeHeader() = assertWelcomeHeader() @@ -81,6 +85,7 @@ class HomeScreenRobot { // Private mode elements fun verifyPrivateSessionHeader() = assertPrivateSessionHeader() + fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible) fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton() @@ -114,7 +119,6 @@ class HomeScreenRobot { fun typeCollectionName(name: String) { mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime) - collectionNameTextField().perform(ViewActions.replaceText(name)) collectionNameTextField().perform(ViewActions.pressImeActionButton()) } @@ -206,6 +210,13 @@ class HomeScreenRobot { HomeScreenRobot().interact() 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 appContext = InstrumentationRegistry.getInstrumentation().targetContext private fun navigationToolbar() = 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 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 private fun assertWelcomeHeader() = 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 collectionThreeDotButton() = onView(allOf(withId(R.id.collection_overflow_button))) +private fun collectionThreeDotButton() = + onView(allOf(withId(R.id.collection_overflow_button))) private fun collectionNameTextField() = onView(allOf(ViewMatchers.withResourceName("name_collection_edittext"))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index 454eecd12..e06971a95 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -10,26 +10,49 @@ import android.net.Uri import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.pressImeActionButton 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.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until +import org.hamcrest.CoreMatchers.not import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.click 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. */ 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 { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - fun enterURLAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), waitingTime) + fun enterURLAndEnterToBrowser( + url: Uri, + interact: BrowserRobot.() -> Unit + ): BrowserRobot.Transition { + mDevice.waitNotNull( + Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), + waitingTime + ) urlBar().click() awesomeBar().perform(replaceText(url.toString()), pressImeActionButton()) @@ -45,7 +68,10 @@ class NavigationToolbarRobot { 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) newTab().click() awesomeBar().perform(replaceText(url.toString()), pressImeActionButton()) @@ -75,6 +101,13 @@ class NavigationToolbarRobot { BrowserRobot().interact() 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() } -private fun dismissOnboardingButton() = onView(ViewMatchers.withId(R.id.close_onboarding)) -private fun urlBar() = onView(ViewMatchers.withId(R.id.toolbar)) -private fun awesomeBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_edit_url_view)) -private fun threeDotButton() = onView(ViewMatchers.withContentDescription("Menu")) -private fun newTab() = onView(ViewMatchers.withContentDescription("Add tab")) -private fun fillLinkButton() = onView(ViewMatchers.withId(R.id.clipboard_url)) -private fun clearAddressBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_clear_view)) +private fun assertSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) { + mDevice.waitForIdle() + awesomeBar().perform(typeText(searchTerm)) + + mDevice.waitForIdle() + onView(withId(R.id.awesomeBar)).check(suggestionsAreEqualTo(suggestionSize)) +} + +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() 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 5188db512..3049e14ce 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 @@ -39,8 +39,10 @@ class SearchRobot { fun verifyBrowserToolbar() = assertBrowserToolbarEditView() fun verifyScanButton() = assertScanButton() fun verifySearchWithText() = assertSearchWithText() - fun verifyDuckDuckGoResults() = assertDuckDuckGoResults() - fun verifyDuckDuckGoURL() = assertDuckDuckGoURL() + fun verifySearchEngineResults(searchEngineName: String) = + assertSearchEngineResults(searchEngineName) + + fun verifySearchEngineURL(searchEngineName: String) = assertSearchEngineURL(searchEngineName) fun verifySearchSettings() = assertSearchSettings() fun verifySearchBarEmpty() = assertSearchBarEmpty() @@ -60,13 +62,21 @@ class SearchRobot { browserToolbarEditView().perform(typeText(searchTerm)) } - fun clickDuckDuckGoEngineButton() { - duckDuckGoEngineButton().perform(click()) + fun clickSearchEngineButton(searchEngineName: String) { + searchEngineButton(searchEngineName).perform(click()) } - fun clickDuckDuckGoResult() { - mDevice.waitNotNull(Until.findObjects(By.text("DuckDuckGo")), TestAssetHelper.waitingTime) - awesomeBar().perform(RecyclerViewActions.actionOnItemAtPosition(0, click())) + fun clickSearchEngineResult(searchEngineName: String) { + mDevice.waitNotNull( + Until.findObjects(By.text(searchEngineName)), + TestAssetHelper.waitingTime + ) + awesomeBar().perform( + RecyclerViewActions.actionOnItemAtPosition( + 0, + click() + ) + ) } fun scrollToSearchEngineSettings(): UiScrollable { @@ -88,7 +98,7 @@ class SearchRobot { fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { mDevice.waitForIdle() - browserToolbarEditView().perform(typeText("Mozilla\n")) + browserToolbarEditView().perform(typeText("mozilla\n")) BrowserRobot().interact() return BrowserRobot.Transition() @@ -98,11 +108,12 @@ class SearchRobot { 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 { - mDevice.waitNotNull(Until.findObject(By.text("DuckDuckGo")), TestAssetHelper.waitingTime) - return onView(Matchers.allOf(withText("DuckDuckGo"))) +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 { @@ -122,14 +133,18 @@ private fun scanButton(): ViewInteraction { private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view)) -private fun assertDuckDuckGoURL() { - mDevice.waitNotNull(Until.findObject(By.textContains("https://duckduckgo.com/?q=mozilla")), TestAssetHelper.waitingTime) - onView(allOf(withText(startsWith("https://duckduckgo.com")))) +private fun assertSearchEngineURL(searchEngineName: String) { + mDevice.waitNotNull( + 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))) } -private fun assertDuckDuckGoResults() { - val count = mDevice.wait(Until.findObjects(By.text(("DuckDuckGo"))), TestAssetHelper.waitingTime) +private fun assertSearchEngineResults(searchEngineName: String) { + val count = + mDevice.wait(Until.findObjects(By.text((searchEngineName))), TestAssetHelper.waitingTime) assert(count.size > 1) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAccessibilityRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAccessibilityRobot.kt index 3bee4db8c..c7592751a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAccessibilityRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAccessibilityRobot.kt @@ -6,27 +6,67 @@ package org.mozilla.fenix.ui.robots -import androidx.test.espresso.Espresso -import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.platform.app.InstrumentationRegistry 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. */ 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 { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { mDevice.waitForIdle() - goBackButton().perform(ViewActions.click()) + goBackButton().perform(click()) SettingsRobot().interact() return SettingsRobot.Transition() @@ -34,13 +74,127 @@ class SettingsSubMenuAccessibilityRobot { } } -private fun assertAutomaticFontSizing() { - Espresso.onView(ViewMatchers.withText("Automatic Font Sizing")) - .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) +val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + +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." - Espresso.onView(ViewMatchers.withText(strFont)) - .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText(strFont)) + .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() = - Espresso.onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) + onView(allOf(withContentDescription("Navigate up"))) + +class SeekBarChangeProgressViewAction(val seekBarPercentage: Int) : ViewAction { + override fun getConstraints(): Matcher { + 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 +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuDefaultBrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuDefaultBrowserRobot.kt index 97f34186e..87697d0ae 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuDefaultBrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuDefaultBrowserRobot.kt @@ -8,18 +8,37 @@ package org.mozilla.fenix.ui.robots import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.action.ViewActions.click +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.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. */ class SettingsSubMenuDefaultBrowserRobot { + companion object { + const val DEFAULT_APPS_SETTINGS_ACTION = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS" + } + fun verifyOpenLinksInPrivateTab() = assertOpenLinksInPrivateTab() + fun verifyDefaultBrowserIsDisabled() = assertDefaultBrowserIsDisabled() + fun clickDefaultBrowserSwitch() = toggleDefaultBrowserSwitch() + fun verifyAndroidDefaultAppsMenuAppears() = assertAndroidDefaultAppsMenuAppears() class Transition { 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() { - onView(ViewMatchers.withText("Open links in private tab")) - .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Open links in private tab")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun goBackButton() = - onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) + onView(allOf(withContentDescription("Navigate up"))) 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 45ba1a433..b50e5aae2 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 @@ -8,14 +8,15 @@ package org.mozilla.fenix.ui.robots import androidx.recyclerview.widget.RecyclerView 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.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.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import org.hamcrest.CoreMatchers @@ -31,13 +32,17 @@ class SettingsSubMenuSearchRobot { fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions() fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory() fun verifySearchBookmarks() = assertSearchBookmarks() + fun changeDefaultSearchEngine(searchEngineName: String) = + selectDefaultSearchEngine(searchEngineName) + + fun disableShowSearchSuggestions() = toggleShowSearchSuggestions() class Transition { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { mDevice.waitForIdle() - goBackButton().perform(ViewActions.click()) + goBackButton().perform(click()) SettingsRobot().interact() return SettingsRobot.Transition() @@ -46,24 +51,24 @@ class SettingsSubMenuSearchRobot { } private fun assertDefaultSearchEngineHeader() = - onView(ViewMatchers.withText("Default search engine")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Default search engine")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertSearchEngineList() { - onView(ViewMatchers.withText("Google")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("Amazon.com")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("Bing")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("DuckDuckGo")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("Twitter")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("Wikipedia")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - onView(ViewMatchers.withText("Add search engine")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + 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("Twitter")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Wikipedia")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Add search engine")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertShowSearchSuggestions() { @@ -72,8 +77,8 @@ private fun assertShowSearchSuggestions() { hasDescendant(withText("Show search suggestions")) ) ) - onView(ViewMatchers.withText("Show search suggestions")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Show search suggestions")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertShowSearchShortcuts() { @@ -82,8 +87,8 @@ private fun assertShowSearchShortcuts() { hasDescendant(withText("Show search shortcuts")) ) ) - onView(ViewMatchers.withText("Show search shortcuts")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Show search shortcuts")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertShowClipboardSuggestions() { @@ -92,8 +97,8 @@ private fun assertShowClipboardSuggestions() { hasDescendant(withText("Show clipboard suggestions")) ) ) - onView(ViewMatchers.withText("Show clipboard suggestions")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Show clipboard suggestions")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertSearchBrowsingHistory() { @@ -102,8 +107,8 @@ private fun assertSearchBrowsingHistory() { hasDescendant(withText("Search browsing history")) ) ) - onView(ViewMatchers.withText("Search browsing history")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Search browsing history")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertSearchBookmarks() { @@ -112,9 +117,30 @@ private fun assertSearchBookmarks() { hasDescendant(withText("Search bookmarks")) ) ) - onView(ViewMatchers.withText("Search bookmarks")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + onView(withText("Search bookmarks")) + .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( + hasDescendant(withText("Show search suggestions")) + ) + ) + + onView(withText("Show search suggestions")) + .perform(click()) } private fun goBackButton() = - onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) + onView(CoreMatchers.allOf(withContentDescription("Navigate up"))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuThemeRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuThemeRobot.kt index d7d26c126..a3b425a10 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuThemeRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuThemeRobot.kt @@ -6,7 +6,9 @@ package org.mozilla.fenix.ui.robots +import android.os.Build import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.matcher.ViewMatchers @@ -25,7 +27,8 @@ class SettingsSubMenuThemeRobot { 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) @@ -47,18 +50,23 @@ class SettingsSubMenuThemeRobot { } private fun assertThemes() { - onView(withText("Light")) + lightModeToggle() .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))) - // 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 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")))