diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt new file mode 100644 index 000000000000..750a1d272e98 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt @@ -0,0 +1,226 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui + +import androidx.core.net.toUri +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.customannotations.SmokeTest +import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.ui.robots.browserScreen +import org.mozilla.fenix.ui.robots.navigationToolbar + +/** + * Tests for verifying site permissions prompts & functionality + * + */ +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" + + @get:Rule + val activityTestRule = HomeActivityIntentTestRule() + + @SmokeTest + @Test + fun microphonePermissionChoiceOnEachRequestTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartMicrophoneButton { + clickAppPermissionButton(true) + verifyMicrophonePermissionPrompt(testPageSubstring) + }.clickPagePermissionButton(false) { + verifyPageContent("Microphone not allowed") + }.clickStartMicrophoneButton { + }.clickPagePermissionButton(true) { + verifyPageContent("Microphone allowed") + } + } + + @SmokeTest + @Test + fun rememberBlockMicrophonePermissionChoiceTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartMicrophoneButton { + clickAppPermissionButton(true) + verifyMicrophonePermissionPrompt(testPageSubstring) + selectRememberPermissionDecision() + }.clickPagePermissionButton(false) { + verifyPageContent("Microphone not allowed") + }.openThreeDotMenu { + }.refreshPage { + waitForPageToLoad() + }.clickStartMicrophoneButton { } + browserScreen { + verifyPageContent("Microphone not allowed") + } + } + + @Ignore("Flaky, needs investigation: https://github.com/mozilla-mobile/fenix/issues/23298") + @SmokeTest + @Test + fun rememberAllowMicrophonePermissionChoiceTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartMicrophoneButton { + clickAppPermissionButton(true) + verifyMicrophonePermissionPrompt(testPageSubstring) + selectRememberPermissionDecision() + }.clickPagePermissionButton(true) { + verifyPageContent("Microphone allowed") + }.openThreeDotMenu { + }.refreshPage { + waitForPageToLoad() + }.clickStartMicrophoneButton { } + browserScreen { + verifyPageContent("Microphone allowed") + } + } + + @SmokeTest + @Test + fun blockAppUsingMicrophoneTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + }.clickStartMicrophoneButton { + clickAppPermissionButton(false) + } + browserScreen { + verifyPageContent("Microphone not allowed") + } + } + + @SmokeTest + @Test + fun cameraPermissionChoiceOnEachRequestTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartCameraButton { + clickAppPermissionButton(true) + verifyCameraPermissionPrompt(testPageSubstring) + }.clickPagePermissionButton(false) { + verifyPageContent("Camera not allowed") + }.clickStartCameraButton { + }.clickPagePermissionButton(true) { + verifyPageContent("Camera allowed") + } + } + + @SmokeTest + @Test + fun rememberBlockCameraPermissionChoiceTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartCameraButton { + clickAppPermissionButton(true) + verifyCameraPermissionPrompt(testPageSubstring) + selectRememberPermissionDecision() + }.clickPagePermissionButton(false) { + verifyPageContent("Camera not allowed") + }.openThreeDotMenu { + }.refreshPage { + waitForPageToLoad() + }.clickStartCameraButton { } + browserScreen { + verifyPageContent("Camera not allowed") + } + } + + @SmokeTest + @Test + fun rememberAllowCameraPermissionChoiceTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + waitForPageToLoad() + }.clickStartCameraButton { + clickAppPermissionButton(true) + verifyCameraPermissionPrompt(testPageSubstring) + selectRememberPermissionDecision() + }.clickPagePermissionButton(true) { + verifyPageContent("Camera allowed") + }.openThreeDotMenu { + }.refreshPage { + waitForPageToLoad() + }.clickStartCameraButton { } + browserScreen { + verifyPageContent("Camera allowed") + } + } + + @SmokeTest + @Test + fun blockAppUsingCameraTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + }.clickStartCameraButton { + clickAppPermissionButton(false) + } + browserScreen { + verifyPageContent("Camera not allowed") + } + } + + @Test + fun blockNotificationsPermissionPromptTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + }.clickOpenNotificationButton { + verifyNotificationsPermissionPrompt(testPageSubstring) + }.clickPagePermissionButton(false) { + verifyPageContent("Notifications not allowed") + }.openThreeDotMenu { + }.refreshPage { + waitForPageToLoad() + }.clickOpenNotificationButton { + verifyNotificationsPermissionPrompt(testPageSubstring, true) + } + } + + @Test + fun allowNotificationsPermissionPromptTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + }.clickOpenNotificationButton { + verifyNotificationsPermissionPrompt(testPageSubstring) + }.clickPagePermissionButton(true) { + verifyPageContent("Notifications allowed") + } + } + + @Ignore("Needs mocking location for Firebase - to do: https://github.com/mozilla-mobile/mobile-test-eng/issues/585") + @Test + fun allowLocationPermissionsTest() { + navigationToolbar { + }.enterURLAndEnterToBrowser(testPage.toUri()) { + }.clickGetLocationButton { + clickAppPermissionButton(true) + verifyLocationPermissionPrompt(testPageSubstring) + }.clickPagePermissionButton(true) { + verifyPageContent("longitude") + verifyPageContent("latitude") + } + } + + @Ignore("Needs mocking location for Firebase - to do: https://github.com/mozilla-mobile/mobile-test-eng/issues/585") + @Test + fun blockLocationPermissionsTest() { + 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 8265ffbb8490..bb107c56b1d5 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -41,7 +41,6 @@ import org.mozilla.fenix.helpers.TestHelper.returnToBrowser import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.browserScreen -import org.mozilla.fenix.ui.robots.clickTabCrashedRestoreButton import org.mozilla.fenix.ui.robots.collectionRobot import org.mozilla.fenix.ui.robots.customTabScreen import org.mozilla.fenix.ui.robots.enhancedTrackingProtection 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 0c019b535800..2745bda4603b 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 @@ -50,6 +50,8 @@ import org.mozilla.fenix.helpers.ext.waitNotNull class BrowserRobot { private lateinit var sessionLoadedIdlingResource: SessionLoadedIdlingResource + fun waitForPageToLoad() = progressBar.waitUntilGone(waitingTime) + fun verifyCurrentPrivateSession(context: Context) { val selectedTab = context.components.core.store.state.selectedTab assertTrue("Current session is private", selectedTab?.content?.private ?: false) @@ -541,6 +543,16 @@ class BrowserRobot { } } + fun clickTabCrashedRestoreButton() { + assertTrue( + mDevice.findObject(UiSelector().resourceId("$packageName:id/restoreTabButton")) + .waitForExists(waitingTime) + ) + + val tabCrashRestoreButton = mDevice.findObject(UiSelector().resourceIdMatches("$packageName:id/restoreTabButton")) + tabCrashRestoreButton.click() + } + class Transition { private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) private fun threeDotButton() = onView( @@ -622,7 +634,6 @@ class BrowserRobot { } fun clickTabCrashedCloseButton(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { - assertTrue( mDevice.findObject(UiSelector().resourceId("$packageName:id/closeTabButton")) .waitForExists(waitingTime) @@ -655,6 +666,42 @@ class BrowserRobot { DownloadRobot().interact() return DownloadRobot.Transition() } + + fun clickStartCameraButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { + // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions + cameraButton.waitForExists(waitingTime) + cameraButton.click() + + SitePermissionsRobot().interact() + return SitePermissionsRobot.Transition() + } + + fun clickStartMicrophoneButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { + // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions + microphoneButton.waitForExists(waitingTime) + microphoneButton.click() + + SitePermissionsRobot().interact() + return SitePermissionsRobot.Transition() + } + + fun clickOpenNotificationButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { + // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions + notificationButton.waitForExists(waitingTime) + notificationButton.click() + + SitePermissionsRobot().interact() + return SitePermissionsRobot.Transition() + } + + fun clickGetLocationButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { + // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions + getLocationButton.waitForExists(waitingTime) + getLocationButton.click() + + SitePermissionsRobot().interact() + return SitePermissionsRobot.Transition() + } } } @@ -699,13 +746,17 @@ private fun mediaPlayerPlayButton() = .text("Play") ) -fun clickTabCrashedRestoreButton() { - - assertTrue( - mDevice.findObject(UiSelector().resourceId("$packageName:id/restoreTabButton")) - .waitForExists(waitingTime) +private var progressBar = + mDevice.findObject( + UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_progress") ) - val tabCrashRestoreButton = mDevice.findObject(UiSelector().resourceIdMatches("$packageName:id/restoreTabButton")) - tabCrashRestoreButton.click() -} +// Permissions test page elements & prompts +// Test page used located at https://mozilla-mobile.github.io/testapp/permissions +private val cameraButton = mDevice.findObject(UiSelector().text("Open camera")) + +private val microphoneButton = mDevice.findObject(UiSelector().text("Open microphone")) + +private val notificationButton = mDevice.findObject(UiSelector().text("Open notifications dialogue")) + +private val getLocationButton = mDevice.findObject(UiSelector().text("Get Location")) 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 new file mode 100644 index 000000000000..9b52c73a97ba --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt @@ -0,0 +1,118 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui.robots + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.uiautomator.UiSelector +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.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 verifyMicrophonePermissionPrompt(url: String) { + assertTrue( + mDevice.findObject(UiSelector().text("Allow $url to use your microphone?")) + .waitForExists(waitingTime) + ) + assertTrue(denyPagePermissionButton.text.equals("Don’t allow")) + assertTrue(allowPagePermissionButton.text.equals("Allow")) + } + + fun verifyCameraPermissionPrompt(url: String) { + assertTrue( + mDevice.findObject(UiSelector().text("Allow $url to use your camera?")) + .waitForExists(waitingTime) + ) + assertTrue(denyPagePermissionButton.text.equals("Don’t allow")) + assertTrue(allowPagePermissionButton.text.equals("Allow")) + } + + fun verifyLocationPermissionPrompt(url: String) { + assertTrue( + mDevice.findObject(UiSelector().text("Allow $url to use your location?")) + .waitForExists(waitingTime) + ) + assertTrue(denyPagePermissionButton.text.equals("Don’t allow")) + assertTrue(allowPagePermissionButton.text.equals("Allow")) + } + + fun verifyNotificationsPermissionPrompt(url: String, blocked: Boolean = false) { + if (!blocked) { + assertTrue( + mDevice.findObject(UiSelector().text("Allow $url to send notifications?")) + .waitForExists(waitingTime) + ) + assertTrue(denyPagePermissionButton.text.equals("Never")) + assertTrue(allowPagePermissionButton.text.equals("Always")) + } else { + /* if "Never" was selected in a previous step, or if the app is not allowed, + the Notifications permission prompt won't be displayed anymore */ + assertFalse( + mDevice.findObject(UiSelector().text("Allow $url to send notifications?")) + .exists() + ) + } + } + + fun selectRememberPermissionDecision() { + onView(withId(R.id.do_not_ask_again)) + .check(matches(isDisplayed())) + .click() + } + + class Transition { + fun clickPagePermissionButton(allow: Boolean, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + if (allow) { + allowPagePermissionButton.waitForExists(waitingTime) + allowPagePermissionButton.click() + // sometimes flaky, the prompt is not dismissed, retrying + if(!allowPagePermissionButton.waitUntilGone(waitingTime)) { + allowPagePermissionButton.click() + } + } else { + denyPagePermissionButton.waitForExists(waitingTime) + denyPagePermissionButton.click() + // sometimes flaky, the prompt is not dismissed, retrying + if(!denyPagePermissionButton.waitUntilGone(waitingTime)) { + denyPagePermissionButton.click() + } + } + + BrowserRobot().interact() + return BrowserRobot.Transition() + } + } +} + +// App permission prompts buttons +private val allowSystemPermissionButton = + mDevice.findObject(UiSelector().resourceId(getPermissionAllowID() + ":id/permission_allow_button")) + +private val denySystemPermissionButton = + mDevice.findObject(UiSelector().resourceId(getPermissionAllowID() + ":id/permission_deny_button")) + +// Page permission prompts buttons +private val allowPagePermissionButton = + mDevice.findObject(UiSelector().resourceId("$packageName:id/allow_button")) + +private val denyPagePermissionButton = + mDevice.findObject(UiSelector().resourceId("$packageName:id/deny_button"))