[fenix] For https://github.com/mozilla-mobile/fenix/issues/19886 - Add a back navigation to the Global Quick Settings from the Tracking Protection dialog

pull/600/head
Gabriel Luong 3 years ago committed by Arturo Mejia
parent 39dc0701a8
commit 2d6dcb814c

@ -28,8 +28,6 @@ interface ConnectionDetailsController {
/** /**
* Default behavior of [ConnectionDetailsController]. * Default behavior of [ConnectionDetailsController].
*
* @param dismiss callback allowing to request this entire Fragment to be dismissed.
*/ */
class DefaultConnectionDetailsController( class DefaultConnectionDetailsController(
private val context: Context, private val context: Context,
@ -37,9 +35,9 @@ class DefaultConnectionDetailsController(
private val navController: () -> NavController, private val navController: () -> NavController,
internal var sitePermissions: SitePermissions?, internal var sitePermissions: SitePermissions?,
private val gravity: Int, private val gravity: Int,
private val getCurrentTab: () -> SessionState?, private val getCurrentTab: () -> SessionState?
private val dismiss: () -> Unit
) : ConnectionDetailsController { ) : ConnectionDetailsController {
override fun handleBackPressed() { override fun handleBackPressed() {
getCurrentTab()?.let { tab -> getCurrentTab()?.let { tab ->
context.components.useCases.trackingProtectionUseCases.containsException(tab.id) { contains -> context.components.useCases.trackingProtectionUseCases.containsException(tab.id) { contains ->

@ -34,15 +34,16 @@ class ConnectionPanelDialogFragment : FenixDialogFragment() {
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
val rootView = inflateRootView(container) val rootView = inflateRootView(container)
val controller = DefaultConnectionDetailsController( val controller = DefaultConnectionDetailsController(
context = requireContext(), context = requireContext(),
fragment = this, fragment = this,
navController = { findNavController() }, navController = { findNavController() },
sitePermissions = args.sitePermissions, sitePermissions = args.sitePermissions,
gravity = args.gravity, gravity = args.gravity,
getCurrentTab = ::getCurrentTab, getCurrentTab = ::getCurrentTab
dismiss = ::dismiss
) )
val interactor = ConnectionDetailsInteractor(controller) val interactor = ConnectionDetailsInteractor(controller)
connectionView = WebsiteInfoView( connectionView = WebsiteInfoView(
container = rootView.connectionDetailsInfoLayout, container = rootView.connectionDetailsInfoLayout,
@ -65,7 +66,7 @@ class ConnectionPanelDialogFragment : FenixDialogFragment() {
) )
} }
internal fun getCurrentTab(): SessionState? { private fun getCurrentTab(): SessionState? {
return requireComponents.core.store.state.findTabOrCustomTab(args.sessionId) return requireComponents.core.store.state.findTabOrCustomTab(args.sessionId)
} }
} }

@ -205,7 +205,8 @@ class DefaultQuickSettingsController(
sessionId = sessionId, sessionId = sessionId,
url = state.url, url = state.url,
trackingProtectionEnabled = state.isTrackingProtectionEnabled, trackingProtectionEnabled = state.isTrackingProtectionEnabled,
gravity = context.components.settings.toolbarPosition.androidGravity gravity = context.components.settings.toolbarPosition.androidGravity,
sitePermissions = sitePermissions
) )
navController().navigate(directions) navController().navigate(directions)
} }

@ -53,7 +53,7 @@ class QuickSettingsFragmentStore(
* @param permissions [SitePermissions]? list of website permissions and their status. * @param permissions [SitePermissions]? list of website permissions and their status.
* @param settings [Settings] application settings. * @param settings [Settings] application settings.
* @param certificateName [String] the certificate name of the current web page. * @param certificateName [String] the certificate name of the current web page.
* @param sessionId [String] TODO * @param sessionId [String] The current session ID.
* @param isTrackingProtectionEnabled [Boolean] Current status of tracking protection * @param isTrackingProtectionEnabled [Boolean] Current status of tracking protection
* for this session. * for this session.
*/ */
@ -127,7 +127,7 @@ class QuickSettingsFragmentStore(
* [TrackingProtectionView]. * [TrackingProtectionView].
* *
* @param context [Context] used for various Android interactions. * @param context [Context] used for various Android interactions.
* @param sessionId [String] TODO * @param sessionId [String] The current session ID.
* @param websiteUrl [String] the URL of the current web page. * @param websiteUrl [String] the URL of the current web page.
* @param isTrackingProtectionEnabled [Boolean] Current status of tracking protection * @param isTrackingProtectionEnabled [Boolean] Current status of tracking protection
* for this session. * for this session.

@ -19,6 +19,7 @@ import androidx.appcompat.app.AppCompatDialogFragment
import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.ContextThemeWrapper
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.whenStarted import androidx.lifecycle.whenStarted
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
@ -96,8 +97,14 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
) )
} }
trackingProtectionInteractor = TrackingProtectionPanelInteractor( trackingProtectionInteractor = TrackingProtectionPanelInteractor(
trackingProtectionStore, context = requireContext(),
::openTrackingProtectionSettings fragment = this,
store = trackingProtectionStore,
navController = { findNavController() },
openTrackingProtectionSettings = ::openTrackingProtectionSettings,
sitePermissions = args.sitePermissions,
gravity = args.gravity,
getCurrentTab = ::getCurrentTab
) )
trackingProtectionView = trackingProtectionView =
TrackingProtectionPanelView(view.fragment_tp, trackingProtectionInteractor) TrackingProtectionPanelView(view.fragment_tp, trackingProtectionInteractor)
@ -219,4 +226,8 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
} }
} }
} }
private fun getCurrentTab(): SessionState? {
return requireComponents.core.store.state.findTabOrCustomTab(args.sessionId)
}
} }

