[fenix] For https://github.com/mozilla-mobile/fenix/issues/19886 - Handle toggling tracking protection in quick settings

pull/600/head
Gabriel Luong 3 years ago committed by Arturo Mejia
parent 23d57b151f
commit 9bb39fe7b3

@ -18,7 +18,9 @@ import mozilla.components.support.base.feature.OnNeedToRequestPermissions
import mozilla.components.support.ktx.kotlin.getOrigin import mozilla.components.support.ktx.kotlin.getOrigin
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.PermissionStorage import org.mozilla.fenix.components.PermissionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
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
@ -169,7 +171,24 @@ class DefaultQuickSettingsController(
} }
override fun handleTrackingProtectionToggled(isEnabled: Boolean) { override fun handleTrackingProtectionToggled(isEnabled: Boolean) {
TODO("Not yet implemented") val components = context.components
val sessionState = components.core.store.state.findTabOrCustomTab(sessionId)
sessionState?.let { session ->
val trackingProtectionUseCases = components.useCases.trackingProtectionUseCases
val sessionUseCases = components.useCases.sessionUseCases
if (isEnabled) {
trackingProtectionUseCases.removeException(session.id)
} else {
context.metrics.track(Event.TrackingProtectionException)
trackingProtectionUseCases.addException(session.id)
}
sessionUseCases.reload.invoke(session.id)
}
quickSettingsStore.dispatch(TrackingProtectionAction.ToggleTrackingProtectionEnabled(isEnabled))
} }
override fun handleBlockedItemsClicked() { override fun handleBlockedItemsClicked() {

@ -6,6 +6,7 @@ package org.mozilla.fenix.settings.quicksettings
import mozilla.components.lib.state.Action import mozilla.components.lib.state.Action
import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.trackingprotection.TrackingProtectionState
/** /**
* Parent [Action] for all the [QuickSettingsFragmentState] changes. * Parent [Action] for all the [QuickSettingsFragmentState] changes.
@ -46,3 +47,16 @@ sealed class WebsitePermissionAction(open val updatedFeature: PhoneFeature) : Qu
val autoplayValue: AutoplayValue val autoplayValue: AutoplayValue
) : WebsitePermissionAction(PhoneFeature.AUTOPLAY) ) : WebsitePermissionAction(PhoneFeature.AUTOPLAY)
} }
/**
* All possible [TrackingProtectionState] changes as a result oof user / system interactions.
*/
sealed class TrackingProtectionAction : QuickSettingsFragmentAction() {
/**
* Toggles the enabled state of tracking protection.
*
* @param isTrackingProtectionEnabled Whether or not tracking protection is enabled.
*/
data class ToggleTrackingProtectionEnabled(val isTrackingProtectionEnabled: Boolean) :
TrackingProtectionAction()
}

@ -4,6 +4,8 @@
package org.mozilla.fenix.settings.quicksettings package org.mozilla.fenix.settings.quicksettings
import org.mozilla.fenix.trackingprotection.TrackingProtectionState
/** /**
* Parent Reducer for all [QuickSettingsFragmentState]s of all Views shown in this Fragment. * Parent Reducer for all [QuickSettingsFragmentState]s of all Views shown in this Fragment.
*/ */
@ -24,6 +26,12 @@ internal fun quickSettingsFragmentReducer(
action action
) )
) )
is TrackingProtectionAction -> state.copy(
trackingProtectionState = TrackingProtectionStateReducer.reduce(
state = state.trackingProtectionState,
action = action
)
)
} }
} }
@ -58,3 +66,19 @@ object WebsitePermissionsStateReducer {
} }
} }
} }
object TrackingProtectionStateReducer {
/**
* Handles creating a new [TrackingProtectionState] based on the specific
* [TrackingProtectionAction].
*/
fun reduce(
state: TrackingProtectionState,
action: TrackingProtectionAction
): TrackingProtectionState {
return when (action) {
is TrackingProtectionAction.ToggleTrackingProtectionEnabled ->
state.copy(isTrackingProtectionEnabled = action.isTrackingProtectionEnabled)
}
}
}

