2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-19 09:25:34 +00:00
* For https://github.com/mozilla-mobile/fenix/issues/4451: Adds tests for DefaultBrowserToolbarController

* Continue working

* Large refactoring of test

* Mock analytics

* Fix merge conflicts
This commit is contained in:
Sawyer Blatz 2019-08-08 09:02:42 -07:00 committed by GitHub
parent 9f5097b48c
commit 93a03e892e
4 changed files with 364 additions and 25 deletions

View File

@ -18,6 +18,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.component_search.* import kotlinx.android.synthetic.main.component_search.*
import kotlinx.android.synthetic.main.fragment_browser.* import kotlinx.android.synthetic.main.fragment_browser.*
@ -46,6 +47,7 @@ import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.ktx.android.view.exitImmersiveModeIfNeeded import mozilla.components.support.ktx.android.view.exitImmersiveModeIfNeeded
import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ThemeManager import org.mozilla.fenix.ThemeManager
import org.mozilla.fenix.collections.CreateCollectionViewModel import org.mozilla.fenix.collections.CreateCollectionViewModel
@ -65,6 +67,8 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.enterToImmersiveMode import org.mozilla.fenix.ext.enterToImmersiveMode
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.toTab
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
/** /**
@ -142,7 +146,14 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
nestedScrollQuickActionView = nestedScrollQuickAction, nestedScrollQuickActionView = nestedScrollQuickAction,
engineView = engineView, engineView = engineView,
currentSession = session, currentSession = session,
viewModel = viewModel viewModel = viewModel,
getSupportUrl = { SupportUtils.getSumoURLForTopic(context!!, SupportUtils.SumoTopic.HELP) },
openInFenixIntent = Intent(context, IntentReceiverActivity::class.java).also {
it.action = Intent.ACTION_VIEW
it.flags = Intent.FLAG_ACTIVITY_NEW_TASK
},
currentSessionAsTab = session.toTab(context!!),
bottomSheetBehavior = BottomSheetBehavior.from(nestedScrollQuickAction)
) )
browserInteractor = createBrowserToolbarViewInteractor(browserToolbarController, session) browserInteractor = createBrowserToolbarViewInteractor(browserToolbarController, session)

View File

@ -19,6 +19,7 @@ import androidx.navigation.fragment.findNavController
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.component_search.* import kotlinx.android.synthetic.main.component_search.*
import kotlinx.android.synthetic.main.fragment_browser.*
import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.android.synthetic.main.fragment_browser.view.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main

View File

@ -14,7 +14,6 @@ import mozilla.components.browser.session.Session
import mozilla.components.concept.engine.EngineView import mozilla.components.concept.engine.EngineView
import org.mozilla.fenix.BrowsingModeManager import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragment import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.browser.BrowserFragmentDirections import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -23,10 +22,8 @@ import org.mozilla.fenix.collections.getStepForCollectionsSize
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.components
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.toTab import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.lib.Do import org.mozilla.fenix.lib.Do
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
import org.mozilla.fenix.settings.SupportUtils
/** /**
* An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor * An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor
@ -43,7 +40,11 @@ class DefaultBrowserToolbarController(
private val nestedScrollQuickActionView: NestedScrollView, private val nestedScrollQuickActionView: NestedScrollView,
private val engineView: EngineView, private val engineView: EngineView,
private val currentSession: Session, private val currentSession: Session,
private val viewModel: CreateCollectionViewModel private val viewModel: CreateCollectionViewModel,
private val getSupportUrl: () -> String,
private val openInFenixIntent: Intent,
private val currentSessionAsTab: Tab,
private val bottomSheetBehavior: BottomSheetBehavior<NestedScrollView>
) : BrowserToolbarController { ) : BrowserToolbarController {
override fun handleToolbarClick() { override fun handleToolbarClick() {
@ -93,9 +94,7 @@ class DefaultBrowserToolbarController(
(context as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private (context as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
} }
ToolbarMenu.Item.FindInPage -> { ToolbarMenu.Item.FindInPage -> {
(BottomSheetBehavior.from(nestedScrollQuickActionView) as QuickActionSheetBehavior).apply { bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
state = BottomSheetBehavior.STATE_COLLAPSED
}
findInPageLauncher() findInPageLauncher()
context.components.analytics.metrics.track(Event.FindInPageOpened) context.components.analytics.metrics.track(Event.FindInPageOpened)
} }
@ -106,12 +105,7 @@ class DefaultBrowserToolbarController(
} }
} }
ToolbarMenu.Item.Help -> { ToolbarMenu.Item.Help -> {
context.components.useCases.tabsUseCases.addTab.invoke( context.components.useCases.tabsUseCases.addTab.invoke(getSupportUrl())
SupportUtils.getSumoURLForTopic(
context,
SupportUtils.SumoTopic.HELP
)
)
} }
ToolbarMenu.Item.NewTab -> { ToolbarMenu.Item.NewTab -> {
val directions = BrowserFragmentDirections val directions = BrowserFragmentDirections
@ -123,10 +117,9 @@ class DefaultBrowserToolbarController(
ToolbarMenu.Item.SaveToCollection -> { ToolbarMenu.Item.SaveToCollection -> {
context.components.analytics.metrics context.components.analytics.metrics
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER)) .track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
currentSession.let {
val tab = it.toTab(context) viewModel.tabs = listOf(currentSessionAsTab)
viewModel.tabs = listOf(tab) val selectedSet = mutableSetOf(currentSessionAsTab)
val selectedSet = mutableSetOf(tab)
viewModel.selectedTabs = selectedSet viewModel.selectedTabs = selectedSet
viewModel.tabCollections = viewModel.tabCollections =
context.components.core.tabCollectionStorage.cachedTabCollections.reversed() context.components.core.tabCollectionStorage.cachedTabCollections.reversed()
@ -136,7 +129,6 @@ class DefaultBrowserToolbarController(
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment() val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
navController.nav(R.id.browserFragment, directions) navController.nav(R.id.browserFragment, directions)
}
} }
ToolbarMenu.Item.OpenInFenix -> { ToolbarMenu.Item.OpenInFenix -> {
// Release the session from this view so that it can immediately be rendered by a different view // Release the session from this view so that it can immediately be rendered by a different view
@ -147,10 +139,7 @@ class DefaultBrowserToolbarController(
context.components.core.sessionManager.select(currentSession) context.components.core.sessionManager.select(currentSession)
// Switch to the actual browser which should now display our new selected session // Switch to the actual browser which should now display our new selected session
context.startActivity(Intent(context, IntentReceiverActivity::class.java).also { context.startActivity(openInFenixIntent)
it.action = Intent.ACTION_VIEW
it.flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
// Close this activity since it is no longer displaying any session // Close this activity since it is no longer displaying any session
(context as Activity).finish() (context as Activity).finish()
@ -188,6 +177,6 @@ class DefaultBrowserToolbarController(
} }
companion object { companion object {
private const val TELEMETRY_BROWSER_IDENTIFIER = "browserMenu" internal const val TELEMETRY_BROWSER_IDENTIFIER = "browserMenu"
} }
} }

View File

@ -0,0 +1,338 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components.toolbar
import android.content.Intent
import androidx.core.widget.NestedScrollView
import androidx.navigation.NavController
import com.google.android.material.bottomsheet.BottomSheetBehavior
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.tabs.TabsUseCases
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.browser.BrowserFragmentDirections
import org.mozilla.fenix.collections.CreateCollectionViewModel
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.Analytics
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.metrics
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.home.sessioncontrol.TabCollection
class DefaultBrowserToolbarControllerTest {
private var context: HomeActivity = mockk(relaxed = true)
private var analytics: Analytics = mockk(relaxed = true)
private var navController: NavController = mockk(relaxed = true)
private var findInPageLauncher: () -> Unit = mockk(relaxed = true)
private val nestedScrollQuickActionView: NestedScrollView = mockk(relaxed = true)
private val engineView: EngineView = mockk(relaxed = true)
private val currentSession: Session = mockk(relaxed = true)
private val viewModel: CreateCollectionViewModel = mockk(relaxed = true)
private val getSupportUrl: () -> String = { "https://supportUrl.org" }
private val openInFenixIntent: Intent = mockk(relaxed = true)
private val currentSessionAsTab: Tab = mockk(relaxed = true)
private val bottomSheetBehavior: BottomSheetBehavior<NestedScrollView> = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
private val sessionUseCases: SessionUseCases = mockk(relaxed = true)
private lateinit var controller: DefaultBrowserToolbarController
@Before
fun setUp() {
controller = DefaultBrowserToolbarController(
context = context,
navController = navController,
findInPageLauncher = findInPageLauncher,
nestedScrollQuickActionView = nestedScrollQuickActionView,
engineView = engineView,
currentSession = currentSession,
viewModel = viewModel,
getSupportUrl = getSupportUrl,
openInFenixIntent = openInFenixIntent,
currentSessionAsTab = currentSessionAsTab,
bottomSheetBehavior = bottomSheetBehavior
)
every { context.components.analytics } returns analytics
every { analytics.metrics } returns metrics
every { context.components.useCases.sessionUseCases } returns sessionUseCases
}
@Test
fun handleToolbarClick() {
every { currentSession.id } returns "1"
controller.handleToolbarClick()
verify { metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.BROWSER)) }
verify { navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(currentSession.id)
) }
}
@Test
fun handleToolbarBackPress() {
val item = ToolbarMenu.Item.Back
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BACK)) }
verify { sessionUseCases.goBack }
}
@Test
fun handleToolbarForwardPress() {
val item = ToolbarMenu.Item.Forward
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.FORWARD)) }
verify { sessionUseCases.goForward }
}
@Test
fun handleToolbarReloadPress() {
val item = ToolbarMenu.Item.Reload
every { context.components.useCases.sessionUseCases } returns sessionUseCases
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.RELOAD)) }
verify { sessionUseCases.reload }
}
@Test
fun handleToolbarStopPress() {
val item = ToolbarMenu.Item.Stop
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.STOP)) }
verify { sessionUseCases.stopLoading }
}
@Test
fun handleToolbarSettingsPress() {
val item = ToolbarMenu.Item.Settings
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SETTINGS)) }
verify { navController.nav(
R.id.settingsFragment,
BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
) }
}
@Test
fun handleToolbarLibraryPress() {
val item = ToolbarMenu.Item.Library
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.LIBRARY)) }
verify { navController.nav(
R.id.libraryFragment,
BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
) }
}
@Test
fun handleToolbarRequestDesktopOnPress() {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase = mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(true)
every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_ON)) }
verify {
requestDesktopSiteUseCase.invoke(
true,
currentSession
)
}
}
@Test
fun handleToolbarRequestDesktopOffPress() {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase = mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(false)
every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_OFF)) }
verify {
requestDesktopSiteUseCase.invoke(
false,
currentSession
)
}
}
@Test
fun handleToolbarSharePress() {
val item = ToolbarMenu.Item.Share
every { currentSession.url } returns "https://mozilla.org"
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SHARE)) }
verify {
val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(currentSession.url)
navController.nav(R.id.browserFragment, directions)
}
}
@Test
fun handleToolbarNewPrivateTabPress() {
val browsingModeManager: BrowsingModeManager = mockk(relaxed = true)
val item = ToolbarMenu.Item.NewPrivateTab
every { context.browsingModeManager } returns browsingModeManager
every { browsingModeManager.mode } returns BrowsingModeManager.Mode.Normal
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.NEW_PRIVATE_TAB)) }
verify {
val directions = BrowserFragmentDirections
.actionBrowserFragmentToSearchFragment(null)
navController.nav(R.id.browserFragment, directions)
}
verify { browsingModeManager.mode = BrowsingModeManager.Mode.Private }
}
@Test
fun handleToolbarFindInPagePress() {
val item = ToolbarMenu.Item.FindInPage
controller.handleToolbarItemInteraction(item)
verify { bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED }
verify { findInPageLauncher() }
verify { metrics.track(Event.FindInPageOpened) }
}
@Test
fun handleToolbarReportIssuePress() {
val tabsUseCases: TabsUseCases = mockk(relaxed = true)
val addTabUseCase: TabsUseCases.AddNewTabUseCase = mockk(relaxed = true)
val item = ToolbarMenu.Item.ReportIssue
every { currentSession.url } returns "https://mozilla.org"
every { context.components.useCases.tabsUseCases } returns tabsUseCases
every { tabsUseCases.addTab } returns addTabUseCase
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.REPORT_SITE_ISSUE)) }
verify {
// Hardcoded URL because this function modifies the URL with an apply
addTabUseCase.invoke(String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, "https://mozilla.org"))
}
}
@Test
fun handleToolbarHelpPress() {
val tabsUseCases: TabsUseCases = mockk(relaxed = true)
val addTabUseCase: TabsUseCases.AddNewTabUseCase = mockk(relaxed = true)
val item = ToolbarMenu.Item.Help
every { context.components.useCases.tabsUseCases } returns tabsUseCases
every { tabsUseCases.addTab } returns addTabUseCase
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.HELP)) }
verify {
addTabUseCase.invoke(getSupportUrl())
}
}
@Test
fun handleToolbarNewTabPress() {
val browsingModeManager: BrowsingModeManager = mockk(relaxed = true)
val item = ToolbarMenu.Item.NewTab
every { context.browsingModeManager } returns browsingModeManager
every { browsingModeManager.mode } returns BrowsingModeManager.Mode.Private
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.NEW_TAB)) }
verify {
val directions = BrowserFragmentDirections
.actionBrowserFragmentToSearchFragment(null)
navController.nav(R.id.browserFragment, directions)
}
verify { browsingModeManager.mode = BrowsingModeManager.Mode.Normal }
}
@Test
fun handleToolbarSaveToCollectionPress() {
val item = ToolbarMenu.Item.SaveToCollection
val cachedTabCollections: List<TabCollection> = mockk(relaxed = true)
every { context.components.useCases.sessionUseCases } returns sessionUseCases
every { context.components.core.tabCollectionStorage.cachedTabCollections } returns cachedTabCollections
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION)) }
verify { metrics.track(Event.CollectionSaveButtonPressed(DefaultBrowserToolbarController.TELEMETRY_BROWSER_IDENTIFIER)) }
verify { viewModel.tabs = listOf(currentSessionAsTab) }
verify { viewModel.selectedTabs = mutableSetOf(currentSessionAsTab) }
verify { viewModel.tabCollections = cachedTabCollections.reversed() }
verify { viewModel.saveCollectionStep = SaveCollectionStep.SelectCollection }
verify { viewModel.snackbarAnchorView = nestedScrollQuickActionView }
verify { viewModel.previousFragmentId = R.id.browserFragment }
verify {
val directions = BrowserFragmentDirections
.actionBrowserFragmentToSearchFragment(null)
navController.nav(R.id.browserFragment, directions)
}
}
@Test
fun handleToolbarOpenInFenixPress() {
val sessionManager: SessionManager = mockk(relaxed = true)
val item = ToolbarMenu.Item.OpenInFenix
every { context.components.core.sessionManager } returns sessionManager
every { currentSession.customTabConfig } returns mockk()
every { context.startActivity(any()) } just Runs
controller.handleToolbarItemInteraction(item)
verify { engineView.release() }
verify { currentSession.customTabConfig = null }
verify { sessionManager.select(currentSession) }
verify { context.startActivity(openInFenixIntent) }
verify { context.finish() }
}
}