1
0
Fork 0

Closes #8082 - Add UI tests for Top Sites

WIP

wip

WIP

WIP

WIP

WIP

fix: unused import [ktlint]
master
Aaron Train 2020-02-06 16:06:28 -05:00 committed by Jeff Boek
parent a5ac7304bb
commit 029bbd3726
5 changed files with 366 additions and 45 deletions

View File

@ -0,0 +1,29 @@
package org.mozilla.fenix.helpers.matchers
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.matcher.BoundedMatcher
import org.hamcrest.Description
import org.hamcrest.Matcher
fun hasItem(matcher: Matcher<View?>): Matcher<View?>? {
return object : BoundedMatcher<View?, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description) {
description.appendText("has item: ")
matcher.describeTo(description)
}
override fun matchesSafely(view: RecyclerView): Boolean {
val adapter = view.adapter
for (position in 0 until adapter!!.itemCount) {
val type = adapter.getItemViewType(position)
val holder = adapter.createViewHolder(view, type)
adapter.onBindViewHolder(holder, position)
if (matcher.matches(holder.itemView)) {
return true
}
}
return false
}
}
}

View File

@ -0,0 +1,162 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ui
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.navigationToolbar
/**
* Tests Top Sites functionality
*
* - Verifies 'Add to Firefox Home' UI functionality
* - Verifies 'Top Sites' context menu UI functionality
* - Verifies 'Top Site' usage UI functionality
* - Verifies existence of default top sites available on the home-screen
*/
class TopSitesTest {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private lateinit var mockWebServer: MockWebServer
@get:Rule
val activityIntentTestRule = HomeActivityIntentTestRule()
@Before
fun setUp() {
mockWebServer = MockWebServer().apply {
setDispatcher(AndroidAssetDispatcher())
start()
}
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
@Test
fun verifyAddToFirefoxHome() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val defaultWebPageTitle = "Test_Page_1"
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openThreeDotMenu {
verifyAddFirefoxHome()
}.addToFirefoxHome {
verifySnackBarText("Added to top sites!")
}.openHomeScreen {
verifyExistingTabList()
verifyExistingTopSitesList()
verifyExistingTopSitesTabs(defaultWebPageTitle)
}
}
@Test
fun verifyOpenTopSiteNormalTab() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val defaultWebPageTitle = "Test_Page_1"
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openThreeDotMenu {
verifyAddFirefoxHome()
}.addToFirefoxHome {
verifySnackBarText("Added to top sites!")
}.openHomeScreen {
verifyExistingTabList()
verifyExistingTopSitesList()
verifyExistingTopSitesTabs(defaultWebPageTitle)
}.openTopSiteTabWithTitle(title = defaultWebPageTitle) {
verifyPageContent(defaultWebPage.content)
verifyUrl(defaultWebPage.url.toString())
}.openHomeScreen {
verifyExistingTopSitesList()
verifyExistingTopSitesTabs(defaultWebPageTitle)
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
verifyTopSiteContextMenuItems()
}
// Dismiss context menu popup
mDevice.pressBack()
}
@Test
fun verifyOpenTopSitePrivateTab() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val defaultWebPageTitle = "Test_Page_1"
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openThreeDotMenu {
verifyAddFirefoxHome()
}.addToFirefoxHome {
verifySnackBarText("Added to top sites!")
}.openHomeScreen {
verifyExistingTabList()
verifyExistingTopSitesList()
verifyExistingTopSitesTabs(defaultWebPageTitle)
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
verifyTopSiteContextMenuItems()
}.openTopSiteInPrivateTab {
verifyCurrentPrivateSession(activityIntentTestRule.activity.applicationContext)
}
}
@Test
fun verifyRemoveTopSite() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val defaultWebPageTitle = "Test_Page_1"
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openThreeDotMenu {
verifyAddFirefoxHome()
}.addToFirefoxHome {
verifySnackBarText("Added to top sites!")
}.openHomeScreen {
verifyExistingTabList()
verifyExistingTopSitesList()
verifyExistingTopSitesTabs(defaultWebPageTitle)
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
verifyTopSiteContextMenuItems()
}.removeTopSite {
verifyNotExistingTopSitesList(defaultWebPageTitle)
}
}
@Test
fun verifyDefaultTopSitesLocale_EN() {
// en-US defaults
val defaultTopSites = arrayOf(
"Top Articles",
"Wikipedia",
"YouTube"
)
homeScreen { }.dismissOnboarding()
homeScreen {
verifyExistingTopSitesList()
defaultTopSites.forEach { item ->
verifyExistingTopSitesTabs(item)
}
}
}
}

View File

