1
0
Fork 0

Added UI tests for the About Settings page (#6161)

master
Kadeem M 2019-12-27 10:55:35 -05:00 committed by Richard Pappalardo
parent 491a198fae
commit e22d092f5d
9 changed files with 229 additions and 97 deletions

View File

@ -501,6 +501,7 @@ dependencies {
androidTestImplementation Deps.androidx_test_core androidTestImplementation Deps.androidx_test_core
androidTestImplementation Deps.espresso_idling_resources androidTestImplementation Deps.espresso_idling_resources
androidTestImplementation Deps.espresso_intents
androidTestImplementation Deps.tools_test_runner androidTestImplementation Deps.tools_test_runner
androidTestImplementation Deps.tools_test_rules androidTestImplementation Deps.tools_test_rules

View File

@ -0,0 +1,8 @@
package org.mozilla.fenix.helpers
object Constants {
object PackageName {
const val GOOGLE_PLAY_SERVICES = "com.android.vending"
}
}

View File

@ -4,6 +4,7 @@
package org.mozilla.fenix.helpers package org.mozilla.fenix.helpers
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.rule.ActivityTestRule import androidx.test.rule.ActivityTestRule
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
@ -16,3 +17,14 @@ import org.mozilla.fenix.HomeActivity
class HomeActivityTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) : class HomeActivityTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) :
ActivityTestRule<HomeActivity>(HomeActivity::class.java, initialTouchMode, launchActivity) ActivityTestRule<HomeActivity>(HomeActivity::class.java, initialTouchMode, launchActivity)
/**
* A [org.junit.Rule] to handle shared test set up for tests on [HomeActivity]. This adds
* functionality for using the Espresso-intents api, and extends from ActivityTestRule.
*
* @param initialTouchMode See [IntentsTestRule]
* @param launchActivity See [IntentsTestRule]
*/
class HomeActivityIntentTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) :
IntentsTestRule<HomeActivity>(HomeActivity::class.java, initialTouchMode, launchActivity)

View File