@ -4,14 +4,31 @@
package org.mozilla.fenix.trackingprotection package org.mozilla.fenix.trackingprotection
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import mozilla.components.browser.state.state.SessionState
import mozilla.components.concept.engine.permission.SitePermissions
import org.mozilla.fenix.browser.BrowserFragmentDirections
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.runIfFragmentIsAttached
/** /**
* Interactor for the tracking protection panel * Interactor for the tracking protection panel
* Provides implementations for the TrackingProtectionPanelViewInteractor * Provides implementations for the TrackingProtectionPanelViewInteractor
*/ */
@Suppress("LongParameterList")
class TrackingProtectionPanelInteractor( class TrackingProtectionPanelInteractor(
private val context: Context,
private val fragment: Fragment,
private val store: TrackingProtectionStore, private val store: TrackingProtectionStore,
private val openTrackingProtectionSettings: () -> Unit private val navController: () -> NavController,
private val openTrackingProtectionSettings: () -> Unit,
internal var sitePermissions: SitePermissions?,
private val gravity: Int,
private val getCurrentTab: () -> SessionState?
) : TrackingProtectionPanelViewInteractor { ) : TrackingProtectionPanelViewInteractor {
override fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean) { override fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean) {
store.dispatch(TrackingProtectionAction.EnterDetailsMode(category, categoryBlocked)) store.dispatch(TrackingProtectionAction.EnterDetailsMode(category, categoryBlocked))
} }
@ -21,6 +38,30 @@ class TrackingProtectionPanelInteractor(
} }
override fun onBackPressed() { override fun onBackPressed() {
getCurrentTab()?.let { tab ->
context.components.useCases.trackingProtectionUseCases.containsException(tab.id) { contains ->
fragment.runIfFragmentIsAttached {
navController().popBackStack()
val isTrackingProtectionEnabled = tab.trackingProtection.enabled && !contains
val directions =
BrowserFragmentDirections.actionGlobalQuickSettingsSheetDialogFragment(
sessionId = tab.id,
url = tab.content.url,
title = tab.content.title,
isSecured = tab.content.securityInfo.secure,
sitePermissions = sitePermissions,
gravity = gravity,
certificateName = tab.content.securityInfo.issuer,
permissionHighlights = tab.content.permissionHighlights,
isTrackingProtectionEnabled = isTrackingProtectionEnabled
)
navController().navigate(directions)
}
}
}
}
override fun onExitDetailMode() {
store.dispatch(TrackingProtectionAction.ExitDetailsMode) store.dispatch(TrackingProtectionAction.ExitDetailsMode)
} }
} }