@ -8,21 +8,20 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.component_tracking_protection_panel.trackingProtectionSwitch
import kotlinx.android.synthetic.main.quicksettings_tracking_protection.* import kotlinx.android.synthetic.main.quicksettings_tracking_protection.*
import kotlinx.android.synthetic.main.switch_with_description.view.* import kotlinx.android.synthetic.main.switch_with_description.view.*
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.trackingprotection.TrackingProtectionState import org.mozilla.fenix.trackingprotection.TrackingProtectionState
/** /**
* Contract declaring all possible user interactions with [TrackingProtectionView] * Contract declaring all possible user interactions with [TrackingProtectionView].
*/ */
interface TrackingProtectionInteractor { interface TrackingProtectionInteractor {
/** /**
* Called whenever the tracking protection toggle for this site is toggled * Called whenever the tracking protection toggle for this site is toggled.
* *
* @param isEnabled new status of session tracking protection * @param isEnabled Whether or not tracking protection is enabled.
*/ */
fun onTrackingProtectionToggled(isEnabled: Boolean) fun onTrackingProtectionToggled(isEnabled: Boolean)
@ -34,10 +33,12 @@ interface TrackingProtectionInteractor {
} }
/** /**
* TODO * MVI View that displays the tracking protection toggle and navigation to additional tracking
* protection details.
* *
* @param containerView [ViewGroup] in which this View will inflate itself. * @param containerView [ViewGroup] in which this View will inflate itself.
* @param interactor [TrackingProtectionInteractor] which will have delegated to all user interactions. * @param interactor [TrackingProtectionInteractor] which will have delegated to all user
* interactions.
*/ */
class TrackingProtectionView( class TrackingProtectionView(
override val containerView: ViewGroup, override val containerView: ViewGroup,
@ -57,6 +58,8 @@ class TrackingProtectionView(
} }
private fun bindTrackingProtectionInfo(isTrackingProtectionEnabled: Boolean) { private fun bindTrackingProtectionInfo(isTrackingProtectionEnabled: Boolean) {
trackingProtectionSwitch.trackingProtectionCategoryItemDescription.text =
view.context.getString(if (isTrackingProtectionEnabled) R.string.etp_panel_on else R.string.etp_panel_off)
trackingProtectionSwitch.switch_widget.isChecked = isTrackingProtectionEnabled trackingProtectionSwitch.switch_widget.isChecked = isTrackingProtectionEnabled
trackingProtectionSwitch.switch_widget.jumpDrawablesToCurrentState() trackingProtectionSwitch.switch_widget.jumpDrawablesToCurrentState()

@ -41,7 +41,6 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
@ -98,7 +97,6 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
} }
trackingProtectionInteractor = TrackingProtectionPanelInteractor( trackingProtectionInteractor = TrackingProtectionPanelInteractor(
trackingProtectionStore, trackingProtectionStore,
::toggleTrackingProtection,
::openTrackingProtectionSettings ::openTrackingProtectionSettings
) )
trackingProtectionView = trackingProtectionView =
@ -143,25 +141,6 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
) )
} }
private fun toggleTrackingProtection(isEnabled: Boolean) {
context?.let { context ->
val session = context.components.core.store.state.findTabOrCustomTab(args.sessionId)
session?.let {
if (isEnabled) {
trackingProtectionUseCases.removeException(it.id)
} else {
context.metrics.track(Event.TrackingProtectionException)
trackingProtectionUseCases.addException(it.id)
}
with(context.components) {
useCases.sessionUseCases.reload.invoke(session.id)
}
}
}
trackingProtectionStore.dispatch(TrackingProtectionAction.TrackerBlockingChanged(isEnabled))
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return if (args.gravity == Gravity.BOTTOM) { return if (args.gravity == Gravity.BOTTOM) {
object : BottomSheetDialog(requireContext(), this.theme) { object : BottomSheetDialog(requireContext(), this.theme) {

@ -10,7 +10,6 @@ package org.mozilla.fenix.trackingprotection
*/ */
class TrackingProtectionPanelInteractor( class TrackingProtectionPanelInteractor(
private val store: TrackingProtectionStore, private val store: TrackingProtectionStore,
private val toggleTrackingProtection: (Boolean) -> Unit,
private val openTrackingProtectionSettings: () -> Unit private val openTrackingProtectionSettings: () -> Unit
) : TrackingProtectionPanelViewInteractor { ) : TrackingProtectionPanelViewInteractor {
override fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean) { override fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean) {
@ -21,10 +20,6 @@ class TrackingProtectionPanelInteractor(
openTrackingProtectionSettings.invoke() openTrackingProtectionSettings.invoke()
} }
override fun trackingProtectionToggled(isEnabled: Boolean) {
toggleTrackingProtection.invoke(isEnabled)
}
override fun onBackPressed() { override fun onBackPressed() {
store.dispatch(TrackingProtectionAction.ExitDetailsMode) store.dispatch(TrackingProtectionAction.ExitDetailsMode)
} }

@ -18,7 +18,6 @@ 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 kotlinx.android.synthetic.main.component_tracking_protection_panel.details_blocking_header
import kotlinx.android.synthetic.main.switch_with_description.view.*
import mozilla.components.browser.state.state.CustomTabSessionState import mozilla.components.browser.state.state.CustomTabSessionState
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -41,12 +40,6 @@ interface TrackingProtectionPanelViewInteractor {
*/ */
fun selectTrackingProtectionSettings() fun selectTrackingProtectionSettings()
/**
* Called whenever the tracking protection toggle for this site is toggled
* @param isEnabled new status of session tracking protection
*/
fun trackingProtectionToggled(isEnabled: Boolean)
/** /**
* Called whenever back is pressed * Called whenever back is pressed
*/ */
@ -111,7 +104,6 @@ class TrackingProtectionPanelView(
not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty() not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty()
bindUrl(state.url) bindUrl(state.url)
bindTrackingProtectionInfo(state.isTrackingProtectionEnabled)
blocking_header.isGone = bucketedTrackers.blockedIsEmpty() blocking_header.isGone = bucketedTrackers.blockedIsEmpty()
updateCategoryVisibility() updateCategoryVisibility()
@ -225,17 +217,6 @@ class TrackingProtectionPanelView(
this.url.text = url.toUri().hostWithoutCommonPrefixes this.url.text = url.toUri().hostWithoutCommonPrefixes
} }
private fun bindTrackingProtectionInfo(isTrackingProtectionOn: Boolean) {
trackingProtectionSwitch.trackingProtectionCategoryItemDescription.text =
view.context.getString(if (isTrackingProtectionOn) R.string.etp_panel_on else R.string.etp_panel_off)
trackingProtectionSwitch.switch_widget.isChecked = isTrackingProtectionOn
trackingProtectionSwitch.switch_widget.jumpDrawablesToCurrentState()
trackingProtectionSwitch.switch_widget.setOnCheckedChangeListener { _, isChecked ->
interactor.trackingProtectionToggled(isChecked)
}
}
fun onBackPressed(): Boolean { fun onBackPressed(): Boolean {
return when (mode) { return when (mode) {
is TrackingProtectionState.Mode.Details -> { is TrackingProtectionState.Mode.Details -> {

@ -34,8 +34,6 @@ sealed class TrackingProtectionAction : Action {
data class UrlChange(val url: String) : TrackingProtectionAction() data class UrlChange(val url: String) : TrackingProtectionAction()
data class TrackerLogChange(val listTrackers: List<TrackerLog>) : TrackingProtectionAction() data class TrackerLogChange(val listTrackers: List<TrackerLog>) : TrackingProtectionAction()
data class TrackerBlockingChanged(val isTrackingProtectionEnabled: Boolean) :
TrackingProtectionAction()
object ExitDetailsMode : TrackingProtectionAction() object ExitDetailsMode : TrackingProtectionAction()
data class EnterDetailsMode( data class EnterDetailsMode(
@ -134,7 +132,5 @@ fun trackingProtectionStateReducer(
), ),
lastAccessedCategory = action.category.name lastAccessedCategory = action.category.name
) )
is TrackingProtectionAction.TrackerBlockingChanged ->
state.copy(isTrackingProtectionEnabled = action.isTrackingProtectionEnabled)
} }
} }

@ -28,18 +28,6 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="https://wikipedia.org" /> tools:text="https://wikipedia.org" />
<org.mozilla.fenix.trackingprotection.SwitchWithDescription
android:id="@+id/trackingProtectionSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/tracking_protection_item_height"
android:text="@string/preference_enhanced_tracking_protection"
app:layout_constraintBottom_toTopOf="@id/blocking_header"
app:layout_constraintTop_toBottomOf="@id/url"
app:switchDescription="@string/etp_panel_on"
app:switchIcon="@drawable/ic_tracking_protection"
app:switchTitle="@string/preference_enhanced_tracking_protection" />
<TextView <TextView
android:id="@+id/blocking_header" android:id="@+id/blocking_header"
style="@style/QuickSettingsText" style="@style/QuickSettingsText"
@ -51,7 +39,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/trackingProtectionSwitch" app:layout_constraintTop_toBottomOf="@id/url"
tools:targetApi="p" /> tools:targetApi="p" />
<TextView <TextView

@ -25,6 +25,7 @@ import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.feature.session.SessionUseCases 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.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
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
@ -36,8 +37,14 @@ import org.junit.Assert.assertTrue
import org.junit.Before 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.R
import org.mozilla.fenix.components.PermissionStorage import org.mozilla.fenix.components.PermissionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
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.nav
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
@ -47,7 +54,7 @@ import org.mozilla.fenix.utils.Settings
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
class DefaultQuickSettingsControllerTest { class DefaultQuickSettingsControllerTest {
private val context = testContext private val context = spyk(testContext)
private lateinit var browserStore: BrowserStore private lateinit var browserStore: BrowserStore
private lateinit var tab: TabSessionState private lateinit var tab: TabSessionState
@ -74,6 +81,9 @@ class DefaultQuickSettingsControllerTest {
@MockK(relaxed = true) @MockK(relaxed = true)
private lateinit var addNewTab: TabsUseCases.AddNewTabUseCase private lateinit var addNewTab: TabsUseCases.AddNewTabUseCase
@MockK(relaxed = true)
private lateinit var requestPermissions: (Array<String>) -> Unit
private lateinit var controller: DefaultQuickSettingsController private lateinit var controller: DefaultQuickSettingsController
@Before @Before
@ -83,7 +93,25 @@ class DefaultQuickSettingsControllerTest {
tab = createTab("https://mozilla.org") tab = createTab("https://mozilla.org")
browserStore = BrowserStore(BrowserState(tabs = listOf(tab))) browserStore = BrowserStore(BrowserState(tabs = listOf(tab)))
sitePermissions = SitePermissions(origin = "", savedAt = 123) sitePermissions = SitePermissions(origin = "", savedAt = 123)
controller = spyk(createController())
controller = spyk(
DefaultQuickSettingsController(
context = context,
quickSettingsStore = store,
browserStore = browserStore,
sessionId = tab.id,
ioScope = coroutinesScope,
navController = navController,
sitePermissions = sitePermissions,
settings = appSettings,
permissionStorage = permissionStorage,
reload = reload,
addNewTab = addNewTab,
requestRuntimePermissions = requestPermissions,
displayPermissions = displayPermissions,
dismiss = dismiss
)
)
} }
@After @After
@ -156,8 +184,9 @@ class DefaultQuickSettingsControllerTest {
permissionStorage = permissionStorage, permissionStorage = permissionStorage,
reload = reload, reload = reload,
addNewTab = addNewTab, addNewTab = addNewTab,
requestRuntimePermissions = requestPermissions,
displayPermissions = {}, displayPermissions = {},
dismiss = {} dismiss = dismiss
) )
every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA
@ -292,4 +321,71 @@ class DefaultQuickSettingsControllerTest {
dismiss = dismiss dismiss = dismiss
) )
} }
@Test
fun `handleTrackingProtectionToggled should call the right use cases`() {
val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true)
val sessionUseCases: SessionUseCases = mockk(relaxed = true)
val metrics: MetricController = mockk(relaxed = true)
every { context.components.core.store } returns browserStore
every { context.components.useCases.trackingProtectionUseCases } returns trackingProtectionUseCases
every { context.components.useCases.sessionUseCases } returns sessionUseCases
every { context.metrics } returns metrics
every { store.dispatch(any()) } returns mockk()
var isEnabled = true
controller.handleTrackingProtectionToggled(isEnabled)
verify {
trackingProtectionUseCases.removeException(tab.id)
sessionUseCases.reload.invoke(tab.id)
store.dispatch(TrackingProtectionAction.ToggleTrackingProtectionEnabled(isEnabled))
}
isEnabled = false
controller.handleTrackingProtectionToggled(isEnabled)
verify {
metrics.track(Event.TrackingProtectionException)
trackingProtectionUseCases.addException(tab.id)
sessionUseCases.reload.invoke(tab.id)
store.dispatch(TrackingProtectionAction.ToggleTrackingProtectionEnabled(isEnabled))
}
}
@Test
fun `handleBlockedItemsClicked should call dismiss and navigate to the tracking protection panel dialog`() {
every { context.components.core.store } returns browserStore
every { context.components.settings } returns appSettings
every { context.components.settings.toolbarPosition.androidGravity } returns mockk(relaxed = true)
val isTrackingProtectionEnabled = true
val state = QuickSettingsFragmentStore.createTrackingProtectionState(
context = context,
websiteUrl = tab.content.url,
sessionId = tab.id,
isTrackingProtectionEnabled = isTrackingProtectionEnabled
)
every { store.state.trackingProtectionState } returns state
controller.handleBlockedItemsClicked()
verify {
dismiss.invoke()
navController.nav(
R.id.quickSettingsSheetDialogFragment,
QuickSettingsSheetDialogFragmentDirections.actionGlobalTrackingProtectionPanelDialogFragment(
sessionId = tab.id,
url = state.url,
trackingProtectionEnabled = state.isTrackingProtectionEnabled,
gravity = context.components.settings.toolbarPosition.androidGravity
)
)
}
}
} }

@ -4,11 +4,16 @@
package org.mozilla.fenix.settings.quicksettings package org.mozilla.fenix.settings.quicksettings
import kotlinx.coroutines.runBlocking
import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules
import mozilla.components.support.test.mock
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotSame
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.trackingprotection.TrackingProtectionState
class QuickSettingsFragmentReducerTest { class QuickSettingsFragmentReducerTest {
@ -70,6 +75,30 @@ class QuickSettingsFragmentReducerTest {
assertEquals(autoplayValue, result.autoplayValue) assertEquals(autoplayValue, result.autoplayValue)
} }
@Test
fun `TrackingProtectionAction - ToggleTrackingProtectionEnabled`() = runBlocking {
val state = QuickSettingsFragmentState(
webInfoState = mock(),
websitePermissionsState = mock(),
trackingProtectionState = TrackingProtectionState(
tab = null,
url = "https://www.firefox.com",
isTrackingProtectionEnabled = true,
listTrackers = listOf(),
mode = TrackingProtectionState.Mode.Normal,
lastAccessedCategory = ""
)
)
val newState = quickSettingsFragmentReducer(
state = state,
action = TrackingProtectionAction.ToggleTrackingProtectionEnabled(false)
)
assertNotSame(state, newState)
assertFalse(newState.trackingProtectionState.isTrackingProtectionEnabled)
}
private fun createTestRule() = SitePermissionsRules( private fun createTestRule() = SitePermissionsRules(
SitePermissionsRules.Action.ALLOWED, SitePermissionsRules.Action.ALLOWED,
SitePermissionsRules.Action.ALLOWED, SitePermissionsRules.Action.ALLOWED,

@ -5,19 +5,23 @@
package org.mozilla.fenix.settings.quicksettings package org.mozilla.fenix.settings.quicksettings
import android.content.pm.PackageManager import android.content.pm.PackageManager
import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.MockKAnnotations
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 kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.content.PermissionHighlightsState import mozilla.components.browser.state.state.content.PermissionHighlightsState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.concept.engine.permission.SitePermissions
import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules
import mozilla.components.feature.sitepermissions.SitePermissionsRules.AutoplayAction
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action
import mozilla.components.feature.sitepermissions.SitePermissionsRules.AutoplayAction
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
@ -29,12 +33,14 @@ 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.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
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.QuickSettingsFragmentStore.Companion.toWebsitePermission import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.toWebsitePermission
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL
import org.mozilla.fenix.trackingprotection.TrackingProtectionState
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
@ -59,21 +65,32 @@ class QuickSettingsFragmentStoreTest {
@Test @Test
fun `createStore constructs a QuickSettingsFragmentState`() { fun `createStore constructs a QuickSettingsFragmentState`() {
val tab = createTab(
url = "https://www.firefox.com",
title = "Firefox"
)
val browserStore = BrowserStore(BrowserState(tabs = listOf(tab)))
every { context.components.core.store } returns browserStore
val store = QuickSettingsFragmentStore.createStore( val store = QuickSettingsFragmentStore.createStore(
context = context, context = context,
websiteUrl = "url", websiteUrl = tab.content.url,
websiteTitle = "Hello", websiteTitle = tab.content.title,
certificateName = "issuer", certificateName = "issuer",
isSecured = true, isSecured = true,
permissions = permissions, permissions = permissions,
permissionHighlights = permissionHighlights, permissionHighlights = permissionHighlights,
settings = appSettings settings = appSettings,
sessionId = tab.id,
isTrackingProtectionEnabled = true
) )
assertNotNull(store) assertNotNull(store)
assertNotNull(store.state) assertNotNull(store.state)
assertNotNull(store.state.webInfoState) assertNotNull(store.state.webInfoState)
assertNotNull(store.state.websitePermissionsState) assertNotNull(store.state.websitePermissionsState)
assertNotNull(store.state.trackingProtectionState)
} }
@Test @Test
@ -264,7 +281,9 @@ class QuickSettingsFragmentStoreTest {
) )
) )
val initialState = QuickSettingsFragmentState( val initialState = QuickSettingsFragmentState(
websiteInfoState, initialWebsitePermissionsState webInfoState = websiteInfoState,
websitePermissionsState = initialWebsitePermissionsState,
trackingProtectionState = mock()
) )
val store = QuickSettingsFragmentStore(initialState) val store = QuickSettingsFragmentStore(initialState)
@ -313,6 +332,30 @@ class QuickSettingsFragmentStoreTest {
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isBlockedByAndroid) assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isBlockedByAndroid)
} }
@Test
fun `createTrackingProtectionState constructs a TrackingProtectionState with the right values`() {
val tab = createTab("https://www.firefox.com")
val browserStore = BrowserStore(BrowserState(tabs = listOf(tab)))
val isTrackingProtectionEnabled = true
every { context.components.core.store } returns browserStore
val state = QuickSettingsFragmentStore.createTrackingProtectionState(
context = context,
websiteUrl = tab.content.url,
sessionId = tab.id,
isTrackingProtectionEnabled = isTrackingProtectionEnabled
)
assertNotNull(state)
assertEquals(tab, state.tab)
assertEquals(tab.content.url, state.url)
assertEquals(isTrackingProtectionEnabled, state.isTrackingProtectionEnabled)
assertEquals(0, state.listTrackers.size)
assertEquals(TrackingProtectionState.Mode.Normal, state.mode)
assertEquals("", state.lastAccessedCategory)
}
private fun getRules() = SitePermissionsRules( private fun getRules() = SitePermissionsRules(
camera = Action.ASK_TO_ALLOW, camera = Action.ASK_TO_ALLOW,
location = Action.ASK_TO_ALLOW, location = Action.ASK_TO_ALLOW,

@ -53,4 +53,24 @@ class QuickSettingsInteractorTest {
assertTrue(permission.isCaptured) assertTrue(permission.isCaptured)
assertEquals(websitePermission, permission.captured) assertEquals(websitePermission, permission.captured)
} }
@Test
fun `onTrackingProtectionToggled should delegate the controller`() {
val isEnabled = true
interactor.onTrackingProtectionToggled(isEnabled)
verify {
controller.handleTrackingProtectionToggled(isEnabled)
}
}
@Test
fun `onBlockedItemsClicked should delegate the controller`() {
interactor.onBlockedItemsClicked()
verify {
controller.handleBlockedItemsClicked()
}
}
} }

@ -5,11 +5,8 @@
package org.mozilla.fenix.settings.quicksettings package org.mozilla.fenix.settings.quicksettings
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.view.isVisible
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -40,9 +37,7 @@ class WebsiteInfoViewTest {
) )
assertEquals("https://mozilla.org", binding.url.text) assertEquals("https://mozilla.org", binding.url.text)
assertEquals("Mozilla", binding.title.text)
assertEquals("Secure Connection", binding.securityInfo.text) assertEquals("Secure Connection", binding.securityInfo.text)
assertFalse(binding.certificateInfo.isVisible)
} }
@Test @Test
@ -57,7 +52,5 @@ class WebsiteInfoViewTest {
) )
assertEquals("Insecure Connection", binding.securityInfo.text) assertEquals("Insecure Connection", binding.securityInfo.text)
assertEquals("Verified By: Certificate", binding.certificateInfo.text)
assertTrue(binding.certificateInfo.isVisible)
} }
} }