@ -10,10 +10,10 @@ import okhttp3.mockwebserver.MockWebServer
import org.junit.Rule import org.junit.Rule
import org.junit.Before import org.junit.Before
import org.junit.After import org.junit.After
import org.junit.Ignore
import org.junit.Test import org.junit.Test
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.ui.robots.clickRateButtonGooglePlay
import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.homeScreen
/** /**
@ -28,7 +28,7 @@ class SettingsAboutTest {
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() {
@ -58,35 +58,24 @@ class SettingsAboutTest {
} }
// ABOUT // ABOUT
@Ignore("This is a stub test, ignore for now")
@Test
fun verifyHelpRedirect() {
// Open 3dot (main) menu
// Select settings
// Click on "Help"
// Verify redirect to: https://support.mozilla.org/
}
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun verifyRateOnGooglePlayRedirect() { fun verifyRateOnGooglePlayRedirect() {
// Open 3dot (main) menu homeScreen {
// Select settings }.openThreeDotMenu {
// Click on "Rate on Google Play" }.openSettings {
// Verify Android "Open with Google Play Store" sub menu clickRateButtonGooglePlay()
verifyGooglePlayRedirect()
}
} }
@Ignore("This is a stub test, ignore for now")
@Test @Test
fun verifyAboutFirefoxPreview() { fun verifyAboutFirefoxPreview() {
// Open 3dot (main) menu homeScreen {
// Select settings }.openThreeDotMenu {
// Click on "Verify About Firefox Preview" }.openSettings {
// Verify about page contains.... }.openAboutFirefoxPreview {
// Build # verifyAboutFirefoxPreview()
// Version # }
// "Firefox Preview is produced by Mozilla"
// Day, Date, timestamp
// "Open source libraries we use"
} }
} }

View File

@ -32,22 +32,23 @@ class BrowserRobot {
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }
fun verifyHelpUrl() { fun verifyUrl(redirectUrl: String) {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val redirectUrl = "https://support.mozilla.org/" mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view")), TestAssetHelper.waitingTime)
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view")),
TestAssetHelper.waitingTime)
onView(withId(R.id.mozac_browser_toolbar_url_view)) onView(withId(R.id.mozac_browser_toolbar_url_view))
.check(matches(withText(containsString(redirectUrl)))) .check(matches(withText(containsString(redirectUrl))))
} }
fun verifyHelpUrl() {
verifyUrl("https://support.mozilla.org/")
}
fun verifyWhatsNewURL() { fun verifyWhatsNewURL() {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) verifyUrl("https://support.mozilla.org/")
val redirectUrl = "https://support.mozilla.org/" }
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view")),
TestAssetHelper.waitingTime) fun verifyRateOnGooglePlayURL() {
onView(withId(R.id.mozac_browser_toolbar_url_view)) verifyUrl("https://play.google.com/store/apps/details?id=org.mozilla.fenix")
.check(matches(withText(containsString(redirectUrl))))
} }
/* Asserts that the text within DOM element with ID="testContent" has the given text, i.e. /* Asserts that the text within DOM element with ID="testContent" has the given text, i.e.
@ -132,6 +133,7 @@ fun browserScreen(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
} }
private fun dismissOnboardingButton() = onView(withId(R.id.close_onboarding)) private fun dismissOnboardingButton() = onView(withId(R.id.close_onboarding))
fun dismissTrackingOnboarding() { fun dismissTrackingOnboarding() {
mDevice.wait(Until.findObject(By.res("close_onboarding")), TestAssetHelper.waitingTime) mDevice.wait(Until.findObject(By.res("close_onboarding")), TestAssetHelper.waitingTime)
dismissOnboardingButton().click() dismissOnboardingButton().click()

View File

@ -15,6 +15,7 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.Visibility
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.withText
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
@ -131,7 +132,6 @@ class HomeScreenRobot {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition { fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
mDevice.waitForIdle()
threeDotButton().perform(click()) threeDotButton().perform(click())
ThreeDotMenuMainRobot().interact() ThreeDotMenuMainRobot().interact()
@ -139,7 +139,6 @@ class HomeScreenRobot {
} }
fun openSearch(interact: SearchRobot.() -> Unit): SearchRobot.Transition { fun openSearch(interact: SearchRobot.() -> Unit): SearchRobot.Transition {
mDevice.waitForIdle()
navigationToolbar().perform(click()) navigationToolbar().perform(click())
SearchRobot().interact() SearchRobot().interact()
@ -160,7 +159,6 @@ class HomeScreenRobot {
} }
fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition { fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
mDevice.waitForIdle()
tabsListThreeDotButton().perform(click()) tabsListThreeDotButton().perform(click())
ThreeDotMenuMainRobot().interact() ThreeDotMenuMainRobot().interact()
@ -177,12 +175,12 @@ fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private fun navigationToolbar() = private fun navigationToolbar() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Search or enter address"))) onView(CoreMatchers.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(ViewMatchers.withText("Search or enter address"))) onView(CoreMatchers.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"))
@ -202,35 +200,34 @@ 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(ViewMatchers.withText("Open tabs"))) onView(CoreMatchers.allOf(withText("Open tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAddTabButton() = private fun assertAddTabButton() =
onView(CoreMatchers.allOf(ViewMatchers.withId(R.id.add_tab_button), isDisplayed())) onView(CoreMatchers.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(ViewMatchers.withText("No open tabs"))) onView(CoreMatchers.allOf(withText("No open tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoTabsOpenedText() { private fun assertNoTabsOpenedText() {
onView(CoreMatchers.allOf(ViewMatchers.withText("Your open tabs will be shown here."))) onView(CoreMatchers.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(ViewMatchers.withText("Collections"))) onView(CoreMatchers.allOf(withText("Collections")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoCollectionsHeader() = private fun assertNoCollectionsHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("No collections"))) onView(CoreMatchers.allOf(withText("No collections")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoCollectionsText() = private fun assertNoCollectionsText() =
onView( onView(
CoreMatchers.allOf( CoreMatchers.allOf(
ViewMatchers 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.")
) )
) )
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
@ -238,15 +235,15 @@ private fun assertNoCollectionsText() =
private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("home_component")) private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("home_component"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun threeDotButton() = onView(allOf(ViewMatchers.withId(R.id.menuButton))) private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
// First Run elements // First Run elements
private fun assertWelcomeHeader() = private fun assertWelcomeHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Welcome to Firefox Preview!"))) onView(CoreMatchers.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(ViewMatchers.withText("Get the most out of Firefox Preview."))) onView(CoreMatchers.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() =
@ -254,15 +251,15 @@ private fun assertAccountsSignInButton() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertGetToKnowHeader() = private fun assertGetToKnowHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Get to know Firefox Preview"))) onView(CoreMatchers.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(ViewMatchers.withText("Choose your theme"))) onView(CoreMatchers.allOf(withText("Choose your theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertChooseThemeText() = private fun assertChooseThemeText() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Try dark theme: easier on your battery and your eyes."))) onView(CoreMatchers.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() =
@ -270,7 +267,7 @@ private fun assertLightThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertLightThemeDescription() = private fun assertLightThemeDescription() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Light theme"))) onView(CoreMatchers.allOf(withText("Light theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertDarkThemeToggle() = private fun assertDarkThemeToggle() =
@ -278,7 +275,7 @@ private fun assertDarkThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertDarkThemeDescription() = private fun assertDarkThemeDescription() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Dark theme"))) onView(CoreMatchers.allOf(withText("Dark theme")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAutomaticThemeToggle() = private fun assertAutomaticThemeToggle() =
@ -286,11 +283,11 @@ private fun assertAutomaticThemeToggle() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAutomaticThemeDescription() = private fun assertAutomaticThemeDescription() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Automatic"))) onView(CoreMatchers.allOf(withText("Automatic")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertProtectYourselfHeader() = private fun assertProtectYourselfHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Protect yourself"))) onView(CoreMatchers.allOf(withText("Protect yourself")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertTrackingProtectionToggle() = onView( private fun assertTrackingProtectionToggle() = onView(
@ -301,7 +298,7 @@ private fun assertTrackingProtectionToggle() = onView(
private fun assertProtectYourselfText() { private fun assertProtectYourselfText() {
onView( onView(
CoreMatchers.allOf( CoreMatchers.allOf(
ViewMatchers.withText( withText(
"Firefox Preview blocks ad trackers that follow you around the web." "Firefox Preview blocks ad trackers that follow you around the web."
) )
) )
@ -310,33 +307,33 @@ private fun assertProtectYourselfText() {
} }
private fun assertBrowsePrivatelyHeader() = private fun assertBrowsePrivatelyHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Browse privately"))) onView(CoreMatchers.allOf(withText("Browse privately")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertBrowsePrivatelyText() = private fun assertBrowsePrivatelyText() =
onView(CoreMatchers.allOf(ViewMatchers.withText(containsString("private browsing is just a tap away.")))) onView(CoreMatchers.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(ViewMatchers.withText("Your privacy"))) onView(CoreMatchers.allOf(withText("Your privacy")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertYourPrivacyText() = private fun assertYourPrivacyText() =
onView(CoreMatchers.allOf(ViewMatchers.withText( onView(CoreMatchers.allOf(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.")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertPrivacyNoticeButton() = private fun assertPrivacyNoticeButton() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Read our privacy notice"))) onView(CoreMatchers.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(ViewMatchers.withText("Start browsing"))) onView(CoreMatchers.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(ViewMatchers.withText("Private tabs"))) onView(CoreMatchers.allOf(withText("Private tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(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 " +
@ -345,27 +342,27 @@ 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(ViewMatchers.withText(PRIVATE_SESSION_MESSAGE))) onView(CoreMatchers.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(ViewMatchers.withId(R.id.share_tabs_button), isDisplayed())) onView(CoreMatchers.allOf(withId(R.id.share_tabs_button), isDisplayed()))
.check(matches(withEffectiveVisibility(visibleOrGone(visible)))) .check(matches(withEffectiveVisibility(visibleOrGone(visible))))
private fun assertCloseTabsButton(visible: Boolean) = private fun assertCloseTabsButton(visible: Boolean) =
onView(CoreMatchers.allOf(ViewMatchers.withId(R.id.close_tab_button), isDisplayed())) onView(CoreMatchers.allOf(withId(R.id.close_tab_button), isDisplayed()))
.check(matches(withEffectiveVisibility(visibleOrGone(visible)))) .check(matches(withEffectiveVisibility(visibleOrGone(visible))))
private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE
private fun assertExistingTabList() = private fun assertExistingTabList() =
onView(CoreMatchers.allOf(ViewMatchers.withId(R.id.item_tab))) onView(CoreMatchers.allOf(withId(R.id.item_tab)))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun tabsListThreeDotButton() = onView(allOf(ViewMatchers.withId(R.id.tabs_overflow_button))) private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button)))
private fun collectionThreeDotButton() = onView(allOf(ViewMatchers.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"))) private fun collectionNameTextField() = onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))

View File

@ -6,11 +6,15 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import android.content.pm.PackageManager
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
import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
@ -20,6 +24,7 @@ import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.Constants.PackageName.GOOGLE_PLAY_SERVICES
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper
import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.click
@ -64,21 +69,31 @@ class SettingsRobot {
fun verifyRateOnGooglePlay() = assertRateOnGooglePlay() fun verifyRateOnGooglePlay() = assertRateOnGooglePlay()
fun verifyAboutFirefoxPreview() = assertAboutFirefoxPreview() fun verifyAboutFirefoxPreview() = assertAboutFirefoxPreview()
fun verifyGooglePlayRedirect() = assertGooglePlayRedirect()
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle() goBackButton().click()
goBackButton().perform(ViewActions.click())
HomeScreenRobot().interact() HomeScreenRobot().interact()
return HomeScreenRobot.Transition() return HomeScreenRobot.Transition()
} }
fun openSearchSubMenu(interact: SettingsSubMenuSearchRobot.() -> Unit): SettingsSubMenuSearchRobot.Transition { fun openAboutFirefoxPreview(interact: SettingsSubMenuAboutRobot.() -> Unit):
mDevice.waitForIdle() SettingsSubMenuAboutRobot.Transition {
assertAboutFirefoxPreview().click()
SettingsSubMenuAboutRobot().interact()
return SettingsSubMenuAboutRobot.Transition()
}
fun openSearchSubMenu(interact: SettingsSubMenuSearchRobot.() -> Unit):
SettingsSubMenuSearchRobot.Transition {
fun searchEngineButton() = onView(ViewMatchers.withText("Search")) fun searchEngineButton() = onView(ViewMatchers.withText("Search"))
searchEngineButton().click() searchEngineButton().click()
@ -87,7 +102,7 @@ class SettingsRobot {
} }
fun openThemeSubMenu(interact: SettingsSubMenuThemeRobot.() -> Unit): SettingsSubMenuThemeRobot.Transition { fun openThemeSubMenu(interact: SettingsSubMenuThemeRobot.() -> Unit): SettingsSubMenuThemeRobot.Transition {
mDevice.waitForIdle()
fun themeButton() = onView(ViewMatchers.withText("Theme")) fun themeButton() = onView(ViewMatchers.withText("Theme"))
themeButton().click() themeButton().click()
@ -96,7 +111,7 @@ class SettingsRobot {
} }
fun openAccessibilitySubMenu(interact: SettingsSubMenuAccessibilityRobot.() -> Unit): SettingsSubMenuAccessibilityRobot.Transition { fun openAccessibilitySubMenu(interact: SettingsSubMenuAccessibilityRobot.() -> Unit): SettingsSubMenuAccessibilityRobot.Transition {
mDevice.waitForIdle()
fun accessibilityButton() = onView(ViewMatchers.withText("Accessibility")) fun accessibilityButton() = onView(ViewMatchers.withText("Accessibility"))
accessibilityButton().click() accessibilityButton().click()
@ -105,7 +120,7 @@ class SettingsRobot {
} }
fun openDefaultBrowserSubMenu(interact: SettingsSubMenuDefaultBrowserRobot.() -> Unit): SettingsSubMenuDefaultBrowserRobot.Transition { fun openDefaultBrowserSubMenu(interact: SettingsSubMenuDefaultBrowserRobot.() -> Unit): SettingsSubMenuDefaultBrowserRobot.Transition {
mDevice.waitForIdle()
fun defaultBrowserButton() = onView(ViewMatchers.withText("Set as default browser")) fun defaultBrowserButton() = onView(ViewMatchers.withText("Set as default browser"))
defaultBrowserButton().click() defaultBrowserButton().click()
@ -114,8 +129,8 @@ class SettingsRobot {
} }
fun openEnhancedTrackingProtectionSubMenu(interact: SettingsSubMenuEnhancedTrackingProtectionRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionRobot.Transition { fun openEnhancedTrackingProtectionSubMenu(interact: SettingsSubMenuEnhancedTrackingProtectionRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionRobot.Transition {
mDevice.waitForIdle() fun enhancedTrackingProtectionButton() =
fun enhancedTrackingProtectionButton() = onView(ViewMatchers.withText("Enhanced Tracking Protection")) onView(ViewMatchers.withText("Enhanced Tracking Protection"))
enhancedTrackingProtectionButton().click() enhancedTrackingProtectionButton().click()
SettingsSubMenuEnhancedTrackingProtectionRobot().interact() SettingsSubMenuEnhancedTrackingProtectionRobot().interact()
@ -231,24 +246,46 @@ private fun assertRemoteDebug() {
} }
// ABOUT SECTION // ABOUT SECTION
private fun assertAboutHeading() { private fun assertAboutHeading(): ViewInteraction {
TestHelper.scrollToElementByText("About") TestHelper.scrollToElementByText("About")
onView(ViewMatchers.withText("About")) return onView(ViewMatchers.withText("About"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertRateOnGooglePlay() { private fun assertRateOnGooglePlay(): ViewInteraction {
TestHelper.scrollToElementByText("About Firefox Preview") TestHelper.scrollToElementByText("About Firefox Preview")
onView(ViewMatchers.withText("Rate on Google Play")) return onView(ViewMatchers.withText("Rate on Google Play"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun assertAboutFirefoxPreview() { private fun assertAboutFirefoxPreview(): ViewInteraction {
TestHelper.scrollToElementByText("About Firefox Preview") TestHelper.scrollToElementByText("About Firefox Preview")
onView(ViewMatchers.withText("About Firefox Preview")) return onView(ViewMatchers.withText("About Firefox Preview"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun goBackButton() = onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
fun swipeToBottom() = onView(ViewMatchers.withId(R.id.recycler_view)).perform(ViewActions.swipeUp()) fun swipeToBottom() = onView(ViewMatchers.withId(R.id.recycler_view)).perform(ViewActions.swipeUp())
fun clickRateButtonGooglePlay() {
assertRateOnGooglePlay().click()
}
private fun assertGooglePlayRedirect() {
if (isPackageInstalled(GOOGLE_PLAY_SERVICES)) {
intended(toPackage(GOOGLE_PLAY_SERVICES))
} else {
BrowserRobot().verifyRateOnGooglePlayURL()
}
}
fun isPackageInstalled(packageName: String): Boolean {
return try {
val packageManager = InstrumentationRegistry.getInstrumentation().context.packageManager
packageManager.getApplicationInfo(packageName, 0).enabled
} catch (exception: PackageManager.NameNotFoundException) {
false
}
}
private fun goBackButton() =
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))

View File

@ -6,24 +6,35 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso import androidx.core.content.pm.PackageInfoCompat
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.Espresso.onView
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 org.hamcrest.CoreMatchers
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import org.hamcrest.CoreMatchers.containsString
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestHelper
/** /**
* Implementation of Robot Pattern for the settings search sub menu. * Implementation of Robot Pattern for the settings search sub menu.
*/ */
class SettingsSubMenuAboutRobot { class SettingsSubMenuAboutRobot {
fun verifyAboutFirefoxPreview() = assertFirefoxPreviewPage()
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() goBackButton().perform(click())
goBackButton().perform(ViewActions.click())
SettingsRobot().interact() SettingsRobot().interact()
return SettingsRobot.Transition() return SettingsRobot.Transition()
@ -31,5 +42,79 @@ class SettingsSubMenuAboutRobot {
} }
} }
private fun assertFirefoxPreviewPage() {
assertVersionNumber()
assertProductCompany()
assertCurrentTimestamp()
assertWhatIsNewInFirefoxPreview()
assertSupport()
assertPrivacyNotice()
assertKnowYourRights()
assertLicensingInformation()
assertLibrariesUsed()
}
private fun assertVersionNumber() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val versionCode = PackageInfoCompat.getLongVersionCode(packageInfo).toString()
val buildNVersion = "${packageInfo.versionName} (Build #$versionCode)\n"
val componentsVersion =
"${mozilla.components.Build.version}, ${mozilla.components.Build.gitHash}"
val geckoVersion =
org.mozilla.geckoview.BuildConfig.MOZ_APP_VERSION + "-" + org.mozilla.geckoview.BuildConfig.MOZ_APP_BUILDID
onView(withId(R.id.about_text))
.check(matches(withText(containsString(buildNVersion))))
.check(matches(withText(containsString(componentsVersion))))
.check(matches(withText(containsString(geckoVersion))))
}
private fun assertProductCompany() {
onView(withId(R.id.about_content))
.check(matches(withText(containsString("Firefox Preview is produced by Mozilla."))))
}
private fun assertCurrentTimestamp() {
onView(withId(R.id.build_date))
.check(matches(withText(org.mozilla.fenix.BuildConfig.BUILD_DATE)))
}
private fun assertWhatIsNewInFirefoxPreview() {
onView(withText("Whats new in Firefox Preview"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertSupport() {
onView(withText("Support"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertPrivacyNotice() {
onView(withText("Privacy notice"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertKnowYourRights() {
onView(withText("Know your rights"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertLicensingInformation() {
onView(withText("Licensing information"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
private fun assertLibrariesUsed() {
TestHelper.scrollToElementByText("Libraries that we use")
onView(withText("Libraries that we use"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.perform(click())
onView(withId(R.id.action_bar)).check(matches(hasDescendant(withText(containsString("Firefox Preview | OSS Libraries")))))
}
private fun goBackButton() = private fun goBackButton() =
Espresso.onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) onView(CoreMatchers.allOf(withContentDescription("Navigate up")))

View File

@ -206,6 +206,7 @@ object Deps {
const val espresso_contrib = "androidx.test.espresso:espresso-contrib:${Versions.espresso_version}" const val espresso_contrib = "androidx.test.espresso:espresso-contrib:${Versions.espresso_version}"
const val espresso_core = "androidx.test.espresso:espresso-core:${Versions.espresso_version}" const val espresso_core = "androidx.test.espresso:espresso-core:${Versions.espresso_version}"
const val espresso_idling_resources = "androidx.test.espresso:espresso-idling-resource:${Versions.espresso_version}" const val espresso_idling_resources = "androidx.test.espresso:espresso-idling-resource:${Versions.espresso_version}"
const val espresso_intents = "androidx.test.espresso:espresso-intents:${Versions.espresso_version}"
const val mockwebserver = "com.squareup.okhttp3:mockwebserver:${Versions.mockwebserver}" const val mockwebserver = "com.squareup.okhttp3:mockwebserver:${Versions.mockwebserver}"
const val orchestrator = "androidx.test:orchestrator:${Versions.orchestrator}" const val orchestrator = "androidx.test:orchestrator:${Versions.orchestrator}"
const val tools_test_rules = "androidx.test:rules:${Versions.tools_test_rules}" const val tools_test_rules = "androidx.test:rules:${Versions.tools_test_rules}"