@ -9,7 +9,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityEvent
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.net.toUri
import androidx.core.view.AccessibilityDelegateCompat import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
@ -17,18 +16,16 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.component_tracking_protection_panel.* import kotlinx.android.synthetic.main.component_tracking_protection_panel.*
import kotlinx.android.synthetic.main.component_tracking_protection_panel.details_blocking_header
import mozilla.components.browser.state.state.CustomTabSessionState import mozilla.components.browser.state.state.CustomTabSessionState
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CROSS_SITE_TRACKING_COOKIES import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CROSS_SITE_TRACKING_COOKIES
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CRYPTOMINERS import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CRYPTOMINERS
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.FINGERPRINTERS import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.FINGERPRINTERS
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.REDIRECT_TRACKERS
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.SOCIAL_MEDIA_TRACKERS import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.SOCIAL_MEDIA_TRACKERS
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.TRACKING_CONTENT import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.TRACKING_CONTENT
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.REDIRECT_TRACKERS
/** /**
* Interface for the TrackingProtectionPanelViewInteractor. This interface is implemented by objects that want * Interface for the TrackingProtectionPanelViewInteractor. This interface is implemented by objects that want
@ -45,6 +42,11 @@ interface TrackingProtectionPanelViewInteractor {
*/ */
fun onBackPressed() fun onBackPressed()
/**
* Called whenever back button is pressed in Detail mode.
*/
fun onExitDetailMode()
/** /**
* Called whenever an active tracking protection category is tapped * Called whenever an active tracking protection category is tapped
* @param category The Tracking Protection Category to view details about * @param category The Tracking Protection Category to view details about
@ -76,9 +78,15 @@ class TrackingProtectionPanelView(
protection_settings.setOnClickListener { protection_settings.setOnClickListener {
interactor.selectTrackingProtectionSettings() interactor.selectTrackingProtectionSettings()
} }
details_back.setOnClickListener { details_back.setOnClickListener {
interactor.onExitDetailMode()
}
navigate_back.setOnClickListener {
interactor.onBackPressed() interactor.onBackPressed()
} }
setCategoryClickListeners() setCategoryClickListeners()
} }
@ -100,12 +108,11 @@ class TrackingProtectionPanelView(
private fun setUIForNormalMode(state: TrackingProtectionState) { private fun setUIForNormalMode(state: TrackingProtectionState) {
details_mode.visibility = View.GONE details_mode.visibility = View.GONE
normal_mode.visibility = View.VISIBLE normal_mode.visibility = View.VISIBLE
protection_settings.isGone = state.tab is CustomTabSessionState
protection_settings.isGone = state.tab is CustomTabSessionState
not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty() not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty()
bindUrl(state.url)
blocking_header.isGone = bucketedTrackers.blockedIsEmpty() blocking_header.isGone = bucketedTrackers.blockedIsEmpty()
updateCategoryVisibility() updateCategoryVisibility()
focusAccessibilityLastUsedCategory(state.lastAccessedCategory) focusAccessibilityLastUsedCategory(state.lastAccessedCategory)
} }
@ -213,10 +220,6 @@ class TrackingProtectionPanelView(
interactor.openDetails(category, categoryBlocked = !isLoaded(v)) interactor.openDetails(category, categoryBlocked = !isLoaded(v))
} }
private fun bindUrl(url: String) {
this.url.text = url.toUri().hostWithoutCommonPrefixes
}
fun onBackPressed(): Boolean { fun onBackPressed(): Boolean {
return when (mode) { return when (mode) {
is TrackingProtectionState.Mode.Details -> { is TrackingProtectionState.Mode.Details -> {

@ -45,14 +45,14 @@ sealed class TrackingProtectionAction : Action {
/** /**
* The state for the Tracking Protection Panel * The state for the Tracking Protection Panel
* @property tab TODO * @property tab Current session to display
* @property url Current URL to display * @property url Current URL to display
* @property isTrackingProtectionEnabled Current status of tracking protection for this session * @property isTrackingProtectionEnabled Current status of tracking protection for this session
* (ie is an exception) * (ie is an exception)
* @property listTrackers Current Tracker Log list of blocked and loaded tracker categories * @property listTrackers Current Tracker Log list of blocked and loaded tracker categories
* @property mode Current Mode of TrackingProtection * @property mode Current Mode of TrackingProtection
* @property lastAccessedCategory Remembers the last accessed details category, used to move * @property lastAccessedCategory Remembers the last accessed details category, used to move
* accessibly focus after returning from details_mode * accessibly focus after returning from details_mode
*/ */
data class TrackingProtectionState( data class TrackingProtectionState(
val tab: SessionState?, val tab: SessionState?,

@ -19,14 +19,29 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/navigate_back"
android:layout_width="@dimen/tracking_protection_item_height"
android:layout_height="@dimen/tracking_protection_item_height"
android:scaleType="center"
android:contentDescription="@string/etp_back_button_content_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/mozac_ic_back"
app:tint="?attr/primaryText" />
<TextView <TextView
android:id="@+id/url" android:id="@+id/details"
style="@style/QuickSettingsText" style="@style/QuickSettingsLargeText"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="@dimen/tracking_protection_item_height" android:layout_height="@dimen/tracking_protection_item_height"
app:layout_constraintStart_toStartOf="parent" android:paddingStart="0dp"
android:paddingEnd="0dp"
android:textColor="?attr/primaryText"
app:fontFamily="@font/metropolis_semibold"
app:layout_constraintStart_toEndOf="@+id/navigate_back"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="https://wikipedia.org" /> android:text="@string/enhanced_tracking_protection_details" />
<TextView <TextView
android:id="@+id/blocking_header" android:id="@+id/blocking_header"
@ -39,7 +54,7 @@
android:textStyle="bold" android:textStyle="bold"
android:visibility="gone" android:visibility="gone"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/url" app:layout_constraintTop_toBottomOf="@id/details"
tools:targetApi="p" /> tools:targetApi="p" />
<TextView <TextView
@ -210,6 +225,7 @@
android:layout_marginEnd="19dp" android:layout_marginEnd="19dp"
android:textColor="?attr/primaryText" android:textColor="?attr/primaryText"
android:textSize="16sp" android:textSize="16sp"
app:fontFamily="@font/metropolis_semibold"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" /> tools:text="@tools:sample/lorem" />

@ -21,8 +21,6 @@
app:switchIcon="@drawable/ic_tracking_protection" app:switchIcon="@drawable/ic_tracking_protection"
app:switchTitle="@string/preference_enhanced_tracking_protection" /> app:switchTitle="@string/preference_enhanced_tracking_protection" />
<!-- TODO: Match drawablePadding with Design Spec. Using @style/QuickSettingsText.Icon as a placeholder -->
<!-- TODO: Match layout_height with Design Spec. Using @dimen/quicksettings_item_height as a placeholder -->
<TextView <TextView
android:id="@+id/trackingProtectionBlockedItems" android:id="@+id/trackingProtectionBlockedItems"
style="@style/QuickSettingsText.Icon" style="@style/QuickSettingsText.Icon"

@ -812,6 +812,10 @@
android:name="gravity" android:name="gravity"
android:defaultValue="80" android:defaultValue="80"
app:argType="integer" /> app:argType="integer" />
<argument
android:name="sitePermissions"
app:argType="mozilla.components.concept.engine.permission.SitePermissions"
app:nullable="true" />
</dialog> </dialog>
<dialog <dialog
android:id="@+id/connectionPanelDialogFragment" android:id="@+id/connectionPanelDialogFragment"

@ -25,7 +25,6 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.navigateBlockingForAsyncNavGraph
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@ -43,9 +42,6 @@ class DefaultConnectionDetailsControllerTest {
@MockK(relaxed = true) @MockK(relaxed = true)
private lateinit var sitePermissions: SitePermissions private lateinit var sitePermissions: SitePermissions
@MockK(relaxed = true)
private lateinit var dismiss: () -> Unit
private lateinit var controller: DefaultConnectionDetailsController private lateinit var controller: DefaultConnectionDetailsController
private lateinit var tab: TabSessionState private lateinit var tab: TabSessionState
@ -64,8 +60,7 @@ class DefaultConnectionDetailsControllerTest {
navController = { navController }, navController = { navController },
sitePermissions = sitePermissions, sitePermissions = sitePermissions,
gravity = gravity, gravity = gravity,
getCurrentTab = { tab }, getCurrentTab = { tab }
dismiss = dismiss
) )
every { fragment.context } returns context every { fragment.context } returns context
@ -87,7 +82,7 @@ class DefaultConnectionDetailsControllerTest {
verify { verify {
navController.popBackStack() navController.popBackStack()
navController.navigateBlockingForAsyncNavGraph(any<NavDirections>()) navController.navigate(any<NavDirections>())
} }
} }
} }