@ -55,18 +55,6 @@ class TrackingProtectionPanelInteractorTest {
assertEquals(true, openSettings) assertEquals(true, openSettings)
} }
@Test
fun trackingProtectionToggled() {
var trackingProtectionNewValue: Boolean? = null
val interactor = TrackingProtectionPanelInteractor(
mockk(),
{ trackingProtectionNewValue = it },
{ }
)
interactor.trackingProtectionToggled(true)
assertEquals(true, trackingProtectionNewValue)
}
@Test @Test
fun onBackPressed() { fun onBackPressed() {
val store: TrackingProtectionStore = mockk(relaxed = true) val store: TrackingProtectionStore = mockk(relaxed = true)

@ -50,23 +50,6 @@ class TrackingProtectionStoreTest {
assertEquals(store.state.lastAccessedCategory, initialState.lastAccessedCategory) assertEquals(store.state.lastAccessedCategory, initialState.lastAccessedCategory)
} }
@Test
fun trackerBlockingChanged() = runBlocking {
val initialState = defaultState()
val store = TrackingProtectionStore(initialState)
store.dispatch(TrackingProtectionAction.TrackerBlockingChanged(false)).join()
assertNotSame(initialState, store.state)
assertEquals(
store.state.mode,
TrackingProtectionState.Mode.Normal
)
assertEquals(
false,
store.state.isTrackingProtectionEnabled
)
}
@Test @Test
fun trackerListChanged() = runBlocking { fun trackerListChanged() = runBlocking {
val initialState = defaultState() val initialState = defaultState()

Loading…
Cancel
Save