Unverified Commit eed20b43 authored by Tiger Oakes's avatar Tiger Oakes Committed by GitHub
Browse files

Test session control controller (#12652)

parent aa7655f4
......@@ -98,7 +98,6 @@ import org.mozilla.fenix.home.sessioncontrol.SessionControlView
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
import org.mozilla.fenix.onboarding.FenixOnboarding
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.settings.SupportUtils.MozillaPage.PRIVATE_NOTICE
import org.mozilla.fenix.settings.SupportUtils.SumoTopic.HELP
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
......@@ -175,6 +174,7 @@ class HomeFragment : Fragment() {
): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)
val activity = activity as HomeActivity
val components = requireComponents
currentMode = CurrentMode(
view.context,
......@@ -186,11 +186,11 @@ class HomeFragment : Fragment() {
homeFragmentStore = StoreProvider.get(this) {
HomeFragmentStore(
HomeFragmentState(
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections,
collections = components.core.tabCollectionStorage.cachedTabCollections,
expandedCollections = emptySet(),
mode = currentMode.getCurrentMode(),
topSites = StrictMode.allowThreadDiskReads().resetPoliciesAfter {
requireComponents.core.topSiteStorage.cachedTopSites
components.core.topSiteStorage.cachedTopSites
},
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
)
......@@ -200,16 +200,18 @@ class HomeFragment : Fragment() {
_sessionControlInteractor = SessionControlInteractor(
DefaultSessionControlController(
activity = activity,
engine = components.core.engine,
metrics = components.analytics.metrics,
sessionManager = sessionManager,
tabCollectionStorage = components.core.tabCollectionStorage,
topSiteStorage = components.core.topSiteStorage,
addTabUseCase = components.useCases.tabsUseCases.addTab,
fragmentStore = homeFragmentStore,
navController = findNavController(),
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
getListOfTabs = ::getListOfTabs,
hideOnboarding = ::hideOnboardingAndOpenSearch,
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
openSettingsScreen = ::openSettingsScreen,
openWhatsNewLink = { openInNormalTab(SupportUtils.getWhatsNewUrl(activity)) },
openPrivacyNotice = { openInNormalTab(SupportUtils.getMozillaPageUrl(PRIVATE_NOTICE)) },
showTabTray = ::openTabTray
)
)
......@@ -611,11 +613,6 @@ class HomeFragment : Fragment() {
nav(R.id.homeFragment, directions, getToolbarNavOptions(requireContext()))
}
private fun openSettingsScreen() {
val directions = HomeFragmentDirections.actionGlobalPrivateBrowsingFragment()
nav(R.id.homeFragment, directions)
}
private fun openInNormalTab(url: String) {
(activity as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = url,
......@@ -767,13 +764,8 @@ class HomeFragment : Fragment() {
}
}
private fun getListOfSessions(private: Boolean = browsingModeManager.mode.isPrivate): List<Session> {
return sessionManager.sessionsOfType(private = private)
.toList()
}
private fun getListOfTabs(): List<Tab> {
return getListOfSessions().toTabs()
private fun getNumberOfSessions(private: Boolean = browsingModeManager.mode.isPrivate): Int {
return sessionManager.sessionsOfType(private = private).count()
}
private fun registerCollectionStorageObserver() {
......@@ -787,7 +779,7 @@ class HomeFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
val recyclerView = sessionControlView!!.view
delay(ANIM_SCROLL_DELAY)
val tabsSize = getListOfSessions().size
val tabsSize = getNumberOfSessions()
var indexOfCollection = tabsSize + NON_TAB_ITEM_NUM
changedCollection?.let { changedCollection ->
......
......@@ -9,9 +9,11 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tab.collections.ext.restore
import mozilla.components.feature.tabs.TabsUseCases
import mozilla.components.feature.top.sites.TopSite
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
......@@ -23,13 +25,12 @@ import org.mozilla.fenix.components.TopSiteStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.components.tips.Tip
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.sessionsOfType
import org.mozilla.fenix.home.HomeFragment
import org.mozilla.fenix.home.HomeFragmentAction
import org.mozilla.fenix.home.HomeFragmentDirections
import org.mozilla.fenix.home.HomeFragmentStore
import org.mozilla.fenix.home.Tab
import org.mozilla.fenix.settings.SupportUtils
import mozilla.components.feature.tab.collections.Tab as ComponentTab
......@@ -130,26 +131,20 @@ interface SessionControlController {
@SuppressWarnings("TooManyFunctions", "LargeClass")
class DefaultSessionControlController(
private val activity: HomeActivity,
private val engine: Engine,
private val metrics: MetricController,
private val sessionManager: SessionManager,
private val tabCollectionStorage: TabCollectionStorage,
private val topSiteStorage: TopSiteStorage,
private val addTabUseCase: TabsUseCases.AddNewTabUseCase,
private val fragmentStore: HomeFragmentStore,
private val navController: NavController,
private val viewLifecycleScope: CoroutineScope,
private val getListOfTabs: () -> List<Tab>,
private val hideOnboarding: () -> Unit,
private val registerCollectionStorageObserver: () -> Unit,
private val showDeleteCollectionPrompt: (tabCollection: TabCollection, title: String?, message: String) -> Unit,
private val openSettingsScreen: () -> Unit,
private val openWhatsNewLink: () -> Unit,
private val openPrivacyNotice: () -> Unit,
private val showTabTray: () -> Unit
) : SessionControlController {
private val metrics: MetricController
get() = activity.components.analytics.metrics
private val sessionManager: SessionManager
get() = activity.components.core.sessionManager
private val tabCollectionStorage: TabCollectionStorage
get() = activity.components.core.tabCollectionStorage
private val topSiteStorage: TopSiteStorage
get() = activity.components.core.topSiteStorage
override fun handleCollectionAddTabTapped(collection: TabCollection) {
metrics.track(Event.CollectionAddTabPressed)
......@@ -162,7 +157,7 @@ class DefaultSessionControlController(
override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
sessionManager.restore(
activity,
activity.components.core.engine,
engine,
tab,
onTabRestored = {
activity.openToBrowser(BrowserDirection.FromHome)
......@@ -182,10 +177,10 @@ class DefaultSessionControlController(
override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
sessionManager.restore(
activity,
activity.components.core.engine,
engine,
collection,
onFailure = { url ->
activity.components.useCases.tabsUseCases.addTab.invoke(url)
addTabUseCase.invoke(url)
}
)
......@@ -261,7 +256,7 @@ class DefaultSessionControlController(
metrics.track(Event.TopSiteOpenInNewTab)
if (isDefault) { metrics.track(Event.TopSiteOpenDefault) }
if (url == SupportUtils.POCKET_TRENDING_URL) { metrics.track(Event.PocketTopSiteClicked) }
activity.components.useCases.tabsUseCases.addTab.invoke(
addTabUseCase.invoke(
url = url,
selectTab = true,
startLoading = true
......@@ -274,15 +269,24 @@ class DefaultSessionControlController(
}
override fun handleOpenSettingsClicked() {
openSettingsScreen()
val directions = HomeFragmentDirections.actionGlobalPrivateBrowsingFragment()
navController.nav(R.id.homeFragment, directions)
}
override fun handleWhatsNewGetAnswersClicked() {
openWhatsNewLink()
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getWhatsNewUrl(activity),
newTab = true,
from = BrowserDirection.FromHome
)
}
override fun handleReadPrivacyNoticeClicked() {
openPrivacyNotice()
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE),
newTab = true,
from = BrowserDirection.FromHome
)
}
override fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
......@@ -303,7 +307,11 @@ class DefaultSessionControlController(
// Only register the observer right before moving to collection creation
registerCollectionStorageObserver()
val tabIds = getListOfTabs().map { it.sessionId }.toTypedArray()
val tabIds = sessionManager
.sessionsOfType(private = activity.browsingModeManager.mode.isPrivate)
.map { session -> session.id }
.toList()
.toTypedArray()
val directions = HomeFragmentDirections.actionGlobalCollectionCreationFragment(
tabIds = tabIds,
saveCollectionStep = step,
......
......@@ -12,9 +12,11 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.feature.intent.processing.IntentProcessor
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
......@@ -39,6 +41,7 @@ class IntentReceiverActivityTest {
@Before
fun setup() {
mockkStatic("org.mozilla.fenix.ext.ContextKt")
settings = mockk()
intentProcessors = mockk()
......@@ -54,6 +57,11 @@ class IntentReceiverActivityTest {
coEvery { intentProcessors.intentProcessor.process(any()) } returns true
}
@After
fun teardown() {
unmockkStatic("org.mozilla.fenix.ext.ContextKt")
}
@Test
fun `process intent with flag launched from history`() = runBlockingTest {
val intent = Intent()
......@@ -185,7 +193,6 @@ class IntentReceiverActivityTest {
}
private fun attachMocks(activity: Activity) {
mockkStatic("org.mozilla.fenix.ext.ContextKt")
every { activity.settings() } returns settings
every { activity.components.analytics } returns mockk(relaxed = true)
every { activity.components.intentProcessors } returns intentProcessors
......
......@@ -5,13 +5,13 @@
package org.mozilla.fenix.home
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.Engine
import mozilla.components.feature.tab.collections.TabCollection
......@@ -23,12 +23,11 @@ import org.junit.Test
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.TopSiteStorage
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.nav
import org.mozilla.fenix.components.tips.Tip
import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController
import org.mozilla.fenix.settings.SupportUtils
import mozilla.components.feature.tab.collections.Tab as ComponentTab
......@@ -42,77 +41,138 @@ class DefaultSessionControlControllerTest {
private val activity: HomeActivity = mockk(relaxed = true)
private val fragmentStore: HomeFragmentStore = mockk(relaxed = true)
private val navController: NavController = mockk(relaxed = true)
private val getListOfTabs: () -> List<Tab> = { emptyList() }
private val hideOnboarding: () -> Unit = mockk(relaxed = true)
private val openSettingsScreen: () -> Unit = mockk(relaxed = true)
private val openWhatsNewLink: () -> Unit = mockk(relaxed = true)
private val openPrivacyNotice: () -> Unit = mockk(relaxed = true)
private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true)
private val showTabTray: () -> Unit = mockk(relaxed = true)
private val showDeleteCollectionPrompt: (tabCollection: TabCollection, title: String?, message: String) -> Unit =
mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
private val state: HomeFragmentState = mockk(relaxed = true)
private val sessionManager: SessionManager = mockk(relaxed = true)
private val engine: Engine = mockk(relaxed = true)
private val tabCollectionStorage: TabCollectionStorage = mockk(relaxed = true)
private val topSiteStorage: TopSiteStorage = mockk(relaxed = true)
private val tabsUseCases: TabsUseCases = mockk(relaxed = true)
private val hideOnboarding: () -> Unit = mockk(relaxed = true)
private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true)
private val showTabTray: () -> Unit = mockk(relaxed = true)
private val showDeleteCollectionPrompt: (tabCollection: TabCollection, title: String?, message: String) -> Unit =
mockk(relaxed = true)
private lateinit var controller: DefaultSessionControlController
@Before
fun setup() {
mockkStatic("org.mozilla.fenix.ext.ContextKt")
every { activity.components.core.engine } returns engine
every { activity.components.core.sessionManager } returns sessionManager
every { activity.components.core.tabCollectionStorage } returns tabCollectionStorage
every { activity.components.useCases.tabsUseCases } returns tabsUseCases
every { fragmentStore.state } returns state
every { state.collections } returns emptyList()
every { state.expandedCollections } returns emptySet()
every { state.mode } returns Mode.Normal
every { activity.components.analytics.metrics } returns metrics
every { fragmentStore.state } returns HomeFragmentState(
collections = emptyList(),
expandedCollections = emptySet(),
mode = Mode.Normal,
topSites = emptyList()
)
every { sessionManager.sessions } returns emptyList()
every { navController.currentDestination } returns mockk {
every { id } returns R.id.homeFragment
}
controller = DefaultSessionControlController(
activity = activity,
engine = engine,
metrics = metrics,
sessionManager = sessionManager,
tabCollectionStorage = tabCollectionStorage,
topSiteStorage = topSiteStorage,
addTabUseCase = tabsUseCases.addTab,
fragmentStore = fragmentStore,
navController = navController,
viewLifecycleScope = MainScope(),
getListOfTabs = getListOfTabs,
viewLifecycleScope = TestCoroutineScope(),
hideOnboarding = hideOnboarding,
registerCollectionStorageObserver = registerCollectionStorageObserver,
showDeleteCollectionPrompt = showDeleteCollectionPrompt,
openSettingsScreen = openSettingsScreen,
openWhatsNewLink = openWhatsNewLink,
openPrivacyNotice = openPrivacyNotice,
showTabTray = showTabTray
)
}
@Test
fun handleCollectionAddTabTapped() {
val collection: TabCollection = mockk(relaxed = true)
val collection = mockk<TabCollection> {
every { id } returns 12L
}
controller.handleCollectionAddTabTapped(collection)
verify { metrics.track(Event.CollectionAddTabPressed) }
verify {
navController.navigate(
match<NavDirections> { it.actionId == R.id.action_global_collectionCreationFragment },
null
)
}
}
@Test
fun handleCollectionOpenTabClicked() {
val tab: ComponentTab = mockk(relaxed = true)
fun `handleCollectionOpenTabClicked onFailure`() {
val tab = mockk<ComponentTab> {
every { url } returns "https://mozilla.org"
every { restore(activity, engine, restoreSessionId = false) } returns null
}
controller.handleCollectionOpenTabClicked(tab)
verify { metrics.track(Event.CollectionTabRestored) }
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = "https://mozilla.org",
newTab = true,
from = BrowserDirection.FromHome
)
}
}
@Test
fun `handleCollectionOpenTabClicked onTabRestored`() {
val tab = mockk<ComponentTab> {
every { restore(activity, engine, restoreSessionId = false) } returns mockk {
every { session } returns mockk()
every { engineSessionState } returns mockk()
}
}
controller.handleCollectionOpenTabClicked(tab)
verify { metrics.track(Event.CollectionTabRestored) }
verify { activity.openToBrowser(BrowserDirection.FromHome) }
}
@Test
fun handleCollectionOpenTabsTapped() {
val collection: TabCollection = mockk(relaxed = true)
val collection = mockk<TabCollection> {
every { tabs } returns emptyList()
}
controller.handleCollectionOpenTabsTapped(collection)
verify { metrics.track(Event.CollectionAllTabsRestored) }
}
@Test
fun handleCollectionRemoveTab() {
fun `handleCollectionRemoveTab one tab`() {
val collection = mockk<TabCollection> {
every { tabs } returns listOf(mockk())
every { title } returns "Collection"
}
val tab = mockk<ComponentTab>()
every {
activity.resources.getString(R.string.delete_tab_and_collection_dialog_title, "Collection")
} returns "Delete Collection?"
every {
activity.resources.getString(R.string.delete_tab_and_collection_dialog_message)
} returns "Deleting this tab will delete everything."
controller.handleCollectionRemoveTab(collection, tab)
verify { metrics.track(Event.CollectionTabRemoved) }
verify {
showDeleteCollectionPrompt(
collection,
"Delete Collection?",
"Deleting this tab will delete everything."
)
}
}
@Test
fun `handleCollectionRemoveTab multiple tabs`() {
val collection: TabCollection = mockk(relaxed = true)
val tab: ComponentTab = mockk(relaxed = true)
controller.handleCollectionRemoveTab(collection, tab)
......@@ -121,9 +181,18 @@ class DefaultSessionControlControllerTest {
@Test
fun handleCollectionShareTabsClicked() {
val collection: TabCollection = mockk(relaxed = true)
val collection = mockk<TabCollection> {
every { tabs } returns emptyList()
}
controller.handleCollectionShareTabsClicked(collection)
verify { metrics.track(Event.CollectionShared) }
verify {
navController.navigate(
match<NavDirections> { it.actionId == R.id.action_global_shareFragment },
null
)
}
}
@Test
......@@ -160,9 +229,18 @@ class DefaultSessionControlControllerTest {
@Test
fun handleRenameCollectionTapped() {
val collection: TabCollection = mockk(relaxed = true)
val collection = mockk<TabCollection> {
every { id } returns 3L
}
controller.handleRenameCollectionTapped(collection)
verify { metrics.track(Event.CollectionRenamePressed) }
verify {
navController.navigate(
match<NavDirections> { it.actionId == R.id.action_global_collectionCreationFragment },
null
)
}
}
@Test
......@@ -203,20 +281,61 @@ class DefaultSessionControlControllerTest {
@Test
fun handleOpenSettingsClicked() {
controller.handleOpenSettingsClicked()
verify { openSettingsScreen() }
verify {
navController.navigate(
match<NavDirections> { it.actionId == R.id.action_global_privateBrowsingFragment },
null
)
}
}
@Test
fun handleWhatsNewGetAnswersClicked() {
controller.handleWhatsNewGetAnswersClicked()
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getWhatsNewUrl(activity),
newTab = true,
from = BrowserDirection.FromHome
)
}
}
@Test
fun handleReadPrivacyNoticeClicked() {
controller.handleReadPrivacyNoticeClicked()
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE),
newTab = true,
from = BrowserDirection.FromHome
)
}
}
@Test
fun handleToggleCollectionExpanded() {
val collection: TabCollection = mockk(relaxed = true)
val collection = mockk<TabCollection>()
controller.handleToggleCollectionExpanded(collection, true)
verify { fragmentStore.dispatch(HomeFragmentAction.CollectionExpanded(collection, true)) }
}
@Test
fun handleCloseTip() {
val tip = mockk<Tip>()
controller.handleCloseTip(tip)
verify { fragmentStore.dispatch(HomeFragmentAction.RemoveTip(tip)) }
}
@Test
fun handleCreateCollection() {
controller.handleCreateCollection()
val directions = HomeFragmentDirections.actionGlobalCollectionCreationFragment(saveCollectionStep = SaveCollectionStep.SelectTabs)
verify { navController.nav(R.id.homeFragment, directions) }
verify {
navController.navigate(
match<NavDirections> { it.actionId == R.id.action_global_collectionCreationFragment },
null
)
}
}
}
......@@ -44,7 +44,7 @@ class AboutItemViewHolderTest {
fun `call listener on click`() {
val holder = AboutItemViewHolder(view, listener)
holder.bind(item)
view.performClick()
holder.itemView.performClick()
verify { listener.onAboutItemClicked(AboutItem.Libraries) }
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment