diff --git a/app/build.gradle b/app/build.gradle index b0af372af..3bdb10eaa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -586,6 +586,7 @@ dependencies { exclude module: 'recyclerview-v7' exclude module: 'design' exclude module: 'espresso-core' + exclude module: 'protobuf-lite' } androidTestImplementation Deps.androidx_test_core @@ -600,12 +601,14 @@ dependencies { } androidTestImplementation Deps.androidx_junit + androidTestImplementation Deps.androidx_test_extensions androidTestImplementation Deps.androidx_work_testing androidTestImplementation Deps.androidx_benchmark_junit4 androidTestImplementation Deps.mockwebserver testImplementation Deps.mozilla_support_test testImplementation Deps.mozilla_support_test_libstate testImplementation Deps.androidx_junit + testImplementation Deps.androidx_test_extensions testImplementation Deps.androidx_work_testing testImplementation (Deps.robolectric) { exclude group: 'org.apache.maven' diff --git a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt index 8d4a76464..a3c1bfd12 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.glean import android.content.Context diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt index ee8809a34..46eee06fe 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt @@ -6,12 +6,14 @@ package org.mozilla.fenix.helpers object Constants { + // Device or AVD requires a Google Services Android OS installation object PackageName { const val GOOGLE_PLAY_SERVICES = "com.android.vending" const val GOOGLE_APPS_PHOTOS = "com.google.android.apps.photos" + const val GOOGLE_QUICK_SEARCH = "com.google.android.googlequicksearchbox" const val YOUTUBE_APP = "com.google.android.youtube" const val GMAIL_APP = "com.google.android.gm" - const val PHONE_APP = "com.google.android.dialer" + const val PHONE_APP = "com.android.dialer" } const val LONG_CLICK_DURATION: Long = 5000 diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt index d02f5114b..2246a469f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt @@ -38,6 +38,10 @@ class FeatureSettingsHelper { settings.userKnowsAboutPwas = disable } + fun deleteSitePermissions(delete: Boolean) { + settings.deleteSitePermissions = delete + } + // Important: // Use this after each test if you have modified these feature settings // to make sure the app goes back to the default state 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 051dd9680..4aec025b3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.helpers import android.view.ViewConfiguration.getLongPressTimeout diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/IdlingResourceHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/IdlingResourceHelper.kt index 861ec21c9..e5cb37495 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/IdlingResourceHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/IdlingResourceHelper.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.helpers import androidx.test.espresso.IdlingRegistry diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/RetryTestRule.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/RetryTestRule.kt index c558be48f..cf37569a6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/RetryTestRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/RetryTestRule.kt @@ -4,14 +4,18 @@ package org.mozilla.fenix.helpers +import androidx.test.espresso.IdlingResourceTimeoutException +import androidx.test.espresso.NoMatchingViewException import androidx.test.uiautomator.UiObjectNotFoundException import junit.framework.AssertionFailedError import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +import java.lang.AssertionError class RetryTestRule(private val retryCount: Int = 5) : TestRule { + @Suppress("TooGenericExceptionCaught", "ComplexMethod") override fun apply(base: Statement, description: Description): Statement { return statement { for (i in 1..retryCount) { @@ -30,6 +34,22 @@ class RetryTestRule(private val retryCount: Int = 5) : TestRule { if (i == retryCount) { throw t } + } catch (t: NoMatchingViewException) { + if (i == retryCount) { + throw t + } + } catch (t: IdlingResourceTimeoutException) { + if (i == retryCount) { + throw t + } + } catch (t: RuntimeException) { + if (i == retryCount) { + throw t + } + } catch (t: NullPointerException) { + if (i == retryCount) { + throw t + } } } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt index c662908bb..1eb054615 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt @@ -14,7 +14,6 @@ import android.graphics.Canvas import android.graphics.Color import android.net.Uri import android.os.Build -import android.os.Environment import android.view.View import androidx.browser.customtabs.CustomTabsIntent import androidx.test.espresso.Espresso @@ -22,9 +21,7 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions.longClick import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents.intended -import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.withChild @@ -35,11 +32,11 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject +import androidx.test.uiautomator.UiObjectNotFoundException import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until -import java.io.File -import kotlinx.coroutines.runBlocking +import junit.framework.AssertionFailedError import mozilla.components.browser.state.search.SearchEngine import mozilla.components.support.ktx.android.content.appName import org.hamcrest.CoreMatchers @@ -48,6 +45,7 @@ import org.hamcrest.Matcher import org.junit.Assert import org.mozilla.fenix.R import org.mozilla.fenix.ext.components +import org.mozilla.fenix.helpers.Constants.PackageName.GOOGLE_APPS_PHOTOS import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.ext.waitNotNull @@ -55,6 +53,7 @@ import org.mozilla.fenix.helpers.idlingresource.NetworkConnectionIdlingResource import org.mozilla.fenix.ui.robots.BrowserRobot import org.mozilla.fenix.ui.robots.mDevice import org.mozilla.fenix.utils.IntentUtils +import java.util.regex.Pattern object TestHelper { @@ -72,7 +71,7 @@ object TestHelper { fun longTapSelectItem(url: Uri) { mDevice.waitNotNull( Until.findObject(By.text(url.toString())), - TestAssetHelper.waitingTime + waitingTime ) onView( allOf( @@ -101,7 +100,7 @@ object TestHelper { fun waitUntilObjectIsFound(resourceName: String) { mDevice.waitNotNull( Until.findObjects(By.res(resourceName)), - TestAssetHelper.waitingTime + waitingTime ) } @@ -127,19 +126,21 @@ object TestHelper { } } - // Remove test file from the device Downloads folder - @Suppress("Deprecation") - fun deleteDownloadFromStorage(fileName: String) { - runBlocking { - val downloadedFile = File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), - fileName - ) + // Remove test file from Google Photos (AOSP) on Firebase + fun deleteDownloadFromStorage() { + val deleteButton = mDevice.findObject(UiSelector().resourceId("$GOOGLE_APPS_PHOTOS:id/trash")) + deleteButton.click() - if (downloadedFile.exists()) { - downloadedFile.delete() - } + // Sometimes there's a secondary confirmation + try { + val deleteConfirm = mDevice.findObject(UiSelector().text("Got it")) + deleteConfirm.click() + } catch (e: UiObjectNotFoundException) { + // Do nothing } + + val trashIt = mDevice.findObject(UiSelector().resourceId("$GOOGLE_APPS_PHOTOS:id/move_to_trash")) + trashIt.click() } fun setNetworkEnabled(enabled: Boolean) { @@ -211,7 +212,11 @@ object TestHelper { fun assertExternalAppOpens(appPackageName: String) { if (isPackageInstalled(appPackageName)) { - Intents.intended(IntentMatchers.toPackage(appPackageName)) + try { + intended(toPackage(appPackageName)) + } catch (e: AssertionFailedError) { + e.printStackTrace() + } } else { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mDevice.waitNotNull( @@ -223,7 +228,11 @@ object TestHelper { fun assertNativeAppOpens(appPackageName: String, url: String) { if (isPackageInstalled(appPackageName)) { - intended(toPackage(appPackageName)) + try { + intended(toPackage(appPackageName)) + } catch (e: AssertionFailedError) { + e.printStackTrace() + } } else { BrowserRobot().verifyUrl(url) } @@ -261,4 +270,36 @@ object TestHelper { selectSearchEngine(searchEngine) } } + + fun grantPermission() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + if (Build.VERSION.SDK_INT >= 23) { + UiDevice.getInstance(instrumentation).findObject( + By.text( + when (Build.VERSION.SDK_INT) { + Build.VERSION_CODES.R -> Pattern.compile( + "WHILE USING THE APP", Pattern.CASE_INSENSITIVE + ) + else -> Pattern.compile("Allow", Pattern.CASE_INSENSITIVE) + } + ) + ).click() + } + } + + fun denyPermission() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + if (Build.VERSION.SDK_INT >= 23) { + UiDevice.getInstance(instrumentation).findObject( + By.text( + when (Build.VERSION.SDK_INT) { + Build.VERSION_CODES.R -> Pattern.compile( + "DENY", Pattern.CASE_INSENSITIVE + ) + else -> Pattern.compile("Deny", Pattern.CASE_INSENSITIVE) + } + ) + ).click() + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt index abedf0eaf..bfd3f370f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.screenshots import android.os.SystemClock diff --git a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt index 3f67dc7e6..285080915 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.screenshots import android.os.SystemClock diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt index a522f27e8..b607b1e27 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt @@ -21,6 +21,7 @@ import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource +import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper.longTapSelectItem import org.mozilla.fenix.ui.robots.bookmarksMenu @@ -47,6 +48,10 @@ class BookmarksTest { @get:Rule val activityTestRule = HomeActivityTestRule() + @Rule + @JvmField + val retryTestRule = RetryTestRule(3) + @Before fun setUp() { mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt index 1ca1b9022..5ed29f663 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt @@ -16,6 +16,7 @@ import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.ui.robots.downloadRobot import org.mozilla.fenix.ui.robots.homeScreen @@ -42,6 +43,10 @@ class ContextMenusTest { @get:Rule val activityIntentTestRule = HomeActivityIntentTestRule() + @Rule + @JvmField + val retryTestRule = RetryTestRule(3) + @Before fun setUp() { activityIntentTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false @@ -194,7 +199,6 @@ class ContextMenusTest { } downloadRobot { - }.clickAllowPermission { verifyDownloadNotificationPopup() }.clickOpen("image/jpeg") {} // verify open intent is matched with associated data type downloadRobot { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt index 00bd7ebb8..3eb292239 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt @@ -1,8 +1,9 @@ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.ui import androidx.core.net.toUri import androidx.test.rule.ActivityTestRule -import androidx.test.rule.GrantPermissionRule import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before @@ -37,11 +38,6 @@ class CustomTabsTest { IntentReceiverActivity::class.java, true, false ) - @get:Rule - var mGrantPermissions = GrantPermissionRule.grant( - android.Manifest.permission.WRITE_EXTERNAL_STORAGE - ) - @Before fun setUp() { mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt index 871600d81..dcb05d64a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt @@ -5,7 +5,6 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri -import androidx.test.rule.GrantPermissionRule import org.junit.After import org.junit.Before import org.junit.Rule @@ -16,7 +15,6 @@ import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RetryTestRule -import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.ui.robots.navigationToolbar /** @@ -39,12 +37,6 @@ class DownloadFileTypesTest(fileName: String) { @JvmField val retryTestRule = RetryTestRule(3) - @get:Rule - var mGrantPermissions = GrantPermissionRule.grant( - android.Manifest.permission.WRITE_EXTERNAL_STORAGE, - android.Manifest.permission.READ_EXTERNAL_STORAGE - ) - companion object { // Creating test data. The test will take each file name as a parameter and run it individually. @JvmStatic @@ -71,7 +63,6 @@ class DownloadFileTypesTest(fileName: String) { @After fun tearDown() { - TestHelper.deleteDownloadFromStorage(downloadFile) featureSettingsHelper.resetAllFeatureFlags() } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt index 4148cd52c..2464d5cec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt @@ -6,7 +6,6 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.rule.GrantPermissionRule import androidx.test.uiautomator.UiDevice import org.junit.After import org.junit.Before @@ -15,7 +14,6 @@ import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule -import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestHelper.deleteDownloadFromStorage import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.downloadRobot @@ -40,28 +38,25 @@ class DownloadTest { @get:Rule val activityTestRule = HomeActivityIntentTestRule() - @Rule - @JvmField - val retryTestRule = RetryTestRule(3) - - @get:Rule - var mGrantPermissions = GrantPermissionRule.grant( - android.Manifest.permission.WRITE_EXTERNAL_STORAGE, - android.Manifest.permission.READ_EXTERNAL_STORAGE - ) - @Before fun setUp() { // disabling the jump-back-in pop-up that interferes with the tests. featureSettingsHelper.setJumpBackCFREnabled(false) // disabling the PWA CFR on 3rd visit featureSettingsHelper.disablePwaCFR(true) + // clear all existing notifications + notificationShade { + mDevice.openNotification() + clearNotifications() + } } @After fun tearDown() { - deleteDownloadFromStorage(downloadFile) featureSettingsHelper.resetAllFeatureFlags() + notificationShade { + cancelAllShownNotifications() + } } @Test @@ -70,6 +65,7 @@ class DownloadTest { navigationToolbar { }.enterURLAndEnterToBrowser(downloadTestPage.toUri()) { + waitForPageToLoad() }.clickDownloadLink(downloadFile) { verifyDownloadPrompt(downloadFile) }.clickDownload { @@ -78,6 +74,7 @@ class DownloadTest { downloadRobot { verifyPhotosAppOpens() } + mDevice.pressBack() } @Test @@ -86,6 +83,7 @@ class DownloadTest { navigationToolbar { }.enterURLAndEnterToBrowser(downloadTestPage.toUri()) { + waitForPageToLoad() }.clickDownloadLink(downloadFile) { verifyDownloadPrompt(downloadFile) }.closePrompt { @@ -101,11 +99,12 @@ class DownloadTest { navigationToolbar { }.enterURLAndEnterToBrowser(downloadTestPage.toUri()) { + waitForPageToLoad() }.clickDownloadLink(downloadFile) { verifyDownloadPrompt(downloadFile) }.clickDownload { verifyDownloadNotificationPopup() - } + }.closePrompt { } mDevice.openNotification() notificationShade { verifySystemNotificationExists("Download completed") @@ -119,15 +118,17 @@ class DownloadTest { navigationToolbar { }.enterURLAndEnterToBrowser(downloadTestPage.toUri()) { + waitForPageToLoad() }.clickDownloadLink(downloadFile) { verifyDownloadPrompt(downloadFile) }.clickDownload {} mDevice.openNotification() notificationShade { + verifySystemNotificationExists("Firefox Fenix") expandNotificationMessage() - clickSystemNotificationControlButton("Pause") - clickSystemNotificationControlButton("Resume") - clickSystemNotificationControlButton("Cancel") + clickDownloadNotificationControlButton("PAUSE") + clickDownloadNotificationControlButton("RESUME") + clickDownloadNotificationControlButton("CANCEL") mDevice.pressBack() } browserScreen { @@ -149,6 +150,7 @@ class DownloadTest { navigationToolbar { }.enterURLAndEnterToBrowser(downloadTestPage.toUri()) { + waitForPageToLoad() }.clickDownloadLink(downloadFile) { verifyDownloadPrompt(downloadFile) }.clickDownload { @@ -162,8 +164,8 @@ class DownloadTest { verifyDownloadedFileIcon() openDownloadedFile(downloadFile) verifyPhotosAppOpens() - mDevice.pressBack() - deleteDownloadFromStorage(downloadFile) + deleteDownloadFromStorage() + waitForDownloadsListToExist() }.exitDownloadsManagerToBrowser { }.openThreeDotMenu { }.openDownloadsManager { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt index d530391c2..081c3dd37 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt @@ -71,7 +71,7 @@ class MediaNotificationTest { assertPlaybackState(browserStore, MediaSession.PlaybackState.PLAYING) }.openNotificationShade { verifySystemNotificationExists(videoTestPage.title) - clickSystemNotificationControlButton("Pause") + clickMediaNotificationControlButton("Pause") verifyMediaSystemNotificationButtonState("Play") } @@ -93,6 +93,7 @@ class MediaNotificationTest { mDevice.pressBack() } + @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun mediaSystemNotificationInPrivateModeTest() { val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) @@ -107,7 +108,7 @@ class MediaNotificationTest { assertPlaybackState(browserStore, MediaSession.PlaybackState.PLAYING) }.openNotificationShade { verifySystemNotificationExists("A site is playing media") - clickSystemNotificationControlButton("Pause") + clickMediaNotificationControlButton("Pause") verifyMediaSystemNotificationButtonState("Play") } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt index 2d92884d6..bae046a00 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt @@ -14,6 +14,7 @@ import org.junit.Test import org.mozilla.fenix.R import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.browserScreen @@ -37,6 +38,10 @@ class ReaderViewTest { @get:Rule val activityIntentTestRule = HomeActivityIntentTestRule() + @Rule + @JvmField + val retryTestRule = RetryTestRule(3) + @Before fun setUp() { mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt index 0d1d57965..ecb1f6e49 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt @@ -17,6 +17,7 @@ import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource +import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.addonsMenu @@ -35,6 +36,10 @@ class SettingsAddonsTest { @get:Rule val activityTestRule = HomeActivityTestRule() + @Rule + @JvmField + val retryTestRule = RetryTestRule(3) + @Before fun setUp() { mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt index a8d34e435..66c81f64e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt @@ -73,6 +73,7 @@ class SettingsAdvancedTest { @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/23481") @SmokeTest @Test + // Assumes Play Store is installed and enabled fun openLinkInAppTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 3) val playStoreUrl = "play.google.com/store/apps/details?id=org.mozilla.fenix" diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt index 6b51f7cfe..f730ab2f2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt @@ -4,20 +4,25 @@ package org.mozilla.fenix.ui +import android.os.Build +import android.view.autofill.AutofillManager import androidx.core.net.toUri 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.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper +import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.helpers.TestHelper.openAppFromExternalLink import org.mozilla.fenix.helpers.TestHelper.restartApp import org.mozilla.fenix.ui.robots.addToHomeScreen @@ -41,6 +46,10 @@ class SettingsPrivacyTest { @get:Rule val activityTestRule = HomeActivityIntentTestRule() + @Rule + @JvmField + val retryTestRule = RetryTestRule(3) + @Before fun setUp() { mockWebServer = MockWebServer().apply { @@ -50,6 +59,12 @@ class SettingsPrivacyTest { val settings = activityTestRule.activity.applicationContext.settings() settings.shouldShowJumpBackInCFR = false + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + val autofillManager: AutofillManager = + appContext.getSystemService(AutofillManager::class.java) + autofillManager.disableAutofillServices() + } } @After @@ -376,6 +391,7 @@ class SettingsPrivacyTest { } } + @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun launchLinksInPrivateToggleOffStateDoesntChangeTest() { val settings = activityTestRule.activity.applicationContext.settings() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt index ed3105de5..f7671f76d 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt @@ -4,12 +4,20 @@ package org.mozilla.fenix.ui +import android.Manifest +import android.content.Context import androidx.core.net.toUri +import androidx.test.rule.GrantPermissionRule +import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test +import org.mozilla.fenix.components.PermissionStorage import org.mozilla.fenix.customannotations.SmokeTest -import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.FeatureSettingsHelper +import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.navigationToolbar @@ -21,21 +29,43 @@ class SitePermissionsTest { /* Test page created and handled by the Mozilla mobile test-eng team */ private val testPage = "https://mozilla-mobile.github.io/testapp/permissions" private val testPageSubstring = "https://mozilla-mobile.github.io:443" + private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityTestRule = HomeActivityIntentTestRule() + val activityTestRule = HomeActivityTestRule() + + @get:Rule + val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.CAMERA + ) + + @Before + fun setUp() { + // disabling the new homepage pop-up that interferes with the tests. + featureSettingsHelper.setJumpBackCFREnabled(false) + featureSettingsHelper.deleteSitePermissions(true) + } + + @After + fun tearDown() { + // Clearing all permission data after each test to avoid overlapping data + val applicationContext: Context = activityTestRule.activity.applicationContext + val permissionStorage = PermissionStorage(applicationContext) + + runBlocking { + permissionStorage.deleteAllSitePermissions() + } + } @SmokeTest @Test + @Ignore("Firebase - No camera and microphone on AVD") fun audioVideoPermissionChoiceOnEachRequestTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartAudioVideoButton { - // allow app to record video - clickAppPermissionButton(true) - // allow app to record audio - clickAppPermissionButton(true) verifyAudioVideoPermissionPrompt(testPageSubstring) }.clickPagePermissionButton(false) { verifyPageContent("Camera and Microphone not allowed") @@ -47,15 +77,12 @@ class SitePermissionsTest { @SmokeTest @Test + @Ignore("Firebase - No camera and microphone on AVD, see also https://github.com/mozilla-mobile/fenix/issues/23298") fun rememberBlockAudioVideoPermissionChoiceTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartAudioVideoButton { - // allow app to record video - clickAppPermissionButton(true) - // allow app to record audio - clickAppPermissionButton(true) verifyAudioVideoPermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(false) { @@ -69,7 +96,7 @@ class SitePermissionsTest { } } - @Ignore("Failing, see https://github.com/mozilla-mobile/fenix/issues/23358") + @Ignore("Firebase - No camera and microphone on AVD, see also https://github.com/mozilla-mobile/fenix/issues/23298") @SmokeTest @Test fun rememberAllowAudioVideoPermissionChoiceTest() { @@ -77,10 +104,6 @@ class SitePermissionsTest { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartAudioVideoButton { - // allow app to record video - clickAppPermissionButton(true) - // allow app to record audio - clickAppPermissionButton(true) verifyAudioVideoPermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(true) { @@ -94,29 +117,13 @@ class SitePermissionsTest { } } - @SmokeTest - @Test - fun blockAppUsingAudioVideoTest() { - navigationToolbar { - }.enterURLAndEnterToBrowser(testPage.toUri()) { - }.clickStartAudioVideoButton { - // allow app to record video - clickAppPermissionButton(false) - // allow app to record audio - clickAppPermissionButton(false) - } - browserScreen { - verifyPageContent("Camera and Microphone not allowed") - } - } - @Test + @Ignore("Firebase - No camera and microphone on AVD") fun microphonePermissionChoiceOnEachRequestTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartMicrophoneButton { - clickAppPermissionButton(true) verifyMicrophonePermissionPrompt(testPageSubstring) }.clickPagePermissionButton(false) { verifyPageContent("Microphone not allowed") @@ -127,12 +134,12 @@ class SitePermissionsTest { } @Test + @Ignore("Firebase - No camera and microphone on AVD") fun rememberBlockMicrophonePermissionChoiceTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartMicrophoneButton { - clickAppPermissionButton(true) verifyMicrophonePermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(false) { @@ -153,7 +160,6 @@ class SitePermissionsTest { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartMicrophoneButton { - clickAppPermissionButton(true) verifyMicrophonePermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(true) { @@ -168,24 +174,12 @@ class SitePermissionsTest { } @Test - fun blockAppUsingMicrophoneTest() { - navigationToolbar { - }.enterURLAndEnterToBrowser(testPage.toUri()) { - }.clickStartMicrophoneButton { - clickAppPermissionButton(false) - } - browserScreen { - verifyPageContent("Microphone not allowed") - } - } - - @Test + @Ignore("Firebase - No camera and microphone on AVD") fun cameraPermissionChoiceOnEachRequestTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartCameraButton { - clickAppPermissionButton(true) verifyCameraPermissionPrompt(testPageSubstring) }.clickPagePermissionButton(false) { verifyPageContent("Camera not allowed") @@ -196,12 +190,12 @@ class SitePermissionsTest { } @Test + @Ignore("Firebase - No camera and microphone on AVD") fun rememberBlockCameraPermissionChoiceTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartCameraButton { - clickAppPermissionButton(true) verifyCameraPermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(false) { @@ -216,12 +210,12 @@ class SitePermissionsTest { } @Test + @Ignore("Firebase - No camera and microphone on AVD") fun rememberAllowCameraPermissionChoiceTest() { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() }.clickStartCameraButton { - clickAppPermissionButton(true) verifyCameraPermissionPrompt(testPageSubstring) selectRememberPermissionDecision() }.clickPagePermissionButton(true) { @@ -235,18 +229,6 @@ class SitePermissionsTest { } } - @Test - fun blockAppUsingCameraTest() { - navigationToolbar { - }.enterURLAndEnterToBrowser(testPage.toUri()) { - }.clickStartCameraButton { - clickAppPermissionButton(false) - } - browserScreen { - verifyPageContent("Camera not allowed") - } - } - @Test fun blockNotificationsPermissionPromptTest() { navigationToolbar { @@ -280,7 +262,6 @@ class SitePermissionsTest { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { }.clickGetLocationButton { - clickAppPermissionButton(true) verifyLocationPermissionPrompt(testPageSubstring) }.clickPagePermissionButton(true) { verifyPageContent("longitude") @@ -294,7 +275,6 @@ class SitePermissionsTest { navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { }.clickGetLocationButton { - clickAppPermissionButton(true) verifyLocationPermissionPrompt(testPageSubstring) }.clickPagePermissionButton(false) { verifyPageContent("User denied geolocation prompt") diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index 01107d984..cc480ef14 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -2,15 +2,17 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.ui import android.view.View import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.core.net.toUri import androidx.test.espresso.IdlingRegistry +import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ActivityTestRule -import androidx.test.rule.GrantPermissionRule import androidx.test.uiautomator.UiDevice import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.mediasession.MediaSession @@ -85,12 +87,6 @@ class SmokeTest { IntentReceiverActivity::class.java, true, false ) - @get:Rule - var mGrantPermissions = GrantPermissionRule.grant( - android.Manifest.permission.WRITE_EXTERNAL_STORAGE, - android.Manifest.permission.READ_EXTERNAL_STORAGE - ) - @Rule @JvmField val retryTestRule = RetryTestRule(3) @@ -379,6 +375,7 @@ class SmokeTest { } @Test + // Device or AVD requires a Google Services Android OS installation with Play Store installed // Verifies the Open in app button when an app is installed fun mainMenuOpenInAppTest() { val playStoreUrl = "play.google.com/store/apps/details?id=org.mozilla.fenix" @@ -537,6 +534,7 @@ class SmokeTest { } @Test + @SdkSuppress(minSdkVersion = 29) // Verifies that you can go to System settings and change app's permissions from inside the app fun redirectToAppPermissionsSystemSettingsTest() { homeScreen { @@ -553,9 +551,12 @@ class SmokeTest { verifyBlockedByAndroid() clickGoToSettingsButton() openAppSystemPermissionsSettings() - switchAppPermissionSystemSetting("Camera") - switchAppPermissionSystemSetting("Location") - switchAppPermissionSystemSetting("Microphone") + switchAppPermissionSystemSetting("Camera", "Allow") + mDevice.pressBack() + switchAppPermissionSystemSetting("Location", "Allow") + mDevice.pressBack() + switchAppPermissionSystemSetting("Microphone", "Allow") + mDevice.pressBack() mDevice.pressBack() mDevice.pressBack() verifyUnblockedByAndroid() @@ -1064,7 +1065,7 @@ class SmokeTest { assertPlaybackState(browserStore, MediaSession.PlaybackState.PLAYING) }.openNotificationShade { verifySystemNotificationExists(audioTestPage.title) - clickSystemNotificationControlButton("Pause") + clickMediaNotificationControlButton("Pause") verifyMediaSystemNotificationButtonState("Play") } @@ -1111,10 +1112,12 @@ class SmokeTest { homeScreen { }.openThreeDotMenu { }.openSettings { - verifyDefaultBrowserIsDisaled() + verifyDefaultBrowserIsDisabled() clickDefaultBrowserSwitch() verifyAndroidDefaultAppsMenuAppears() } + // Dismiss the request + mDevice.pressBack() } @Test diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt index 2be2e07d5..7d11f0943 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.ui import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest @@ -125,6 +126,7 @@ class StrictEnhancedTrackingProtectionTest { } } + @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun testStrictVisitDisableExceptionToggle() { val genericPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt index 45d1b41f5..b1a37eacb 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.ui import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.ext.settings @@ -42,6 +43,7 @@ class ThreeDotMenuMainTest { } // Verifies the list of items in the homescreen's 3 dot main menu + @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun homeThreeDotMenuItemsTest() { homeScreen { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/AddToHomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/AddToHomeScreenRobot.kt index 859bd317b..c410c1ab6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/AddToHomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/AddToHomeScreenRobot.kt @@ -14,7 +14,6 @@ import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By -import androidx.test.uiautomator.By.textContains import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until @@ -23,6 +22,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull +import java.util.regex.Pattern /** * Implementation of Robot Pattern for the Add to homescreen feature. @@ -50,7 +50,14 @@ class AddToHomeScreenRobot { fun clickAddAutomaticallyButton() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mDevice.wait(Until.findObject(textContains("add automatically")), waitingTime) + mDevice.wait( + Until.findObject( + By.text( + Pattern.compile("Add Automatically", Pattern.CASE_INSENSITIVE) + ) + ), + waitingTime + ) addAutomaticallyButton().click() } } @@ -69,6 +76,7 @@ class AddToHomeScreenRobot { fun searchAndOpenHomeScreenShortcut(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { mDevice.pressHome() + mDevice.waitForIdle() fun homeScreenView() = UiScrollable(UiSelector().scrollable(true)) homeScreenView().setAsHorizontalList() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/EnhancedTrackingProtectionRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/EnhancedTrackingProtectionRobot.kt index 0577325e4..9067d3746 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/EnhancedTrackingProtectionRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/EnhancedTrackingProtectionRobot.kt @@ -8,6 +8,7 @@ package org.mozilla.fenix.ui.robots import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.RootMatchers import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed @@ -151,7 +152,11 @@ private fun enhancedTrackingProtectionSwitch() = onView(ViewMatchers.withResourceName("switch_widget")) private fun trackingProtectionSettingsButton() = - onView(withId(R.id.protection_settings)) + onView(withId(R.id.protection_settings)).inRoot(RootMatchers.isDialog()).check( + matches( + isDisplayed() + ) + ) private fun openEnhancedTrackingProtectionDetails() = mDevice.findObject(UiSelector().resourceId("$packageName:id/trackingProtectionDetails")) 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 ea2af99c5..c1ceb0c80 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 @@ -665,9 +665,13 @@ private fun assertExistingTopSitesTabs(title: String) { .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertNotExistingTopSitesList(title: String) = +private fun assertNotExistingTopSitesList(title: String) { + mDevice.findObject(UiSelector().text(title)) + .waitUntilGone(waitingTime) + onView(allOf(withId(R.id.top_sites_list))) .check(matches(not(hasItem(hasDescendant(withText(title)))))) +} private fun assertTopSiteContextMenuItems() { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt index 57d1eade7..1770f2e59 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt @@ -4,33 +4,49 @@ package org.mozilla.fenix.ui.robots +import android.app.NotificationManager +import android.content.Context import androidx.test.uiautomator.By.text -import androidx.test.uiautomator.UiObjectNotFoundException import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.ext.waitNotNull +import java.lang.AssertionError class NotificationRobot { fun verifySystemNotificationExists(notificationMessage: String) { - var notificationFound = false - - do { - try { - notificationFound = notificationTray().getChildByText( - UiSelector().text(notificationMessage), notificationMessage, true - ).waitForExists(waitingTime) - assertTrue(notificationFound) - } catch (e: UiObjectNotFoundException) { - notificationTray().scrollForward() - mDevice.waitForIdle() + val notification = UiSelector().text(notificationMessage) + var notificationFound = mDevice.findObject(notification).waitForExists(waitingTime) + + while (!notificationFound) { + scrollToEnd() + notificationFound = mDevice.findObject(notification).waitForExists(waitingTime) + } + + assertTrue(notificationFound) + } + + fun clearNotifications() { + if (clearButton.exists()) { + clearButton.click() + } else { + scrollToEnd() + if (clearButton.exists()) { + clearButton.click() + } else if (notificationTray().exists()) { + mDevice.pressBack() } - } while (!notificationFound) + } + } + + fun cancelAllShownNotifications() { + cancelAll() } fun verifySystemNotificationGone(notificationMessage: String) { @@ -51,20 +67,47 @@ class NotificationRobot { assertPrivateTabsNotification() } - fun clickSystemNotificationControlButton(action: String) { + fun clickMediaNotificationControlButton(action: String) { mediaSystemNotificationButton(action).waitForExists(waitingTime) mediaSystemNotificationButton(action).click() } + fun clickDownloadNotificationControlButton(action: String) { + assertTrue(downloadSystemNotificationButton(action).waitForExists(waitingTime)) + downloadSystemNotificationButton(action).click() + + // API 30 Bug? Sometimes a click doesn't register, try again + try { + assertTrue(downloadSystemNotificationButton(action).waitUntilGone(waitingTime)) + } catch (e: AssertionError) { + downloadSystemNotificationButton(action).click() + } + } + fun verifyMediaSystemNotificationButtonState(action: String) { assertTrue(mediaSystemNotificationButton(action).waitForExists(waitingTime)) } + fun verifyDownloadSystemNotificationButtonState(action: String) { + assertTrue(downloadSystemNotificationButton(action).waitForExists(waitingTime)) + } + fun expandNotificationMessage() { while (!notificationHeader.exists()) { - notificationTray().scrollForward() + scrollToEnd() + } + + if (notificationHeader.exists()) { + // expand the notification + notificationHeader.click() + + // double check if notification actions are viewable by checking for action existence; otherwise scroll again + while (!mDevice.findObject(UiSelector().resourceId("android:id/action0")).exists() && + !mDevice.findObject(UiSelector().resourceId("android:id/actions_container")).exists() + ) { + scrollToEnd() + } } - notificationHeader.click() } class Transition { @@ -92,16 +135,23 @@ private fun assertPrivateTabsNotification() { private fun closePrivateTabsNotification() = mDevice.findObject(UiSelector().text("Close private tabs")) -private fun mediaSystemNotificationButton(action: String) = +private fun downloadSystemNotificationButton(action: String) = mDevice.findObject( UiSelector() .resourceId("android:id/action0") + .textContains(action) + ) + +private fun mediaSystemNotificationButton(action: String) = + mDevice.findObject( + UiSelector() + .resourceId("com.android.systemui:id/action0") .descriptionContains(action) ) private fun notificationTray() = UiScrollable( UiSelector().resourceId("com.android.systemui:id/notification_stack_scroller") -) +).setAsVerticalList() private val notificationHeader = mDevice.findObject( @@ -109,3 +159,15 @@ private val notificationHeader = .resourceId("android:id/app_name_text") .text(appName) ) + +private fun scrollToEnd() { + notificationTray().scrollToEnd(1) +} + +private val clearButton = mDevice.findObject(UiSelector().resourceId("com.android.systemui:id/dismiss_text")) + +private fun cancelAll() { + val notificationManager: NotificationManager = + TestHelper.appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancelAll() +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index cfae227a8..c1754cf81 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.ui.robots +import android.os.Build import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed @@ -49,6 +50,7 @@ import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.waitForObjects import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull +import org.mozilla.fenix.helpers.Constants.PackageName /** * Implementation of Robot Pattern for the search fragment. @@ -66,12 +68,29 @@ class SearchRobot { } } + // Device or AVD requires a Google Services Android OS installation fun startVoiceSearch() { voiceSearchButton.click() - assertTrue( - mDevice.findObject(UiSelector().packageName("com.google.android.googlequicksearchbox")) - .exists() - ) + + // Accept runtime permission (API 30) for Google Voice + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + val allowPermission = mDevice.findObject( + UiSelector().text( + when { + Build.VERSION.SDK_INT == Build.VERSION_CODES.R -> "Allow all the time" + else -> "While using the app" + } + ) + ) + + if (allowPermission.exists()) { + allowPermission.click() + } + + mDevice.waitNotNull( + Until.findObject(By.pkg(PackageName.GOOGLE_QUICK_SEARCH)), waitingTime + ) + } } fun verifySearchEngineButton() = assertSearchButton() 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 f991d8804..4cdff8187 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 @@ -68,7 +68,7 @@ class SettingsRobot { fun verifyHomepageButton() = assertHomepageButton() fun verifyCreditCardsButton() = assertCreditCardsButton() fun verifyLanguageButton() = assertLanguageButton() - fun verifyDefaultBrowserIsDisaled() = assertDefaultBrowserIsDisabled() + fun verifyDefaultBrowserIsDisabled() = assertDefaultBrowserIsDisabled() fun clickDefaultBrowserSwitch() = toggleDefaultBrowserSwitch() fun verifyAndroidDefaultAppsMenuAppears() = assertAndroidDefaultAppsMenuAppears() @@ -187,10 +187,15 @@ class SettingsRobot { } fun openLanguageSubMenu(interact: SettingsSubMenuLanguageRobot.() -> Unit): SettingsSubMenuLanguageRobot.Transition { - scrollToElementByText("Language") - - fun languageButton() = onView(withText("Language")) - languageButton().click() + onView(withId(R.id.recycler_view)) + .perform( + RecyclerViewActions.actionOnItem( + hasDescendant( + withText(R.string.preferences_language) + ), + ViewActions.click() + ) + ) SettingsSubMenuLanguageRobot().interact() return SettingsSubMenuLanguageRobot.Transition() @@ -295,7 +300,7 @@ class SettingsRobot { } companion object { - const val DEFAULT_APPS_SETTINGS_ACTION = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS" + const val DEFAULT_APPS_SETTINGS_ACTION = "android.app.role.action.REQUEST_ROLE" } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAddonsManagerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAddonsManagerRobot.kt index b3ec5b076..2a897c6f0 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAddonsManagerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAddonsManagerRobot.kt @@ -2,6 +2,8 @@ * 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/. */ +@file:Suppress("DEPRECATION") + package org.mozilla.fenix.ui.robots import android.widget.RelativeLayout diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt index e06dc670b..31875fe41 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt @@ -98,9 +98,15 @@ class SettingsSubMenuSitePermissionsCommonRobot { mDevice.findObject(UiSelector().textContains("Permissions")).click() } - fun switchAppPermissionSystemSetting(permissionCategory: String) { + fun switchAppPermissionSystemSetting(permissionCategory: String, permission: String) { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mDevice.findObject(UiSelector().textContains(permissionCategory)).click() + + if (permission == "Allow") { + mDevice.findObject(UiSelector().textContains("Allow")).click() + } else { + mDevice.findObject(UiSelector().textContains("Deny")).click() + } } class Transition { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt index 717904b0a..9943d012b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt @@ -13,19 +13,18 @@ import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.getPermissionAllowID import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.click class SitePermissionsRobot { - fun clickAppPermissionButton(allow: Boolean) { - if (allow) { - allowSystemPermissionButton.waitForExists(waitingTime) - allowSystemPermissionButton.click() - } else { - denySystemPermissionButton.waitForExists(waitingTime) - denySystemPermissionButton.click() - } + fun clickGrantAppPermissionButton() { + TestHelper.grantPermission() + } + + fun clickDenyAppPermissionButton() { + TestHelper.denyPermission() } fun verifyMicrophonePermissionPrompt(url: String) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SystemSettingsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SystemSettingsRobot.kt index 03a1796e8..dc1ce816d 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SystemSettingsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SystemSettingsRobot.kt @@ -9,6 +9,7 @@ import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction import androidx.test.uiautomator.UiSelector import org.junit.Assert.assertTrue import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestHelper class SystemSettingsRobot { fun verifySystemNotificationsView() = assertSystemNotificationsView() @@ -40,7 +41,7 @@ private fun assertSystemNotificationsView() { mDevice.findObject(UiSelector().resourceId("com.android.settings:id/list")) .waitForExists(waitingTime) assertTrue( - mDevice.findObject(UiSelector().textContains("Show notifications")) + mDevice.findObject(UiSelector().textContains("All ${TestHelper.appName} notifications")) .waitForExists(waitingTime) ) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 6731ec117..9fe33ad8f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -43,6 +43,7 @@ import org.hamcrest.Matcher import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort +import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.click @@ -228,15 +229,17 @@ class TabDrawerRobot { tabMediaControlButton().click() } - fun clickSelectTabs() { + private fun clickSelectTabs() { threeDotMenu().click() mDevice.waitNotNull( - Until.findObject(text("Select tabs")), + findObject( + text(getStringResource(R.string.tabs_tray_select_tabs)) + ), waitingTime ) - val selectTabsButton = mDevice.findObject(text("Select tabs")) + val selectTabsButton = mDevice.findObject(text(getStringResource(R.string.tabs_tray_select_tabs))) selectTabsButton.click() } diff --git a/automation/taskcluster/androidTest/flank-arm64-v8a.yml b/automation/taskcluster/androidTest/flank-arm64-v8a.yml index c29f03968..58db5c740 100644 --- a/automation/taskcluster/androidTest/flank-arm64-v8a.yml +++ b/automation/taskcluster/androidTest/flank-arm64-v8a.yml @@ -35,7 +35,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-armeabi-v7a-start-test.yml b/automation/taskcluster/androidTest/flank-armeabi-v7a-start-test.yml index 16292c98e..b1df75ed8 100644 --- a/automation/taskcluster/androidTest/flank-armeabi-v7a-start-test.yml +++ b/automation/taskcluster/androidTest/flank-armeabi-v7a-start-test.yml @@ -38,7 +38,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-armeabi-v7a.yml b/automation/taskcluster/androidTest/flank-armeabi-v7a.yml index dc30199e5..78a3137c6 100644 --- a/automation/taskcluster/androidTest/flank-armeabi-v7a.yml +++ b/automation/taskcluster/androidTest/flank-armeabi-v7a.yml @@ -35,7 +35,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-x86-beta.yml b/automation/taskcluster/androidTest/flank-x86-beta.yml index 96aaa82bd..2041985ab 100644 --- a/automation/taskcluster/androidTest/flank-x86-beta.yml +++ b/automation/taskcluster/androidTest/flank-x86-beta.yml @@ -48,7 +48,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-x86-screenshots-tests.yml b/automation/taskcluster/androidTest/flank-x86-screenshots-tests.yml index 61adceda5..fd026eaa3 100644 --- a/automation/taskcluster/androidTest/flank-x86-screenshots-tests.yml +++ b/automation/taskcluster/androidTest/flank-x86-screenshots-tests.yml @@ -42,7 +42,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-x86-start-test.yml b/automation/taskcluster/androidTest/flank-x86-start-test.yml index af3b13037..3eca68bed 100644 --- a/automation/taskcluster/androidTest/flank-x86-start-test.yml +++ b/automation/taskcluster/androidTest/flank-x86-start-test.yml @@ -44,7 +44,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 flank: project: GOOGLE_PROJECT diff --git a/automation/taskcluster/androidTest/flank-x86.yml b/automation/taskcluster/androidTest/flank-x86.yml index 8ea8f47f5..4226b9a20 100644 --- a/automation/taskcluster/androidTest/flank-x86.yml +++ b/automation/taskcluster/androidTest/flank-x86.yml @@ -43,7 +43,7 @@ gcloud: device: - model: Pixel2 - version: 28 + version: 30 locale: en_US flank: diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 6d58755fb..ca23a394d 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -226,14 +226,15 @@ object Deps { // https://developer.android.com/jetpack/androidx/releases/test // For the full IDs of these test dependencies, see: // https://developer.android.com/training/testing/set-up-project#android-test-dependencies - private const val androidx_test_shared_version = "1.3.0-alpha05" // this appears to be shared with many deps. + private const val androidx_test_shared_version = "1.4.0" // this appears to be shared with many deps. const val androidx_test_core = "androidx.test:core:$androidx_test_shared_version" - private const val androidx_espresso_version = "3.3.0-alpha05" + private const val androidx_espresso_version = "3.4.0" const val espresso_core = "androidx.test.espresso:espresso-core:$androidx_espresso_version" const val espresso_contrib = "androidx.test.espresso:espresso-contrib:$androidx_espresso_version" const val espresso_idling_resources = "androidx.test.espresso:espresso-idling-resource:$androidx_espresso_version" const val espresso_intents = "androidx.test.espresso:espresso-intents:$androidx_espresso_version" const val androidx_junit = "androidx.test.ext:junit:1.1.2-alpha05" + const val androidx_test_extensions = "androidx.test.ext:junit-ktx:1.1.3" // Monitor is unused const val orchestrator = "androidx.test:orchestrator:$androidx_test_shared_version" const val tools_test_runner = "androidx.test:runner:$androidx_test_shared_version" @@ -278,5 +279,5 @@ object RepoMatching { * explicitly exclude it from this regex so it can be found on Maven Central. Note that the transitive * dependency com.google.guava is also not available on google's repo. */ - const val comGoogleAndroid = "com\\.google\\.android\\.(?!apps\\.common\\.testing\\.accessibility\\.framework).*" + const val comGoogleAndroid = "com\\.google\\.android\\..*" }