diff --git a/app/build.gradle b/app/build.gradle index 9e85f7a8b..1a3293f96 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -501,6 +501,7 @@ dependencies { androidTestImplementation Deps.androidx_test_core androidTestImplementation Deps.espresso_idling_resources + androidTestImplementation Deps.espresso_intents androidTestImplementation Deps.tools_test_runner androidTestImplementation Deps.tools_test_rules diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt new file mode 100644 index 000000000..b83e20a72 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt @@ -0,0 +1,8 @@ +package org.mozilla.fenix.helpers + +object Constants { + + object PackageName { + const val GOOGLE_PLAY_SERVICES = "com.android.vending" + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt index bc11ca5dc..9beaf4524 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.helpers +import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.rule.ActivityTestRule import org.mozilla.fenix.HomeActivity @@ -16,3 +17,14 @@ import org.mozilla.fenix.HomeActivity class HomeActivityTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) : ActivityTestRule(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::class.java, initialTouchMode, launchActivity) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt index 94409643c..26368bd0a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt @@ -10,10 +10,10 @@ import okhttp3.mockwebserver.MockWebServer import org.junit.Rule import org.junit.Before import org.junit.After -import org.junit.Ignore import org.junit.Test 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 /** @@ -28,7 +28,7 @@ class SettingsAboutTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityTestRule = HomeActivityTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule() @Before fun setUp() { @@ -58,35 +58,24 @@ class SettingsAboutTest { } // 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 fun verifyRateOnGooglePlayRedirect() { - // Open 3dot (main) menu - // Select settings - // Click on "Rate on Google Play" - // Verify Android "Open with Google Play Store" sub menu + homeScreen { + }.openThreeDotMenu { + }.openSettings { + clickRateButtonGooglePlay() + verifyGooglePlayRedirect() + } + } - @Ignore("This is a stub test, ignore for now") @Test fun verifyAboutFirefoxPreview() { - // Open 3dot (main) menu - // Select settings - // Click on "Verify About Firefox Preview" - // Verify about page contains.... - // Build # - // Version # - // "Firefox Preview is produced by Mozilla" - // Day, Date, timestamp - // "Open source libraries we use" + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openAboutFirefoxPreview { + verifyAboutFirefoxPreview() + } } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index ff8f17b8b..b99c96803 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -32,22 +32,23 @@ class BrowserRobot { .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } - fun verifyHelpUrl() { + fun verifyUrl(redirectUrl: String) { 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)) .check(matches(withText(containsString(redirectUrl)))) } + fun verifyHelpUrl() { + verifyUrl("https://support.mozilla.org/") + } + fun verifyWhatsNewURL() { - 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) - onView(withId(R.id.mozac_browser_toolbar_url_view)) - .check(matches(withText(containsString(redirectUrl)))) + verifyUrl("https://support.mozilla.org/") + } + + fun verifyRateOnGooglePlayURL() { + verifyUrl("https://play.google.com/store/apps/details?id=org.mozilla.fenix") } /* 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)) + fun dismissTrackingOnboarding() { mDevice.wait(Until.findObject(By.res("close_onboarding")), TestAssetHelper.waitingTime) dismissOnboardingButton().click() 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 e2b2d8be1..feda6ba00 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 @@ -15,6 +15,7 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.Until @@ -131,7 +132,6 @@ class HomeScreenRobot { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition { - mDevice.waitForIdle() threeDotButton().perform(click()) ThreeDotMenuMainRobot().interact() @@ -139,7 +139,6 @@ class HomeScreenRobot { } fun openSearch(interact: SearchRobot.() -> Unit): SearchRobot.Transition { - mDevice.waitForIdle() navigationToolbar().perform(click()) SearchRobot().interact() @@ -160,7 +159,6 @@ class HomeScreenRobot { } fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition { - mDevice.waitForIdle() tabsListThreeDotButton().perform(click()) ThreeDotMenuMainRobot().interact() @@ -177,12 +175,12 @@ fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 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 assertNavigationToolbar() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Search or enter address"))) + onView(CoreMatchers.allOf(withText("Search or enter address"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout")) @@ -202,35 +200,34 @@ private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar" .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertOpenTabsHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Open tabs"))) + onView(CoreMatchers.allOf(withText("Open tabs"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) private fun assertNoTabsOpenedHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("No open tabs"))) + onView(CoreMatchers.allOf(withText("No open tabs"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) } private fun assertCollectionsHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Collections"))) + onView(CoreMatchers.allOf(withText("Collections"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertNoCollectionsHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("No collections"))) + onView(CoreMatchers.allOf(withText("No collections"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertNoCollectionsText() = onView( 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))) @@ -238,15 +235,15 @@ private fun assertNoCollectionsText() = private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("home_component")) .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 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))) 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))) private fun assertAccountsSignInButton() = @@ -254,15 +251,15 @@ private fun assertAccountsSignInButton() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) private fun assertChooseThemeHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Choose your theme"))) + onView(CoreMatchers.allOf(withText("Choose your theme"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) private fun assertLightThemeToggle() = @@ -270,7 +267,7 @@ private fun assertLightThemeToggle() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertLightThemeDescription() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Light theme"))) + onView(CoreMatchers.allOf(withText("Light theme"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertDarkThemeToggle() = @@ -278,7 +275,7 @@ private fun assertDarkThemeToggle() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertDarkThemeDescription() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Dark theme"))) + onView(CoreMatchers.allOf(withText("Dark theme"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertAutomaticThemeToggle() = @@ -286,11 +283,11 @@ private fun assertAutomaticThemeToggle() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertAutomaticThemeDescription() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Automatic"))) + onView(CoreMatchers.allOf(withText("Automatic"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertProtectYourselfHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Protect yourself"))) + onView(CoreMatchers.allOf(withText("Protect yourself"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertTrackingProtectionToggle() = onView( @@ -301,7 +298,7 @@ private fun assertTrackingProtectionToggle() = onView( private fun assertProtectYourselfText() { onView( CoreMatchers.allOf( - ViewMatchers.withText( + withText( "Firefox Preview blocks ad trackers that follow you around the web." ) ) @@ -310,33 +307,33 @@ private fun assertProtectYourselfText() { } private fun assertBrowsePrivatelyHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Browse privately"))) + onView(CoreMatchers.allOf(withText("Browse privately"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) private fun assertYourPrivacyHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Your privacy"))) + onView(CoreMatchers.allOf(withText("Your privacy"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertYourPrivacyText() = - onView(CoreMatchers.allOf(ViewMatchers.withText( + onView(CoreMatchers.allOf(withText( "We’ve designed Firefox Preview to give you control over what you share online and what you share with us."))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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))) private fun assertStartBrowsingButton() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Start browsing"))) + onView(CoreMatchers.allOf(withText("Start browsing"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) // Private mode elements private fun assertPrivateSessionHeader() = - onView(CoreMatchers.allOf(ViewMatchers.withText("Private tabs"))) + onView(CoreMatchers.allOf(withText("Private tabs"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 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." private fun assertPrivateSessionMessage(visible: Boolean) = - onView(CoreMatchers.allOf(ViewMatchers.withText(PRIVATE_SESSION_MESSAGE))) + onView(CoreMatchers.allOf(withText(PRIVATE_SESSION_MESSAGE))) .check( if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist() ) 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)))) 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)))) private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE 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))) -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"))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt index be1c5ecff..fe123f8a5 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt @@ -6,11 +6,15 @@ package org.mozilla.fenix.ui.robots +import android.content.pm.PackageManager import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.ViewInteraction 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.Visibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility @@ -20,6 +24,7 @@ import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers 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.TestHelper import org.mozilla.fenix.helpers.click @@ -64,21 +69,31 @@ class SettingsRobot { fun verifyRateOnGooglePlay() = assertRateOnGooglePlay() fun verifyAboutFirefoxPreview() = assertAboutFirefoxPreview() + fun verifyGooglePlayRedirect() = assertGooglePlayRedirect() class Transition { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { - mDevice.waitForIdle() - goBackButton().perform(ViewActions.click()) + goBackButton().click() HomeScreenRobot().interact() return HomeScreenRobot.Transition() } - fun openSearchSubMenu(interact: SettingsSubMenuSearchRobot.() -> Unit): SettingsSubMenuSearchRobot.Transition { - mDevice.waitForIdle() + fun openAboutFirefoxPreview(interact: SettingsSubMenuAboutRobot.() -> Unit): + SettingsSubMenuAboutRobot.Transition { + + assertAboutFirefoxPreview().click() + + SettingsSubMenuAboutRobot().interact() + return SettingsSubMenuAboutRobot.Transition() + } + + fun openSearchSubMenu(interact: SettingsSubMenuSearchRobot.() -> Unit): + SettingsSubMenuSearchRobot.Transition { + fun searchEngineButton() = onView(ViewMatchers.withText("Search")) searchEngineButton().click() @@ -87,7 +102,7 @@ class SettingsRobot { } fun openThemeSubMenu(interact: SettingsSubMenuThemeRobot.() -> Unit): SettingsSubMenuThemeRobot.Transition { - mDevice.waitForIdle() + fun themeButton() = onView(ViewMatchers.withText("Theme")) themeButton().click() @@ -96,7 +111,7 @@ class SettingsRobot { } fun openAccessibilitySubMenu(interact: SettingsSubMenuAccessibilityRobot.() -> Unit): SettingsSubMenuAccessibilityRobot.Transition { - mDevice.waitForIdle() + fun accessibilityButton() = onView(ViewMatchers.withText("Accessibility")) accessibilityButton().click() @@ -105,7 +120,7 @@ class SettingsRobot { } fun openDefaultBrowserSubMenu(interact: SettingsSubMenuDefaultBrowserRobot.() -> Unit): SettingsSubMenuDefaultBrowserRobot.Transition { - mDevice.waitForIdle() + fun defaultBrowserButton() = onView(ViewMatchers.withText("Set as default browser")) defaultBrowserButton().click() @@ -114,8 +129,8 @@ class SettingsRobot { } fun openEnhancedTrackingProtectionSubMenu(interact: SettingsSubMenuEnhancedTrackingProtectionRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionRobot.Transition { - mDevice.waitForIdle() - fun enhancedTrackingProtectionButton() = onView(ViewMatchers.withText("Enhanced Tracking Protection")) + fun enhancedTrackingProtectionButton() = + onView(ViewMatchers.withText("Enhanced Tracking Protection")) enhancedTrackingProtectionButton().click() SettingsSubMenuEnhancedTrackingProtectionRobot().interact() @@ -231,24 +246,46 @@ private fun assertRemoteDebug() { } // ABOUT SECTION -private fun assertAboutHeading() { +private fun assertAboutHeading(): ViewInteraction { TestHelper.scrollToElementByText("About") - onView(ViewMatchers.withText("About")) + return onView(ViewMatchers.withText("About")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertRateOnGooglePlay() { +private fun assertRateOnGooglePlay(): ViewInteraction { 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))) } -private fun assertAboutFirefoxPreview() { +private fun assertAboutFirefoxPreview(): ViewInteraction { TestHelper.scrollToElementByText("About Firefox Preview") - onView(ViewMatchers.withText("About Firefox Preview")) + return onView(ViewMatchers.withText("About Firefox Preview")) .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 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"))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt index 5076c048b..4a55098cc 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt @@ -6,24 +6,35 @@ package org.mozilla.fenix.ui.robots -import androidx.test.espresso.Espresso -import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.matcher.ViewMatchers +import androidx.core.content.pm.PackageInfoCompat +import androidx.test.espresso.Espresso.onView import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice 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. */ class SettingsSubMenuAboutRobot { + fun verifyAboutFirefoxPreview() = assertFirefoxPreviewPage() + 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() @@ -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("What’s 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() = - Espresso.onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) + onView(CoreMatchers.allOf(withContentDescription("Navigate up"))) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index ed6c77418..e5b7750f2 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -206,6 +206,7 @@ object Deps { 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_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 orchestrator = "androidx.test:orchestrator:${Versions.orchestrator}" const val tools_test_rules = "androidx.test:rules:${Versions.tools_test_rules}"