@ -6,15 +6,15 @@ package org.mozilla.fenix.settings.quicksettings
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coVerifyOrder import io.mockk.coVerifyOrder
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScope import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runBlockingTest
@ -22,9 +22,9 @@ import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.concept.engine.permission.SitePermissions
import mozilla.components.concept.engine.permission.SitePermissions.Status.NO_DECISION import mozilla.components.concept.engine.permission.SitePermissions.Status.NO_DECISION
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.session.TrackingProtectionUseCases import mozilla.components.feature.session.TrackingProtectionUseCases
import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.feature.tabs.TabsUseCases
import mozilla.components.support.test.mock import mozilla.components.support.test.mock
@ -43,7 +43,6 @@ import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.directionsEq import org.mozilla.fenix.ext.directionsEq
import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.navigateBlockingForAsyncNavGraph
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
@ -376,7 +375,7 @@ class DefaultQuickSettingsControllerTest {
verify { verify {
navController.popBackStack() navController.popBackStack()
navController.navigateBlockingForAsyncNavGraph(any<NavDirections>()) navController.navigate(any<NavDirections>())
} }
} }
@ -400,7 +399,7 @@ class DefaultQuickSettingsControllerTest {
verify { verify {
navController.popBackStack() navController.popBackStack()
navController.navigateBlockingForAsyncNavGraph(any<NavDirections>()) navController.navigate(any<NavDirections>())
} }
} }
} }

