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 7c0cd92b61..2162531d44 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt @@ -14,6 +14,7 @@ object Constants { const val YOUTUBE_APP = "com.google.android.youtube" const val GMAIL_APP = "com.google.android.gm" const val PHONE_APP = "com.android.dialer" + const val ANDROID_SETTINGS = "com.android.settings" } const val SPEECH_RECOGNITION = "android.speech.action.RECOGNIZE_SPEECH" 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 bc33a27cfd..e633e04b81 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt @@ -55,6 +55,7 @@ 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 +import org.junit.Assert.assertTrue object TestHelper { @@ -227,10 +228,13 @@ object TestHelper { } } - fun assertNativeAppOpens(appPackageName: String, url: String) { + fun assertNativeAppOpens(appPackageName: String, url: String = "") { if (isPackageInstalled(appPackageName)) { mDevice.waitForIdle(waitingTimeShort) - assertTrue(mDevice.findObject(UiSelector().packageName(appPackageName)).waitForExists(waitingTime)) + assertTrue( + mDevice.findObject(UiSelector().packageName(appPackageName)) + .waitForExists(waitingTime) + ) } else { BrowserRobot().verifyUrl(url) } 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 04dab742f4..1f897d25e2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt @@ -4,14 +4,20 @@ package org.mozilla.fenix.ui +import android.os.Build import androidx.core.net.toUri +import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.permission.PermissionRequester import androidx.test.uiautomator.UiDevice import org.junit.After import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule +import org.junit.rules.TestWatcher +import org.junit.runner.Description import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule @@ -39,6 +45,22 @@ class DownloadTest { @get:Rule val activityTestRule = HomeActivityIntentTestRule() + @get: Rule + // Making sure to grant storage access for this test running on API 28 + var watcher: TestRule = object : TestWatcher() { + override fun starting(description: Description) { + if (description.methodName == "pauseResumeCancelDownloadTest") { + PermissionRequester().apply { + addPermissions( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE, + android.Manifest.permission.READ_EXTERNAL_STORAGE + ) + requestPermissions() + } + } + } + } + @Before fun setUp() { // disabling the jump-back-in pop-up that interferes with the tests. @@ -112,7 +134,7 @@ class DownloadTest { } } - @Ignore("Intermittent: https://github.com/mozilla-mobile/fenix/issues/23434") + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun pauseResumeCancelDownloadTest() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index 899092fe79..66eb0b0bcf 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -4,24 +4,33 @@ package org.mozilla.fenix.ui +import android.content.Context +import android.hardware.camera2.CameraManager +import android.os.Build import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.core.net.toUri import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu +import androidx.test.filters.SdkSuppress import mozilla.components.browser.icons.IconRequest import mozilla.components.browser.icons.generator.DefaultIconGenerator import mozilla.components.feature.search.ext.createSearchEngine import okhttp3.mockwebserver.MockWebServer import org.junit.After +import org.junit.Assume.assumeTrue 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.helpers.Constants.PackageName.ANDROID_SETTINGS import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.SearchDispatcher import org.mozilla.fenix.helpers.TestHelper.appContext +import org.mozilla.fenix.helpers.TestHelper.assertNativeAppOpens +import org.mozilla.fenix.helpers.TestHelper.denyPermission import org.mozilla.fenix.helpers.TestHelper.exitMenu +import org.mozilla.fenix.helpers.TestHelper.grantPermission import org.mozilla.fenix.helpers.TestHelper.longTapSelectItem import org.mozilla.fenix.helpers.TestHelper.setCustomSearchEngine import org.mozilla.fenix.ui.robots.browserScreen @@ -75,16 +84,40 @@ class SearchTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest - @Ignore("This test cannot run on virtual devices due to camera permissions being required") @Test - fun scanButtonTest() { + fun scanButtonDenyPermissionTest() { + val cameraManager = appContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + homeScreen { }.openSearch { clickScanButton() - clickDenyPermission() + denyPermission() clickScanButton() - clickAllowPermission() + clickDismissPermissionRequiredDialog() + } + homeScreen { + }.openSearch { + clickScanButton() + clickGoToPermissionsSettings() + assertNativeAppOpens(ANDROID_SETTINGS) + } + } + + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") + @SmokeTest + @Test + fun scanButtonAllowPermissionTest() { + val cameraManager = appContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + + homeScreen { + }.openSearch { + clickScanButton() + grantPermission() + verifyScannerOpen() } } 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 f7671f76db..38de81d019 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt @@ -6,10 +6,15 @@ package org.mozilla.fenix.ui import android.Manifest import android.content.Context +import android.hardware.camera2.CameraManager +import android.media.AudioManager +import android.os.Build import androidx.core.net.toUri +import androidx.test.filters.SdkSuppress import androidx.test.rule.GrantPermissionRule import kotlinx.coroutines.runBlocking import org.junit.After +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Ignore import org.junit.Rule @@ -18,6 +23,7 @@ import org.mozilla.fenix.components.PermissionStorage import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.navigationToolbar @@ -30,6 +36,8 @@ class SitePermissionsTest { private val testPage = "https://mozilla-mobile.github.io/testapp/permissions" private val testPageSubstring = "https://mozilla-mobile.github.io:443" private val featureSettingsHelper = FeatureSettingsHelper() + private val cameraManager = appContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager + private val micManager = appContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager @get:Rule val activityTestRule = HomeActivityTestRule() @@ -58,10 +66,12 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test - @Ignore("Firebase - No camera and microphone on AVD") fun audioVideoPermissionChoiceOnEachRequestTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -75,10 +85,13 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test - @Ignore("Firebase - No camera and microphone on AVD, see also https://github.com/mozilla-mobile/fenix/issues/23298") fun rememberBlockAudioVideoPermissionChoiceTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + assumeTrue(micManager.microphones.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -96,10 +109,13 @@ class SitePermissionsTest { } } - @Ignore("Firebase - No camera and microphone on AVD, see also https://github.com/mozilla-mobile/fenix/issues/23298") + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun rememberAllowAudioVideoPermissionChoiceTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + assumeTrue(micManager.microphones.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -117,9 +133,11 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test - @Ignore("Firebase - No camera and microphone on AVD") fun microphonePermissionChoiceOnEachRequestTest() { + assumeTrue(micManager.microphones.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -133,9 +151,11 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test - @Ignore("Firebase - No camera and microphone on AVD") fun rememberBlockMicrophonePermissionChoiceTest() { + assumeTrue(micManager.microphones.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -153,9 +173,11 @@ class SitePermissionsTest { } } - @Ignore("Flaky, needs investigation: https://github.com/mozilla-mobile/fenix/issues/23298") + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun rememberAllowMicrophonePermissionChoiceTest() { + assumeTrue(micManager.microphones.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -173,9 +195,11 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test - @Ignore("Firebase - No camera and microphone on AVD") fun cameraPermissionChoiceOnEachRequestTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -189,9 +213,11 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test - @Ignore("Firebase - No camera and microphone on AVD") fun rememberBlockCameraPermissionChoiceTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() @@ -209,9 +235,11 @@ class SitePermissionsTest { } } + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test - @Ignore("Firebase - No camera and microphone on AVD") fun rememberAllowCameraPermissionChoiceTest() { + assumeTrue(cameraManager.cameraIdList.isNotEmpty()) + navigationToolbar { }.enterURLAndEnterToBrowser(testPage.toUri()) { waitForPageToLoad() 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 1770f2e59e..a37dfd5acb 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 @@ -17,6 +17,7 @@ import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.ext.waitNotNull import java.lang.AssertionError +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort class NotificationRobot { @@ -73,9 +74,13 @@ class NotificationRobot { } fun clickDownloadNotificationControlButton(action: String) { - assertTrue(downloadSystemNotificationButton(action).waitForExists(waitingTime)) - downloadSystemNotificationButton(action).click() + try { + assertTrue(downloadSystemNotificationButton(action).waitForExists(waitingTimeShort)) + } catch (e: AssertionError) { + notificationTray().flingToEnd(1) + } + downloadSystemNotificationButton(action).click() // API 30 Bug? Sometimes a click doesn't register, try again try { assertTrue(downloadSystemNotificationButton(action).waitUntilGone(waitingTime)) @@ -88,10 +93,6 @@ class NotificationRobot { assertTrue(mediaSystemNotificationButton(action).waitForExists(waitingTime)) } - fun verifyDownloadSystemNotificationButtonState(action: String) { - assertTrue(downloadSystemNotificationButton(action).waitForExists(waitingTime)) - } - fun expandNotificationMessage() { while (!notificationHeader.exists()) { scrollToEnd() 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 755dc9b370..c6aa83a3c0 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 @@ -20,7 +20,6 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollToIndex import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.assertion.ViewAssertions.matches @@ -35,7 +34,6 @@ import androidx.test.espresso.matcher.ViewMatchers.withText 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.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until @@ -130,15 +128,25 @@ class SearchRobot { } fun clickScanButton() { - scanButton().perform(click()) + scanButton.waitForExists(waitingTime) + scanButton.click() } - fun clickDenyPermission() { - denyPermissionButton().click() + fun clickDismissPermissionRequiredDialog() { + dismissPermissionButton.waitForExists(waitingTime) + dismissPermissionButton.click() } - fun clickAllowPermission() { - allowPermissionButton().click() + fun clickGoToPermissionsSettings() { + goToPermissionsSettingsButton.waitForExists(waitingTime) + goToPermissionsSettingsButton.click() + } + + fun verifyScannerOpen() { + assertTrue( + mDevice.findObject(UiSelector().resourceId("$packageName:id/view_finder")) + .waitForExists(waitingTime) + ) } fun typeSearch(searchTerm: String) { @@ -281,20 +289,14 @@ class SearchRobot { private fun browserToolbarEditView() = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view")) -private fun denyPermissionButton(): UiObject { - mDevice.waitNotNull(Until.findObjects(By.text("Deny")), waitingTime) - return mDevice.findObject(UiSelector().text("Deny")) -} +private val dismissPermissionButton = + mDevice.findObject(UiSelector().text("DISMISS")) -private fun allowPermissionButton(): UiObject { - mDevice.waitNotNull(Until.findObjects(By.text("Allow")), waitingTime) - return mDevice.findObject(UiSelector().text("Allow")) -} +private val goToPermissionsSettingsButton = + mDevice.findObject(UiSelector().text("GO TO SETTINGS")) -private fun scanButton(): ViewInteraction { - mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/search_scan_button")), waitingTime) - return onView(allOf(withId(R.id.qr_scan_button))) -} +private val scanButton = + mDevice.findObject(UiSelector().resourceId("$packageName:id/qr_scan_button")) private fun clearButton() = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_clear_view")) @@ -348,9 +350,7 @@ private fun assertBrowserToolbarEditView() = private fun assertScanButton() = assertTrue( - mDevice.findObject( - UiSelector().resourceId("$packageName:id/qr_scan_button") - ).waitForExists(waitingTime) + scanButton.waitForExists(waitingTime) ) private fun assertSearchButton() =