@ -6,6 +6,7 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
@ -15,6 +16,7 @@ import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.BundleMatchers import androidx.test.espresso.intent.matcher.BundleMatchers
import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
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
@ -25,11 +27,13 @@ import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.containsString
import org.junit.Assert.assertTrue
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.Constants.LongClickDuration
import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper
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.Constants.LongClickDuration
class BrowserRobot { class BrowserRobot {
@ -38,6 +42,11 @@ class BrowserRobot {
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }
fun verifyCurrentPrivateSession(context: Context) {
val session = context.components.core.sessionManager.selectedSession
assertTrue("Current session is private", session?.private!!)
}
fun verifyUrl(url: String) { fun verifyUrl(url: String) {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.waitNotNull( mDevice.waitNotNull(
@ -76,6 +85,10 @@ class BrowserRobot {
fun verifySnackBarText(expectedText: String) { fun verifySnackBarText(expectedText: String) {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime) mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
onView(withText(expectedText)).check(
matches(isCompletelyDisplayed())
)
} }
fun verifyLinkContextMenuItems(containsURL: Uri) { fun verifyLinkContextMenuItems(containsURL: Uri) {
@ -324,4 +337,4 @@ fun dismissTrackingOnboarding() {
fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view)) fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
private fun tabsCounter() = onView(withId(R.id.counter_box)) private fun tabsCounter() = onView(withId(R.id.mozac_browser_toolbar_browser_actions))

View File

@ -14,10 +14,12 @@ import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist 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.contrib.RecyclerViewActions.actionOnItem
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
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.Visibility
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
@ -27,9 +29,9 @@ import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.Matchers.allOf import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Matchers.containsString import org.hamcrest.CoreMatchers.not
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
@ -37,6 +39,7 @@ 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.components.Search
import org.mozilla.fenix.helpers.withBitmapDrawable import org.mozilla.fenix.helpers.withBitmapDrawable
import org.mozilla.fenix.helpers.matchers.hasItem
/** /**
* Implementation of Robot Pattern for the home screen menu. * Implementation of Robot Pattern for the home screen menu.
@ -96,6 +99,11 @@ class HomeScreenRobot {
fun verifyExistingTabList() = assertExistingTabList() fun verifyExistingTabList() = assertExistingTabList()
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title) fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
fun verifyExistingTopSitesList() = assertExistingTopSitesList()
fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
fun verifyExistingTopSitesTabs(title: String) = assertExistingTopSitesTabs(title)
fun verifyTopSiteContextMenuItems() = assertTopSiteContextMenuItems()
// Collections element // Collections element
fun clickCollectionThreeDotButton() { fun clickCollectionThreeDotButton() {
collectionThreeDotButton().click() collectionThreeDotButton().click()
@ -160,7 +168,7 @@ class HomeScreenRobot {
} }
fun snackBarButtonClick(expectedText: String) { fun snackBarButtonClick(expectedText: String) {
onView(CoreMatchers.allOf(withId(R.id.snackbar_btn), withText(expectedText))).check( onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))
).perform(ViewActions.click()) ).perform(ViewActions.click())
} }
@ -217,6 +225,42 @@ class HomeScreenRobot {
NavigationToolbarRobot().interact() NavigationToolbarRobot().interact()
return NavigationToolbarRobot.Transition() return NavigationToolbarRobot.Transition()
} }
fun openContextMenuOnTopSitesWithTitle(title: String, interact: HomeScreenRobot.() -> Unit): Transition {
onView(withId(R.id.top_sites_list)).perform(
actionOnItem<RecyclerView.ViewHolder>(hasDescendant(withText(title)), ViewActions.longClick())
)
HomeScreenRobot().interact()
return Transition()
}
fun openTopSiteTabWithTitle(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
onView(withId(R.id.top_sites_list)).perform(
actionOnItem<RecyclerView.ViewHolder>(hasDescendant(withText(title)), click())
)
BrowserRobot().interact()
return BrowserRobot.Transition()
}
fun removeTopSite(interact: HomeScreenRobot.() -> Unit): Transition {
onView(withText("Remove"))
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
.perform(click())
HomeScreenRobot().interact()
return Transition()
}
fun openTopSiteInPrivateTab(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
onView(withText("Open in private tab"))
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
.perform(click())
BrowserRobot().interact()
return BrowserRobot.Transition()
}
} }
} }
@ -229,12 +273,12 @@ val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val appContext = InstrumentationRegistry.getInstrumentation().targetContext val appContext = InstrumentationRegistry.getInstrumentation().targetContext
private fun navigationToolbar() = private fun navigationToolbar() =
onView(CoreMatchers.allOf(withText("Search or enter address"))) onView(allOf(withText("Search or enter address")))
private fun closeTabButton() = onView(withId(R.id.close_tab_button)) private fun closeTabButton() = onView(withId(R.id.close_tab_button))
private fun assertNavigationToolbar() = private fun assertNavigationToolbar() =
onView(CoreMatchers.allOf(withText("Search or enter address"))) onView(allOf(withText("Search or enter address")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout")) private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
@ -254,33 +298,33 @@ private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertOpenTabsHeader() = private fun assertOpenTabsHeader() =
onView(CoreMatchers.allOf(withText("Open tabs"))) onView(allOf(withText("Open tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAddTabButton() = private fun assertAddTabButton() =
onView(CoreMatchers.allOf(withId(R.id.add_tab_button), isDisplayed())) onView(allOf(withId(R.id.add_tab_button), isDisplayed()))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoTabsOpenedHeader() = private fun assertNoTabsOpenedHeader() =
onView(CoreMatchers.allOf(withText("No open tabs"))) onView(allOf(withText("No open tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoTabsOpenedText() { private fun assertNoTabsOpenedText() {
onView(CoreMatchers.allOf(withText("Your open tabs will be shown here."))) onView(allOf(withText("Your open tabs will be shown here.")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertCollectionsHeader() = private fun assertCollectionsHeader() =
onView(CoreMatchers.allOf(withText("Collections"))) onView(allOf(withText("Collections")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoCollectionsHeader() = private fun assertNoCollectionsHeader() =
onView(CoreMatchers.allOf(withText("No collections"))) onView(allOf(withText("No collections")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoCollectionsText() = private fun assertNoCollectionsText() =
onView( onView(
CoreMatchers.allOf( allOf(
withText("Collect the things that matter to you. To start, save open tabs to a new collection.") withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
) )
) )
@ -306,11 +350,11 @@ private fun verifySearchEngineIcon(searchEngineName: String) {
// First Run elements // First Run elements
private fun assertWelcomeHeader() = private fun assertWelcomeHeader() =
onView(CoreMatchers.allOf(withText("Welcome to Firefox Preview!"))) onView(allOf(withText("Welcome to Firefox Preview!")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertGetTheMostHeader() = private fun assertGetTheMostHeader() =
onView(CoreMatchers.allOf(withText("Get the most out of Firefox Preview."))) onView(allOf(withText("Get the most out of Firefox Preview.")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAccountsSignInButton() = private fun assertAccountsSignInButton() =
@ -318,15 +362,15 @@ private fun assertAccountsSignInButton() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertGetToKnowHeader() = private fun assertGetToKnowHeader() =
onView(CoreMatchers.allOf(withText("Get to know Firefox Preview"))) onView(allOf(withText("Get to know Firefox Preview")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertChooseThemeHeader() = private fun assertChooseThemeHeader() =
onView(CoreMatchers.allOf(withText("Choose your theme"))) onView(allOf(withText("Choose your theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertChooseThemeText() = private fun assertChooseThemeText() =
onView(CoreMatchers.allOf(withText("Try dark theme: easier on your battery and your eyes."))) onView(allOf(withText("Try dark theme: easier on your battery and your eyes.")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertLightThemeToggle() = private fun assertLightThemeToggle() =
@ -334,7 +378,7 @@ private fun assertLightThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertLightThemeDescription() = private fun assertLightThemeDescription() =
onView(CoreMatchers.allOf(withText("Light theme"))) onView(allOf(withText("Light theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertDarkThemeToggle() = private fun assertDarkThemeToggle() =
@ -342,7 +386,7 @@ private fun assertDarkThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertDarkThemeDescription() = private fun assertDarkThemeDescription() =
onView(CoreMatchers.allOf(withText("Dark theme"))) onView(allOf(withText("Dark theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAutomaticThemeToggle() = private fun assertAutomaticThemeToggle() =
@ -350,21 +394,21 @@ private fun assertAutomaticThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAutomaticThemeDescription() = private fun assertAutomaticThemeDescription() =
onView(CoreMatchers.allOf(withText("Automatic"))) onView(allOf(withText("Automatic")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertProtectYourselfHeader() = private fun assertProtectYourselfHeader() =
onView(CoreMatchers.allOf(withText("Protect yourself"))) onView(allOf(withText("Protect yourself")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertTrackingProtectionToggle() = onView( private fun assertTrackingProtectionToggle() = onView(
CoreMatchers.allOf(ViewMatchers.withResourceName("tracking_protection_toggle")) allOf(ViewMatchers.withResourceName("tracking_protection_toggle"))
) )
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertProtectYourselfText() { private fun assertProtectYourselfText() {
onView( onView(
CoreMatchers.allOf( allOf(
withText( withText(
"Firefox Preview blocks ad trackers that follow you around the web." "Firefox Preview blocks ad trackers that follow you around the web."
) )
@ -374,20 +418,20 @@ private fun assertProtectYourselfText() {
} }
private fun assertBrowsePrivatelyHeader() = private fun assertBrowsePrivatelyHeader() =
onView(CoreMatchers.allOf(withText("Browse privately"))) onView(allOf(withText("Browse privately")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertBrowsePrivatelyText() = private fun assertBrowsePrivatelyText() =
onView(CoreMatchers.allOf(withText(containsString("private browsing is just a tap away.")))) onView(allOf(withText(containsString("private browsing is just a tap away."))))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertYourPrivacyHeader() = private fun assertYourPrivacyHeader() =
onView(CoreMatchers.allOf(withText("Your privacy"))) onView(allOf(withText("Your privacy")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertYourPrivacyText() = private fun assertYourPrivacyText() =
onView( onView(
CoreMatchers.allOf( allOf(
withText( withText(
"Weve designed Firefox Preview to give you control over what you share online and what you share with us." "Weve designed Firefox Preview to give you control over what you share online and what you share with us."
) )
@ -396,16 +440,16 @@ private fun assertYourPrivacyText() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertPrivacyNoticeButton() = private fun assertPrivacyNoticeButton() =
onView(CoreMatchers.allOf(withText("Read our privacy notice"))) onView(allOf(withText("Read our privacy notice")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertStartBrowsingButton() = private fun assertStartBrowsingButton() =
onView(CoreMatchers.allOf(withText("Start browsing"))) onView(allOf(withText("Start browsing")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
// Private mode elements // Private mode elements
private fun assertPrivateSessionHeader() = private fun assertPrivateSessionHeader() =
onView(CoreMatchers.allOf(withText("Private tabs"))) onView(allOf(withText("Private tabs")))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " + const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
@ -414,13 +458,13 @@ const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and brow
"who uses this device." "who uses this device."
private fun assertPrivateSessionMessage(visible: Boolean) = private fun assertPrivateSessionMessage(visible: Boolean) =
onView(CoreMatchers.allOf(withText(PRIVATE_SESSION_MESSAGE))) onView(allOf(withText(PRIVATE_SESSION_MESSAGE)))
.check( .check(
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist() if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist()
) )
private fun assertShareTabsButton(visible: Boolean) = private fun assertShareTabsButton(visible: Boolean) =
onView(CoreMatchers.allOf(withId(R.id.share_tabs_button), isDisplayed())) onView(allOf(withId(R.id.share_tabs_button), isDisplayed()))
.check(matches(withEffectiveVisibility(visibleOrGone(visible)))) .check(matches(withEffectiveVisibility(visibleOrGone(visible))))
private fun assertCloseTabsButton(title: String) = private fun assertCloseTabsButton(title: String) =
@ -431,7 +475,7 @@ private fun visibleOrGone(visibility: Boolean) =
if (visibility) Visibility.VISIBLE else Visibility.GONE if (visibility) Visibility.VISIBLE else Visibility.GONE
private fun assertExistingTabList() = private fun assertExistingTabList() =
onView(CoreMatchers.allOf(withId(R.id.item_tab))) onView(allOf(withId(R.id.item_tab)))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertExistingOpenTabs(title: String) = private fun assertExistingOpenTabs(title: String) =
@ -460,3 +504,29 @@ private fun closeTabViaX(title: String) {
} }
private fun assertPrivateTabsCloseTabsButton() = onView(allOf(withId(R.id.close_tabs_button))) private fun assertPrivateTabsCloseTabsButton() = onView(allOf(withId(R.id.close_tabs_button)))
private fun assertExistingTopSitesList() =
onView(allOf(withId(R.id.top_sites_list)))
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
private fun assertExistingTopSitesTabs(title: String) =
onView(allOf(withId(R.id.top_sites_list)))
.check(matches(hasItem(hasDescendant(withText(title)))))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNotExistingTopSitesList(title: String) =
onView(allOf(withId(R.id.top_sites_list)))
.check(matches(not(hasItem(hasDescendant(withText(title))))))
private fun assertTopSiteContextMenuItems() {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.waitNotNull(
Until.findObject(By.text("Open in private tab")),
waitingTime
)
mDevice.waitNotNull(
Until.findObject(By.text("Remove")),
waitingTime
)
}

View File

@ -6,17 +6,21 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.contrib.RecyclerViewActions
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.assertion.ViewAssertions
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.hasFocus import androidx.test.espresso.matcher.ViewMatchers.hasFocus
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
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.withResourceName import androidx.test.espresso.matcher.ViewMatchers.withResourceName
import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.Visibility
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
@ -75,6 +79,7 @@ class ThreeDotMenuMainRobot {
fun verifySendToDeviceTitle() = assertSendToDeviceTitle() fun verifySendToDeviceTitle() = assertSendToDeviceTitle()
fun verifyShareALinkTitle() = assertShareALinkTitle() fun verifyShareALinkTitle() = assertShareALinkTitle()
fun verifyWhatsNewButton() = assertWhatsNewButton() fun verifyWhatsNewButton() = assertWhatsNewButton()
fun verifyAddFirefoxHome() = assertAddToFirefoxHome()
class Transition { class Transition {
@ -185,11 +190,20 @@ class ThreeDotMenuMainRobot {
return BrowserRobot.Transition() return BrowserRobot.Transition()
} }
fun typeCollectionName(name: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { fun typeCollectionName(
mDevice.wait(Until.findObject(By.res("org.mozilla.fenix.debug:id/name_collection_edittext")), waitingTime) name: String,
interact: BrowserRobot.() -> Unit
): BrowserRobot.Transition {
mDevice.wait(
Until.findObject(By.res("org.mozilla.fenix.debug:id/name_collection_edittext")),
waitingTime
)
collectionNameTextField().check(matches(hasFocus())) collectionNameTextField().check(matches(hasFocus()))
collectionNameTextField().perform(ViewActions.replaceText(name), ViewActions.pressImeActionButton()) collectionNameTextField().perform(
ViewActions.replaceText(name),
ViewActions.pressImeActionButton()
)
BrowserRobot().interact() BrowserRobot().interact()
return BrowserRobot.Transition() return BrowserRobot.Transition()
@ -208,6 +222,13 @@ class ThreeDotMenuMainRobot {
ReaderViewRobot().interact() ReaderViewRobot().interact()
return ReaderViewRobot.Transition() return ReaderViewRobot.Transition()
} }
fun addToFirefoxHome(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
addToFirefoxHomeButton().click()
BrowserRobot().interact()
return BrowserRobot.Transition()
}
} }
} }
@ -215,8 +236,13 @@ private fun threeDotMenuRecyclerViewExists() {
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed())) onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
} }
private fun settingsButton() = onView(allOf(withText(R.string.settings), private fun settingsButton() = onView(
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) allOf(
withText(R.string.settings),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
)
)
private fun assertSettingsButton() = settingsButton() private fun assertSettingsButton() = settingsButton()
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
@ -264,8 +290,12 @@ private fun shareButton() = onView(ViewMatchers.withContentDescription("Share"))
private fun assertShareButton() = shareButton() private fun assertShareButton() = shareButton()
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
private fun browserViewSaveCollectionButton() = onView(allOf(withText("Save to Collection"), private fun browserViewSaveCollectionButton() = onView(
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) allOf(
withText("Save to Collection"),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
)
)
private fun saveCollectionButton() = onView(allOf(withText("Save to collection"))) private fun saveCollectionButton() = onView(allOf(withText("Save to collection")))
private fun assertSaveCollectionButton() = saveCollectionButton() private fun assertSaveCollectionButton() = saveCollectionButton()
@ -300,7 +330,10 @@ private fun assertShareALinkTitle() = ShareALinkTitle()
private fun whatsNewButton() = onView( private fun whatsNewButton() = onView(
allOf( allOf(
withText("Whats New"), withText("Whats New"),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
)
)
private fun assertWhatsNewButton() = whatsNewButton() private fun assertWhatsNewButton() = whatsNewButton()
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
@ -309,8 +342,22 @@ private fun assertReaderViewToggle(visible: Boolean) = readerViewToggle()
.check( .check(
if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist() if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist()
) )
private fun readerViewAppearanceToggle() = onView(allOf(withText(R.string.browser_menu_read_appearance)))
private fun readerViewAppearanceToggle() =
onView(allOf(withText(R.string.browser_menu_read_appearance)))
private fun assertReaderViewAppearanceButton(visible: Boolean) = readerViewAppearanceToggle() private fun assertReaderViewAppearanceButton(visible: Boolean) = readerViewAppearanceToggle()
.check( .check(
if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist() if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist()
) )
private fun addToFirefoxHomeButton() =
onView(allOf(withText(R.string.browser_menu_add_to_top_sites)))
private fun assertAddToFirefoxHome() {
onView(withId(R.id.mozac_browser_menu_recyclerView))
.perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.browser_menu_add_to_top_sites))
)
).check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}