@ -4,19 +4,89 @@
package org.mozilla.fenix.trackingprotection package org.mozilla.fenix.trackingprotection
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk import io.mockk.mockk
import io.mockk.slot
import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import org.junit.Test import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab
import mozilla.components.concept.engine.permission.SitePermissions
import mozilla.components.feature.session.TrackingProtectionUseCases
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
class TrackingProtectionPanelInteractorTest { class TrackingProtectionPanelInteractorTest {
private lateinit var context: Context
@MockK(relaxed = true)
private lateinit var navController: NavController
@MockK(relaxed = true)
private lateinit var fragment: Fragment
@MockK(relaxed = true)
private lateinit var sitePermissions: SitePermissions
@MockK(relaxed = true)
private lateinit var store: TrackingProtectionStore
private lateinit var interactor: TrackingProtectionPanelInteractor
private lateinit var tab: TabSessionState
private var openSettings = false
private var gravity = 54
@Before
fun setup() {
MockKAnnotations.init(this)
context = spyk(testContext)
tab = createTab("https://mozilla.org")
interactor = TrackingProtectionPanelInteractor(
context = context,
fragment = fragment,
store = store,
navController = { navController },
openTrackingProtectionSettings = { openSettings = true },
sitePermissions = sitePermissions,
gravity = gravity,
getCurrentTab = { tab }
)
val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true)
every { fragment.context } returns context
every { context.components.useCases.trackingProtectionUseCases } returns trackingProtectionUseCases
val onComplete = slot<(Boolean) -> Unit>()
every {
trackingProtectionUseCases.containsException.invoke(
any(),
capture(onComplete)
)
}.answers { onComplete.captured.invoke(true) }
}
@Test @Test
fun openDetails() { fun `WHEN openDetails is called THEN store should dispatch EnterDetailsMode action with the right category`() {
val store: TrackingProtectionStore = mockk(relaxed = true) interactor.openDetails(TrackingProtectionCategory.FINGERPRINTERS, true, {}, {})
val interactor = TrackingProtectionPanelInteractor(store, {}, {})
interactor.openDetails(TrackingProtectionCategory.FINGERPRINTERS, true)
verify { verify {
store.dispatch( store.dispatch(
TrackingProtectionAction.EnterDetailsMode( TrackingProtectionAction.EnterDetailsMode(
@ -25,14 +95,9 @@ class TrackingProtectionPanelInteractorTest {
) )
) )
} }
}
@Test
fun openDetailsForRedirectTrackers() {
val store: TrackingProtectionStore = mockk(relaxed = true)
val interactor =
TrackingProtectionPanelInteractor(store, {}, {})
interactor.openDetails(TrackingProtectionCategory.REDIRECT_TRACKERS, true) interactor.openDetails(TrackingProtectionCategory.REDIRECT_TRACKERS, true)
verify { verify {
store.dispatch( store.dispatch(
TrackingProtectionAction.EnterDetailsMode( TrackingProtectionAction.EnterDetailsMode(
@ -44,23 +109,27 @@ class TrackingProtectionPanelInteractorTest {
} }
@Test @Test
fun selectTrackingProtectionSettings() { fun `WHEN selectTrackingProtectionSettings is called THEN openTrackingProtectionSettings should be invoked`() {
var openSettings = false
val interactor = TrackingProtectionPanelInteractor(
mockk(),
{ },
{ openSettings = true }
)
interactor.selectTrackingProtectionSettings() interactor.selectTrackingProtectionSettings()
assertEquals(true, openSettings) assertEquals(true, openSettings)
} }
@Test @Test
fun onBackPressed() { fun `WHEN onBackPressed is called THEN call popBackStack and navigate`() {
val store: TrackingProtectionStore = mockk(relaxed = true)
val interactor =
TrackingProtectionPanelInteractor(store, {}, {})
interactor.onBackPressed() interactor.onBackPressed()
verify {
navController.popBackStack()
navController.navigate(any<NavDirections>())
}
}
@Test
fun `WHEN onExitDetailMode is called THEN store should dispatch ExitDetailsMode action`() {
interactor.onExitDetailMode()
verify { store.dispatch(TrackingProtectionAction.ExitDetailsMode) } verify { store.dispatch(TrackingProtectionAction.ExitDetailsMode) }
} }
} }

@ -87,8 +87,14 @@ class TrackingProtectionPanelViewTest {
} }
@Test @Test
fun testDetailsBack() { fun testExistDetailModed() {
view.details_back.performClick() view.details_back.performClick()
verify { interactor.onExitDetailMode() }
}
@Test
fun testDetailsBack() {
view.navigate_back.performClick()
verify { interactor.onBackPressed() } verify { interactor.onBackPressed() }
} }

Loading…
Cancel
Save