commit b596f41b60902b26eb9bf3f4cf7735fbae4bd7dd
parent a20df35f4aa93c6d111a9482927db93ecb642b84
Author: AndiAJ <andiaj@users.noreply.github.com>
Date: Thu, 30 Oct 2025 11:53:55 +0000
Bug 1996247 - New Unified Trust Panel related UI smoke tests r=aaronmt,mcarare
New "Unified Trust Panel" related smoke tests.
All 10 UI tests successfully passed 50x on Firebase ✅
I've encountered a problem and had to make some changes to the TrustPanelMiddleware because while automating these scenarios, after clicking the "Enhanced tracking protection" option, the tests failed with this error:
```
java.lang.IllegalThreadStateException: Expected thread 2 ("main"), but running on thread 167 ("pool-32-thread-1")
at org.mozilla.gecko.util.ThreadUtils.assertOnThreadComparison(ThreadUtils.java:127)
at org.mozilla.gecko.util.ThreadUtils.assertOnThread(ThreadUtils.java:93)
at org.mozilla.gecko.util.ThreadUtils.assertOnUiThread(ThreadUtils.java:84)
at org.mozilla.geckoview.GeckoRuntime.getStorageController(GeckoRuntime.java:1119)
at mozilla.components.browser.engine.gecko.GeckoTrackingProtectionExceptionStorage.add(GeckoTrackingProtectionExceptionStorage.kt:66)
at mozilla.components.feature.session.TrackingProtectionUseCases$AddExceptionUseCase.invoke(TrackingProtectionUseCases.kt:48)
at mozilla.components.feature.session.TrackingProtectionUseCases$AddExceptionUseCase.invoke$default(TrackingProtectionUseCases.kt:44)
at org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelMiddleware$toggleTrackingProtection$1.invokeSuspend(TrustPanelMiddleware.kt:92)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:52)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor$FrameDeferredContinuation.resumeWith(FrameDeferringContinuationInterceptor.jvm.kt:187)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:279)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:358)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:134)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:53)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:44)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
at org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelMiddleware.toggleTrackingProtection(TrustPanelMiddleware.kt:89)
at org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelMiddleware.invoke(TrustPanelMiddleware.kt:73)
at org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelMiddleware.invoke(TrustPanelMiddleware.kt:49)
at mozilla.components.lib.state.internal.ReducerChainBuilder.build$lambda$2$0(ReducerChainBuilder.kt:62)
at mozilla.components.lib.state.internal.ReducerChainBuilder.$r8$lambda$qHkQY5kClmN8JcchHLSDzKdcDSM(Unknown Source:0)
at mozilla.components.lib.state.internal.ReducerChainBuilder$$ExternalSyntheticLambda2.invoke(D8$$SyntheticClass:0)
at mozilla.components.lib.state.internal.ReducerChainBuilder.build$lambda$1(ReducerChainBuilder.kt:57)
at mozilla.components.lib.state.internal.ReducerChainBuilder.$r8$lambda$6MYQUAWlO75P4JJe4GYUjKauyKM(Unknown Source:0)
at mozilla.components.lib.state.internal.ReducerChainBuilder$$ExternalSyntheticLambda1.invoke(D8$$SyntheticClass:0)
at mozilla.components.lib.state.internal.ReducerChainBuilder.build$lambda$2$0(ReducerChainBuilder.kt:62)
at mozilla.components.lib.state.internal.ReducerChainBuilder.$r8$lambda$qHkQY5kClmN8JcchHLSDzKdcDSM(Unknown Source:0)
at mozilla.components.lib.state.internal.ReducerChainBuilder$$ExternalSyntheticLambda2.invoke(D8$$SyntheticClass:0)
at mozilla.components.lib.state.Store$dispatch$1.invokeSuspend(Store.kt:96)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
```
Differential Revision: https://phabricator.services.mozilla.com/D269952
Diffstat:
5 files changed, 604 insertions(+), 2 deletions(-)
diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/UnifiedTrustPanelTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/UnifiedTrustPanelTest.kt
@@ -0,0 +1,416 @@
+/* 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/. */
+
+@file:Suppress("DEPRECATION")
+
+package org.mozilla.fenix.ui
+
+import androidx.compose.ui.test.junit4.AndroidComposeTestRule
+import androidx.core.net.toUri
+import androidx.test.rule.ActivityTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.mozilla.fenix.IntentReceiverActivity
+import org.mozilla.fenix.customannotations.SmokeTest
+import org.mozilla.fenix.ext.settings
+import org.mozilla.fenix.helpers.DataGenerationHelper.createCustomTabIntent
+import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
+import org.mozilla.fenix.helpers.TestAssetHelper.getEnhancedTrackingProtectionAsset
+import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset
+import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong
+import org.mozilla.fenix.helpers.TestHelper.appContext
+import org.mozilla.fenix.helpers.TestSetup
+import org.mozilla.fenix.helpers.perf.DetectMemoryLeaksRule
+import org.mozilla.fenix.ui.robots.browserScreen
+import org.mozilla.fenix.ui.robots.customTabScreen
+import org.mozilla.fenix.ui.robots.navigationToolbar
+
+class UnifiedTrustPanelTest : TestSetup() {
+ @get:Rule
+ val composeTestRule =
+ AndroidComposeTestRule(
+ HomeActivityIntentTestRule(
+ isUnifiedTrustPanelEnabled = true,
+ isComposableToolbarEnabled = false,
+ isPWAsPromptEnabled = false,
+ ),
+ ) { it.activity }
+
+ @get:Rule
+ val intentReceiverActivityTestRule = ActivityTestRule(
+ IntentReceiverActivity::class.java,
+ true,
+ false,
+ )
+
+ @get:Rule
+ val memoryLeaksRule = DetectMemoryLeaksRule()
+
+ // TestRail: https://mozilla.testrail.io/index.php?/cases/view/3186718
+ @SmokeTest
+ @Test
+ fun verifySecurePageConnectionFromQuickSettingsWithNoTrackersTest() {
+ val firstPage = "https://mozilla-mobile.github.io/testapp"
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(firstPage.toUri()) {
+ verifyPageContent("Lets test!")
+ }
+ navigationToolbar {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = "Test App",
+ webSiteURL = firstPage.toUri().host.toString(),
+ isTheWebSiteSecure = true,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = false,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = "Test App",
+ webSiteURL = firstPage.toUri().host.toString(),
+ isEnhancedTrackingProtectionEnabled = false,
+ isTheWebSiteSecure = true,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186721
+ @SmokeTest
+ @Test
+ fun verifyInsecurePageConnectionFromQuickSettingsWithTrackersTest() {
+ appContext.settings().setStrictETP()
+ val genericPage = getGenericAsset(mockWebServer, 1)
+ val trackingProtectionPage = getEnhancedTrackingProtectionAsset(mockWebServer).url
+
+ // browsing a generic page to allow GV to load on a fresh run
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(genericPage.url) {
+ }.openTabDrawer(composeTestRule) {
+ closeTab()
+ }
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(trackingProtectionPage) {
+ verifyTrackingProtectionWebContent("social blocked")
+ verifyTrackingProtectionWebContent("ads blocked")
+ verifyTrackingProtectionWebContent("analytics blocked")
+ verifyTrackingProtectionWebContent("Fingerprinting blocked")
+ verifyTrackingProtectionWebContent("Cryptomining blocked")
+ }
+ navigationToolbar {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = trackingProtectionPage.host.toString(),
+ webSiteURL = trackingProtectionPage.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = true,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = trackingProtectionPage.host.toString(),
+ webSiteURL = trackingProtectionPage.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = false,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186723
+ @SmokeTest
+ @Test
+ fun verifyClearCookiesAndSiteDataFromQuickSettingsTest() {
+ val loginPage = "https://mozilla-mobile.github.io/testapp/loginForm"
+ val originWebsite = "mozilla-mobile.github.io"
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(loginPage.toUri()) {
+ waitForPageToLoad(waitingTimeLong)
+ }
+ navigationToolbar {
+ }.openUnifiedTrustPanel {
+ clickTheClearCookiesAndSiteDataButton(composeTestRule)
+ verifyTheClearCookiesAndSiteDataDialog(composeTestRule, originWebsite)
+ }
+ }
+
+ // TestRail: https://mozilla.testrail.io/index.php?/cases/view/3186719
+ @Test
+ fun verifySecurePageConnectionFromQuickSettingsWithTrackersTest() {
+ appContext.settings().setStrictETP()
+ val genericPage = getGenericAsset(mockWebServer, 1)
+ val trackingProtectionPage = "https://senglehardt.com/test/trackingprotection/test_pages/tracking_protection"
+
+ // browsing a generic page to allow GV to load on a fresh run
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(genericPage.url) {
+ }
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(trackingProtectionPage.toUri()) {
+ verifyPageContent("Tracker Blocking")
+ }
+ navigationToolbar {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = trackingProtectionPage.toUri().host.toString(),
+ webSiteURL = trackingProtectionPage.toUri().host.toString(),
+ isTheWebSiteSecure = true,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = true,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = trackingProtectionPage.toUri().host.toString(),
+ webSiteURL = trackingProtectionPage.toUri().host.toString(),
+ isEnhancedTrackingProtectionEnabled = false,
+ isTheWebSiteSecure = true,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = true,
+ )
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186720
+ @Test
+ fun verifyInsecurePageConnectionFromQuickSettingsWithNoTrackersTest() {
+ val genericPage = getGenericAsset(mockWebServer, 1)
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(genericPage.url) {
+ verifyPageContent(genericPage.content)
+ }
+ navigationToolbar {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = genericPage.title,
+ webSiteURL = genericPage.url.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = false,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = genericPage.title,
+ webSiteURL = genericPage.url.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = false,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+
+ // TestRail: https://mozilla.testrail.io/index.php?/cases/view/3186709
+ @Test
+ fun verifySecurePageConnectionFromQuickSettingsWithNoTrackersInCustomTabsTest() {
+ val customTabPage = "https://mozilla-mobile.github.io/testapp"
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = customTabPage,
+ ),
+ )
+
+ browserScreen {
+ verifyPageContent("Lets test!")
+ }
+
+ customTabScreen {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = "Test App",
+ webSiteURL = customTabPage.toUri().host.toString(),
+ isTheWebSiteSecure = true,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = false,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = "Test App",
+ webSiteURL = customTabPage.toUri().host.toString(),
+ isEnhancedTrackingProtectionEnabled = false,
+ isTheWebSiteSecure = true,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+
+ // TestRail: https://mozilla.testrail.io/index.php?/cases/view/3186710
+ @SmokeTest
+ @Test
+ fun verifySecurePageConnectionFromQuickSettingsWithTrackersInCustomTabsTest() {
+ appContext.settings().setStrictETP()
+ val genericPage = getGenericAsset(mockWebServer, 1)
+ val customTabPage = "https://senglehardt.com/test/trackingprotection/test_pages/tracking_protection"
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = genericPage.url.toString(),
+ ),
+ )
+
+ browserScreen {
+ verifyPageContent(genericPage.content)
+ }
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = customTabPage,
+ ),
+ )
+
+ browserScreen {
+ verifyPageContent("Tracker Blocking")
+ }
+ customTabScreen {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.toUri().host.toString(),
+ webSiteURL = customTabPage.toUri().host.toString(),
+ isTheWebSiteSecure = true,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = true,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.toUri().host.toString(),
+ webSiteURL = customTabPage.toUri().host.toString(),
+ isEnhancedTrackingProtectionEnabled = false,
+ isTheWebSiteSecure = true,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = true,
+ )
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186711
+ @SmokeTest
+ @Test
+ fun verifyInsecurePageConnectionFromQuickSettingsWithNoTrackersInCustomTabsTest() {
+ val customTabPage = getGenericAsset(mockWebServer, 1)
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = customTabPage.url.toString(),
+ ),
+ )
+
+ browserScreen {
+ verifyPageContent(customTabPage.content)
+ }
+
+ customTabScreen {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.title,
+ webSiteURL = customTabPage.url.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = false,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.title,
+ webSiteURL = customTabPage.url.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = false,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186714
+ @SmokeTest
+ @Test
+ fun verifyClearCookiesAndSiteDataFromQuickSettingsInCustomTabsTest() {
+ val customTabPage = "https://mozilla-mobile.github.io/testapp/loginForm"
+ val originWebsite = "mozilla-mobile.github.io"
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = customTabPage,
+ ),
+ )
+
+ customTabScreen {
+ waitForPageToLoad(waitingTimeLong)
+ }.openUnifiedTrustPanel {
+ clickTheClearCookiesAndSiteDataButton(composeTestRule)
+ verifyTheClearCookiesAndSiteDataDialog(composeTestRule, originWebsite)
+ }
+ }
+
+ // TestRail link: https://mozilla.testrail.io/index.php?/cases/view/3186712
+ @Test
+ fun verifyInsecurePageConnectionFromQuickSettingsWithTrackersInCustomTabsTest() {
+ appContext.settings().setStrictETP()
+
+ val customTabPage = getEnhancedTrackingProtectionAsset(mockWebServer).url
+
+ intentReceiverActivityTestRule.launchActivity(
+ createCustomTabIntent(
+ pageUrl = customTabPage.toString(),
+ ),
+ )
+
+ browserScreen {
+ verifyTrackingProtectionWebContent("social blocked")
+ verifyTrackingProtectionWebContent("ads blocked")
+ verifyTrackingProtectionWebContent("analytics blocked")
+ verifyTrackingProtectionWebContent("Fingerprinting blocked")
+ verifyTrackingProtectionWebContent("Cryptomining blocked")
+ }
+ customTabScreen {
+ }.openUnifiedTrustPanel {
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.host.toString(),
+ webSiteURL = customTabPage.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = true,
+ isTrackerBlockingEnabled = true,
+ areTrackersBlocked = true,
+ )
+ clickTheEnhancedTrackingProtectionOption(composeTestRule)
+ verifyUnifiedTrustPanelItems(
+ composeTestRule = composeTestRule,
+ webSite = customTabPage.host.toString(),
+ webSiteURL = customTabPage.host.toString(),
+ isTheWebSiteSecure = false,
+ isEnhancedTrackingProtectionEnabled = false,
+ isTrackerBlockingEnabled = false,
+ areTrackersBlocked = false,
+ )
+ }
+ }
+}
diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt
@@ -5,6 +5,7 @@ package org.mozilla.fenix.ui.robots
import android.net.Uri
import android.util.Log
+import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
@@ -388,6 +389,18 @@ class CustomTabRobot {
BrowserRobot().interact()
return BrowserRobot.Transition()
}
+
+ fun openUnifiedTrustPanel(interact: UnifiedTrustPanelRobot.() -> Unit): UnifiedTrustPanelRobot.Transition {
+ Log.i(TAG, "openUnifiedTrustPanel: Waiting for $waitingTime ms for site security button to exist")
+ itemWithResId("$packageName:id/mozac_browser_toolbar_site_info_indicator").waitForExists(waitingTime)
+ Log.i(TAG, "openUnifiedTrustPanel: Waited for $waitingTime ms for site security button to exist")
+ Log.i(TAG, "openUnifiedTrustPanel: Trying to click site security button")
+ itemWithResId("$packageName:id/mozac_browser_toolbar_site_info_indicator").click()
+ Log.i(TAG, "openUnifiedTrustPanel: Clicked site security button")
+
+ UnifiedTrustPanelRobot().interact()
+ return UnifiedTrustPanelRobot.Transition()
+ }
}
}
diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt
@@ -647,6 +647,21 @@ class NavigationToolbarRobot {
SearchRobot().interact()
return SearchRobot.Transition()
}
+
+ fun openUnifiedTrustPanel(interact: UnifiedTrustPanelRobot.() -> Unit): UnifiedTrustPanelRobot.Transition {
+ Log.i(TAG, "openUnifiedTrustPanel: Waiting for $waitingTime ms for site security button to exist")
+ itemWithResId("$packageName:id/mozac_browser_toolbar_site_info_indicator").waitForExists(waitingTime)
+ Log.i(TAG, "openUnifiedTrustPanel: Waited for $waitingTime ms for site security button to exist")
+ Log.i(TAG, "openUnifiedTrustPanel: Trying to click site security button")
+ itemWithResId("$packageName:id/mozac_browser_toolbar_site_info_indicator").click()
+ Log.i(TAG, "openUnifiedTrustPanel: Clicked site security button")
+ Log.i(TAG, "openUnifiedTrustPanel: Waiting for $waitingTime for the unified trust panel to exist")
+ itemWithResId("$packageName:id/design_bottom_sheet").waitForExists(waitingTime)
+ Log.i(TAG, "openUnifiedTrustPanel: Waited for $waitingTime for the unified trust panel to exist")
+
+ UnifiedTrustPanelRobot().interact()
+ return UnifiedTrustPanelRobot.Transition()
+ }
}
}
diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/UnifiedTrustPanelRobot.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/UnifiedTrustPanelRobot.kt
@@ -0,0 +1,158 @@
+package org.mozilla.fenix.ui.robots
+
+import android.util.Log
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.ComposeTestRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.core.text.HtmlCompat
+import org.mozilla.fenix.R
+import org.mozilla.fenix.helpers.Constants.TAG
+import org.mozilla.fenix.helpers.DataGenerationHelper.getStringResource
+import org.mozilla.fenix.helpers.TestHelper.appName
+import org.mozilla.fenix.helpers.TestHelper.waitForAppWindowToBeUpdated
+
+class UnifiedTrustPanelRobot {
+
+ fun verifyUnifiedTrustPanelItems(
+ composeTestRule: ComposeTestRule,
+ webSite: String,
+ webSiteURL: String,
+ isTheWebSiteSecure: Boolean,
+ isEnhancedTrackingProtectionEnabled: Boolean,
+ isTrackerBlockingEnabled: Boolean,
+ areTrackersBlocked: Boolean,
+ ) {
+ waitForAppWindowToBeUpdated()
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Trying to verify that the web site title: $webSite is displayed")
+ composeTestRule.onNodeWithText(webSite, useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Verified that the web site title: $webSite is displayed")
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Trying to verify that the web site url: $webSiteURL is displayed")
+ composeTestRule.onNodeWithText(webSiteURL, useUnmergedTree = true, substring = true).assertIsDisplayed()
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Verified that the web site url: $webSiteURL is displayed")
+ verifyTheEnhancedTrackingProtectionState(composeTestRule, isEnhancedTrackingProtectionEnabled, isTheWebSiteSecure)
+ verifyTheTrackersBlockedOptionState(composeTestRule, isTrackerBlockingEnabled, areTrackersBlocked)
+ verifyTheSiteSecurityOption(composeTestRule, isTheWebSiteSecure)
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Trying to verify that the \"Clear cookies and site data\" option is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.clear_site_data), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Verified that the \"Clear cookies and site data\" option is displayed")
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Trying to verify that the \"Privacy settings\" hyperlink is displayed")
+ composeTestRule.onNodeWithContentDescription("Privacy Settings Links available", useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyUnifiedTrustPanelItems: Verified that the \"Privacy settings\" hyperlink is displayed")
+ }
+
+ fun verifyTheEnhancedTrackingProtectionState(composeTestRule: ComposeTestRule, isEnhancedTrackingProtectionEnabled: Boolean, isTheWebSiteSecure: Boolean) {
+ if (isEnhancedTrackingProtectionEnabled) {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that \"Enhanced tracking protection\" is enabled")
+ if (isTheWebSiteSecure) {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the website is secure")
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"$appName is on guard\" banner title and message are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_protected_title, argument = appName), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_protected_description), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"$appName is on guard\" banner title and message are displayed")
+ } else {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the website is not secure")
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"Be careful on this site\" banner title and message are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_secure_title, argument = appName), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_secure_description), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"Be careful on this site\" banner title and message are displayed")
+ }
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"Enhanced tracking protection\" option, message and \"On\" state are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_label), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_enabled_description_2), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_on), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"Enhanced tracking protection\" option, message and \"On\" state are displayed")
+ } else {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that \"Enhanced tracking protection\" is not enabled")
+ if (isTheWebSiteSecure) {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the website is secure")
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"You turned off protection\" banner title and message are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_protected_title), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_protected_description, argument = appName), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"You turned off protection\" banner title and message are displayed")
+ } else {
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the website is not secure")
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"Be careful on this site\" banner title and message are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_secure_title, argument = appName), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_banner_not_secure_description), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"Be careful on this site\" banner title and message are displayed")
+ }
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Trying to verify that the \"Enhanced tracking protection\" option, message and \"Off\" state are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_label), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_disabled_description_2), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_off), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheEnhancedTrackingProtectionState: Verified that the \"Enhanced tracking protection\" option, message and \"Off\" state are displayed")
+ }
+ }
+
+ fun verifyTheTrackersBlockedOptionState(composeTestRule: ComposeTestRule, isTrackerBlockingEnabled: Boolean, areTrackersBlocked: Boolean) {
+ if (isTrackerBlockingEnabled) {
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that the tracker blocking is enabled")
+ if (areTrackersBlocked) {
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that trackers are blocked")
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Trying to verify that the \"Trackers blocked\" option is displayed")
+ composeTestRule.onNodeWithText("Trackers blocked:", useUnmergedTree = true, substring = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that the \"Trackers blocked\" option is displayed")
+ } else {
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Trying to verify that the \"No trackers found\" option is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_no_trackers_blocked), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that the \"No trackers found\" option is displayed")
+ }
+ } else {
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that the tracker blocking is not enabled")
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Trying to verify that the \"Trackers aren't blocked\" option is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_disabled_no_trackers_blocked), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheTrackersBlockedOptionState: Verified that the \"Trackers aren't blocked\" option is displayed")
+ }
+ }
+
+ fun verifyTheSiteSecurityOption(composeTestRule: ComposeTestRule, isTheWebSiteSecure: Boolean) {
+ if (isTheWebSiteSecure) {
+ Log.i(TAG, "verifyTheSiteSecurityOption: Verified that the web site is secure")
+ Log.i(TAG, "verifyTheSiteSecurityOption: Trying to verify that the \"Secure connection\" option and \"Verified by\" description are displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.connection_security_panel_secure), useUnmergedTree = true).assertIsDisplayed()
+ composeTestRule.onNodeWithText("Verified by", useUnmergedTree = true, substring = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheSiteSecurityOption: Verified that the \"Secure connection\" option and \"Verified by\" description are displayed")
+ } else {
+ Log.i(TAG, "verifyTheSiteSecurityOption: Verified that the web site is not secure")
+ Log.i(TAG, "verifyTheSiteSecurityOption: Trying to verify that the \"Connection not secure\" option is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.connection_security_panel_not_secure), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheSiteSecurityOption: Verified that the \"Connection not secure\" option is displayed")
+ }
+ }
+
+ fun clickTheEnhancedTrackingProtectionOption(composeTestRule: ComposeTestRule) {
+ Log.i(TAG, "clickTheEnhancedTrackingProtectionOption: Trying to click the ETP option")
+ composeTestRule.onNodeWithText(getStringResource(R.string.protection_panel_etp_toggle_label), useUnmergedTree = true).performClick()
+ Log.i(TAG, "clickTheEnhancedTrackingProtectionOption: Clicked the ETP option")
+ composeTestRule.waitForIdle()
+ }
+
+ fun clickTheClearCookiesAndSiteDataButton(composeTestRule: ComposeTestRule) {
+ Log.i(TAG, "clickTheClearCookiesAndSiteDataButton: Trying to click the \"Clear cookies and site data\" button")
+ composeTestRule.onNodeWithText(getStringResource(R.string.clear_site_data), useUnmergedTree = true).performClick()
+ Log.i(TAG, "clickTheClearCookiesAndSiteDataButton: Clicked the \"Clear cookies and site data\" button")
+ }
+
+ fun verifyTheClearCookiesAndSiteDataDialog(composeTestRule: ComposeTestRule, webSite: String) {
+ // convert HTML-formatted string resource to plain text
+ val clearCookiesAndSiteDataDialogRawDescription = getStringResource(R.string.clear_site_data_dialog_description, argument = webSite)
+ val clearCookiesAndSiteDataDialogConvertedDescription = HtmlCompat.fromHtml(clearCookiesAndSiteDataDialogRawDescription, HtmlCompat.FROM_HTML_MODE_LEGACY).toString()
+
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Trying to verify that the \"Clear cookies and site data\" dialog title is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.clear_site_data), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Verified that the \"Clear cookies and site data\" dialog title is displayed")
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Trying to verify that the \"Clear cookies and site data\" dialog message is displayed")
+ composeTestRule.onNodeWithText(clearCookiesAndSiteDataDialogConvertedDescription, useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Verified that the \"Clear cookies and site data\" dialog message is displayed")
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Trying to verify that the \"Clear\" dialog button is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.clear_site_data_dialog_positive_button_text), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Verified that the \"Clear\" dialog button is displayed")
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Trying to verify that the \"Cancel\" dialog button is displayed")
+ composeTestRule.onNodeWithText(getStringResource(R.string.clear_site_data_dialog_negative_button_text), useUnmergedTree = true).assertIsDisplayed()
+ Log.i(TAG, "verifyTheClearCookiesAndSiteDataDialog: Verified that the \"Cancel\" dialog button is displayed")
+ }
+
+ class Transition
+}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/middleware/TrustPanelMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/middleware/TrustPanelMiddleware.kt
@@ -56,7 +56,7 @@ class TrustPanelMiddleware(
private val permissionStorage: PermissionStorage,
private val requestPermissionsLauncher: ActivityResultLauncher<Array<String>>,
private val onDismiss: suspend () -> Unit,
- private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO),
+ private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main),
) : Middleware<TrustPanelState, TrustPanelAction> {
override fun invoke(
@@ -86,7 +86,7 @@ class TrustPanelMiddleware(
private fun toggleTrackingProtection(
currentState: TrustPanelState,
- ) = scope.launch {
+ ) = scope.launch(Dispatchers.Main) {
currentState.sessionState?.let { session ->
if (currentState.isTrackingProtectionEnabled) {
trackingProtectionUseCases.addException(session.id)