1
0
Fork 0

For #12565 - Clean up controller and add tests

master
Tiger Oakes 2020-07-21 10:58:28 -07:00 committed by Jeff Boek
parent 596300591e
commit d640f58316
3 changed files with 94 additions and 57 deletions

View File

@ -8,6 +8,7 @@ import android.content.Intent
import androidx.navigation.NavController import androidx.navigation.NavController
import mozilla.components.browser.search.SearchEngine import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
@ -16,15 +17,14 @@ import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.ACTION import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.ACTION
import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.NONE import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.NONE
import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.SUGGESTION import org.mozilla.fenix.components.metrics.Event.PerformedSearch.SearchAccessPoint.SUGGESTION
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.components.metrics.MetricsUtils import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.components.searchengine.CustomSearchEngineStore import org.mozilla.fenix.components.searchengine.CustomSearchEngineStore
import org.mozilla.fenix.crashes.CrashListActivity import org.mozilla.fenix.crashes.CrashListActivity
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.navigateSafe import org.mozilla.fenix.ext.navigateSafe
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.settings.SupportUtils.MozillaPage.MANIFESTO import org.mozilla.fenix.settings.SupportUtils.MozillaPage.MANIFESTO
import org.mozilla.fenix.utils.Settings
/** /**
* An interface that handles the view manipulation of the Search, triggered by the Interactor * An interface that handles the view manipulation of the Search, triggered by the Interactor
@ -42,11 +42,14 @@ interface SearchController {
fun handleSearchShortcutsButtonClicked() fun handleSearchShortcutsButtonClicked()
} }
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions", "LongParameterList")
class DefaultSearchController( class DefaultSearchController(
private val activity: HomeActivity, private val activity: HomeActivity,
private val sessionManager: SessionManager,
private val store: SearchFragmentStore, private val store: SearchFragmentStore,
private val navController: NavController, private val navController: NavController,
private val settings: Settings,
private val metrics: MetricController,
private val clearToolbarFocus: () -> Unit private val clearToolbarFocus: () -> Unit
) : SearchController { ) : SearchController {
@ -76,7 +79,7 @@ class DefaultSearchController(
val event = if (url.isUrl()) { val event = if (url.isUrl()) {
Event.EnteredUrl(false) Event.EnteredUrl(false)
} else { } else {
activity.settings().incrementActiveSearchCount() settings.incrementActiveSearchCount()
val searchAccessPoint = when (store.state.searchAccessPoint) { val searchAccessPoint = when (store.state.searchAccessPoint) {
NONE -> ACTION NONE -> ACTION
@ -92,7 +95,7 @@ class DefaultSearchController(
} }
} }
event?.let { activity.metrics.track(it) } event?.let { metrics.track(it) }
} }
override fun handleEditingCancelled() { override fun handleEditingCancelled() {
@ -100,7 +103,6 @@ class DefaultSearchController(
} }
override fun handleTextChanged(text: String) { override fun handleTextChanged(text: String) {
val settings = activity.settings()
// Display the search shortcuts on each entry of the search fragment (see #5308) // Display the search shortcuts on each entry of the search fragment (see #5308)
val textMatchesCurrentUrl = store.state.url == text val textMatchesCurrentUrl = store.state.url == text
val textMatchesCurrentSearch = store.state.searchTerms == text val textMatchesCurrentSearch = store.state.searchTerms == text
@ -129,11 +131,11 @@ class DefaultSearchController(
from = BrowserDirection.FromSearch from = BrowserDirection.FromSearch
) )
activity.metrics.track(Event.EnteredUrl(false)) metrics.track(Event.EnteredUrl(false))
} }
override fun handleSearchTermsTapped(searchTerms: String) { override fun handleSearchTermsTapped(searchTerms: String) {
activity.settings().incrementActiveSearchCount() settings.incrementActiveSearchCount()
activity.openToBrowserAndLoad( activity.openToBrowserAndLoad(
searchTermOrURL = searchTerms, searchTermOrURL = searchTerms,
@ -155,14 +157,14 @@ class DefaultSearchController(
sap sap
) )
} }
event?.let { activity.metrics.track(it) } event?.let { metrics.track(it) }
} }
override fun handleSearchShortcutEngineSelected(searchEngine: SearchEngine) { override fun handleSearchShortcutEngineSelected(searchEngine: SearchEngine) {
store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine)) store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine))
val isCustom = val isCustom =
CustomSearchEngineStore.isCustomSearchEngine(activity, searchEngine.identifier) CustomSearchEngineStore.isCustomSearchEngine(activity, searchEngine.identifier)
activity.metrics.track(Event.SearchShortcutSelected(searchEngine, isCustom)) metrics.track(Event.SearchShortcutSelected(searchEngine, isCustom))
} }
override fun handleSearchShortcutsButtonClicked() { override fun handleSearchShortcutsButtonClicked() {
@ -176,14 +178,14 @@ class DefaultSearchController(
} }
override fun handleExistingSessionSelected(session: Session) { override fun handleExistingSessionSelected(session: Session) {
activity.components.core.sessionManager.select(session) sessionManager.select(session)
activity.openToBrowser( activity.openToBrowser(
from = BrowserDirection.FromSearch from = BrowserDirection.FromSearch
) )
} }
override fun handleExistingSessionSelected(tabId: String) { override fun handleExistingSessionSelected(tabId: String) {
val session = activity.components.core.sessionManager.findSessionById(tabId) val session = sessionManager.findSessionById(tabId)
if (session != null) { if (session != null) {
handleExistingSessionSelected(session) handleExistingSessionSelected(session)
} }

View File

@ -86,6 +86,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
val activity = activity as HomeActivity val activity = activity as HomeActivity
val settings = activity.settings()
val args by navArgs<SearchFragmentArgs>() val args by navArgs<SearchFragmentArgs>()
val tabId = args.sessionId val tabId = args.sessionId
@ -112,13 +113,13 @@ class SearchFragment : Fragment(), UserInteractionHandler {
defaultEngineSource = currentSearchEngine, defaultEngineSource = currentSearchEngine,
showSearchSuggestions = shouldShowSearchSuggestions(isPrivate), showSearchSuggestions = shouldShowSearchSuggestions(isPrivate),
showSearchSuggestionsHint = false, showSearchSuggestionsHint = false,
showSearchShortcuts = requireContext().settings().shouldShowSearchShortcuts && showSearchShortcuts = settings.shouldShowSearchShortcuts &&
url.isEmpty() && url.isEmpty() &&
areShortcutsAvailable, areShortcutsAvailable,
areShortcutsAvailable = areShortcutsAvailable, areShortcutsAvailable = areShortcutsAvailable,
showClipboardSuggestions = requireContext().settings().shouldShowClipboardSuggestions, showClipboardSuggestions = settings.shouldShowClipboardSuggestions,
showHistorySuggestions = requireContext().settings().shouldShowHistorySuggestions, showHistorySuggestions = settings.shouldShowHistorySuggestions,
showBookmarkSuggestions = requireContext().settings().shouldShowBookmarkSuggestions, showBookmarkSuggestions = settings.shouldShowBookmarkSuggestions,
tabId = tabId, tabId = tabId,
pastedText = args.pastedText, pastedText = args.pastedText,
searchAccessPoint = args.searchAccessPoint searchAccessPoint = args.searchAccessPoint
@ -128,8 +129,11 @@ class SearchFragment : Fragment(), UserInteractionHandler {
val searchController = DefaultSearchController( val searchController = DefaultSearchController(
activity = activity, activity = activity,
sessionManager = requireComponents.core.sessionManager,
store = searchStore, store = searchStore,
navController = findNavController(), navController = findNavController(),
settings = settings,
metrics = requireComponents.analytics.metrics,
clearToolbarFocus = ::clearToolbarFocus clearToolbarFocus = ::clearToolbarFocus
) )
@ -163,7 +167,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
visible = { visible = {
currentSearchEngine.searchEngine.identifier.contains("google") && currentSearchEngine.searchEngine.identifier.contains("google") &&
speechIsAvailable() && speechIsAvailable() &&
requireContext().settings().shouldShowVoiceSearch settings.shouldShowVoiceSearch
}, },
listener = ::launchVoiceSearch listener = ::launchVoiceSearch
) )

View File

@ -4,71 +4,75 @@
package org.mozilla.fenix.search package org.mozilla.fenix.search
import android.content.Intent
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.every import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkObject
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.browser.search.SearchEngine import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager
import mozilla.components.support.test.robolectric.testContext import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
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.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.crashes.CrashListActivity import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.intentFilterEq
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.navigateSafe import org.mozilla.fenix.ext.navigateSafe
import org.mozilla.fenix.ext.searchEngineManager
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class)
class DefaultSearchControllerTest { class DefaultSearchControllerTest {
private val activity: HomeActivity = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var activity: HomeActivity
private val store: SearchFragmentStore = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var store: SearchFragmentStore
private val navController: NavController = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var navController: NavController
private val defaultSearchEngine: SearchEngine? = mockk(relaxed = true) @MockK private lateinit var searchEngine: SearchEngine
private val searchEngine: SearchEngine = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var metrics: MetricController
private val metrics: MetricController = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var settings: Settings
private val sessionManager: SessionManager = mockk(relaxed = true) @MockK private lateinit var sessionManager: SessionManager
private val settings: Settings = mockk(relaxed = true) @MockK(relaxed = true) private lateinit var clearToolbarFocus: () -> Unit
private val clearToolbarFocus: (() -> Unit) = mockk(relaxed = true)
private lateinit var controller: DefaultSearchController private lateinit var controller: DefaultSearchController
@Before @Before
fun setUp() { fun setUp() {
every { activity.searchEngineManager.defaultSearchEngine } returns defaultSearchEngine MockKAnnotations.init(this)
mockkObject(MetricsUtils)
every { store.state.tabId } returns "test-tab-id" every { store.state.tabId } returns "test-tab-id"
every { store.state.searchEngineSource.searchEngine } returns searchEngine every { store.state.searchEngineSource.searchEngine } returns searchEngine
every { activity.metrics } returns metrics every { sessionManager.select(any()) } just Runs
every { activity.components.core.sessionManager } returns sessionManager every { MetricsUtils.createSearchEvent(searchEngine, activity, any()) } returns null
every { activity.components.settings } returns settings
controller = DefaultSearchController( controller = DefaultSearchController(
activity = activity, activity = activity,
sessionManager = sessionManager,
store = store, store = store,
navController = navController, navController = navController,
settings = settings,
metrics = metrics,
clearToolbarFocus = clearToolbarFocus clearToolbarFocus = clearToolbarFocus
) )
} }
@After
fun teardown() {
unmockkObject(MetricsUtils)
}
@Test @Test
fun handleUrlCommitted() { fun handleUrlCommitted() {
val url = "https://www.google.com/" val url = "https://www.google.com/"
@ -86,15 +90,32 @@ class DefaultSearchControllerTest {
verify { metrics.track(Event.EnteredUrl(false)) } verify { metrics.track(Event.EnteredUrl(false)) }
} }
@Test
fun handleSearchCommitted() {
val searchTerm = "Firefox"
controller.handleUrlCommitted(searchTerm)
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = searchTerm,
newTab = false,
from = BrowserDirection.FromSearch,
engine = searchEngine
)
}
verify { settings.incrementActiveSearchCount() }
}
@Test @Test
fun handleCrashesUrlCommitted() { fun handleCrashesUrlCommitted() {
val url = "about:crashes" val url = "about:crashes"
every { activity.packageName } returns testContext.packageName every { activity.packageName } returns "org.mozilla.fenix"
controller.handleUrlCommitted(url) controller.handleUrlCommitted(url)
verify { verify {
activity.startActivity(intentFilterEq(Intent(testContext, CrashListActivity::class.java))) activity.startActivity(any())
} }
} }
@ -117,13 +138,6 @@ class DefaultSearchControllerTest {
@Test @Test
fun handleEditingCancelled() = runBlockingTest { fun handleEditingCancelled() = runBlockingTest {
controller = DefaultSearchController(
activity = activity,
store = store,
navController = navController,
clearToolbarFocus = clearToolbarFocus
)
controller.handleEditingCancelled() controller.handleEditingCancelled()
verify { verify {
@ -183,8 +197,6 @@ class DefaultSearchControllerTest {
fun `do not show search shortcuts when setting disabled AND query empty AND url not matching query`() { fun `do not show search shortcuts when setting disabled AND query empty AND url not matching query`() {
every { settings.shouldShowSearchShortcuts } returns false every { settings.shouldShowSearchShortcuts } returns false
assertFalse(testContext.settings().shouldShowSearchShortcuts)
val text = "" val text = ""
controller.handleTextChanged(text) controller.handleTextChanged(text)
@ -196,8 +208,6 @@ class DefaultSearchControllerTest {
fun `do not show search shortcuts when setting disabled AND query non-empty`() { fun `do not show search shortcuts when setting disabled AND query non-empty`() {
every { settings.shouldShowSearchShortcuts } returns false every { settings.shouldShowSearchShortcuts } returns false
assertFalse(testContext.settings().shouldShowSearchShortcuts)
val text = "mozilla" val text = "mozilla"
controller.handleTextChanged(text) controller.handleTextChanged(text)
@ -278,11 +288,32 @@ class DefaultSearchControllerTest {
@Test @Test
fun handleExistingSessionSelected() { fun handleExistingSessionSelected() {
val session: Session = mockk(relaxed = true) val session = mockk<Session>()
controller.handleExistingSessionSelected(session) controller.handleExistingSessionSelected(session)
verify { sessionManager.select(session) } verify { sessionManager.select(session) }
verify { activity.openToBrowser(from = BrowserDirection.FromSearch) } verify { activity.openToBrowser(from = BrowserDirection.FromSearch) }
} }
@Test
fun handleExistingSessionSelected_tabId_nullSession() {
every { sessionManager.findSessionById("tab-id") } returns null
controller.handleExistingSessionSelected("tab-id")
verify(inverse = true) { sessionManager.select(any()) }
verify(inverse = true) { activity.openToBrowser(from = BrowserDirection.FromSearch) }
}
@Test
fun handleExistingSessionSelected_tabId() {
val session = mockk<Session>()
every { sessionManager.findSessionById("tab-id") } returns session
controller.handleExistingSessionSelected("tab-id")
verify { sessionManager.select(any()) }
verify { activity.openToBrowser(from = BrowserDirection.FromSearch) }
}
} }