[fenix] For https://github.com/mozilla-mobile/fenix/issues/25816: Support changing autocomplete providers.

Everywhere the toolbar which needs to show autocomplete suggestions is used we
show a `ToolbarView`. So instead of having this configurable in 2 or more
places as it happened before the autocomplete functionality is configured only
from the `ToolbarView` class.
It will contain a `ToolbarAutocompleteFeature` that will be immediately updated
with the appropriate autocomplete providers or remove all such providers to
immediately update the current autocomplete or remove it entirely depending on
the new search engine selected.
pull/600/head
Mugurell 2 years ago committed by mergify[bot]
parent 12c8d94eeb
commit 244dc7e2af

@ -21,6 +21,7 @@ import mozilla.components.concept.sync.DeviceType
import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.feature.accounts.push.FxaPushSupportFeature
import mozilla.components.feature.accounts.push.SendTabFeature
import mozilla.components.feature.syncedtabs.SyncedTabsAutocompleteProvider
import mozilla.components.feature.syncedtabs.storage.SyncedTabsStorage
import mozilla.components.lib.crash.CrashReporter
import mozilla.components.service.fxa.PeriodicSyncConfig
@ -144,6 +145,9 @@ class BackgroundServices(
val syncedTabsStorage by lazyMonitored {
SyncedTabsStorage(accountManager, context.components.core.store, remoteTabsStorage.value)
}
val syncedTabsAutocompleteProvider by lazyMonitored {
SyncedTabsAutocompleteProvider(syncedTabsStorage)
}
@VisibleForTesting(otherwise = PRIVATE)
fun makeAccountManager(

@ -11,6 +11,8 @@ import android.os.StrictMode
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.engine.gecko.cookiebanners.GeckoCookieBannersStorage
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
@ -33,6 +35,7 @@ import mozilla.components.concept.engine.DefaultSettings
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.concept.fetch.Client
import mozilla.components.feature.awesomebar.provider.SessionAutocompleteProvider
import mozilla.components.feature.customtabs.store.CustomTabsServiceStore
import mozilla.components.feature.downloads.DownloadMiddleware
import mozilla.components.feature.logins.exceptions.LoginExceptionStorage
@ -358,6 +361,16 @@ class Core(
val lazyPasswordsStorage = lazyMonitored { SyncableLoginsStorage(context, lazySecurePrefs) }
val lazyAutofillStorage =
lazyMonitored { AutofillCreditCardsAddressesStorage(context, lazySecurePrefs) }
val lazyDomainsAutocompleteProvider = lazyMonitored {
// Assume this is used together with other autocomplete providers (like history) which have priority 0
// and set priority 1 for the domains provider to ensure other providers' results are shown first.
ShippedDomainsProvider(1).also { shippedDomainsProvider ->
shippedDomainsProvider.initialize(context)
}
}
val lazySessionAutocompleteProvider = lazyMonitored {
SessionAutocompleteProvider(store)
}
/**
* The storage component to sync and persist tabs in a Firefox Sync account.
@ -372,6 +385,8 @@ class Core(
val bookmarksStorage: PlacesBookmarksStorage get() = lazyBookmarksStorage.value
val passwordsStorage: SyncableLoginsStorage get() = lazyPasswordsStorage.value
val autofillStorage: AutofillCreditCardsAddressesStorage get() = lazyAutofillStorage.value
val domainsAutocompleteProvider: BaseDomainAutocompleteProvider get() = lazyDomainsAutocompleteProvider.value
val sessionAutocompleteProvider: SessionAutocompleteProvider get() = lazySessionAutocompleteProvider.value
val tabCollectionStorage by lazyMonitored {
TabCollectionStorage(

@ -15,7 +15,6 @@ import androidx.annotation.VisibleForTesting
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.state.CustomTabSessionState
import mozilla.components.browser.state.state.ExternalAppType
@ -175,13 +174,10 @@ class BrowserToolbarView(
this,
view,
menuToolbar,
ShippedDomainsProvider().also { it.initialize(this) },
components.core.historyStorage,
lifecycleOwner,
sessionId = null,
isPrivate = components.core.store.state.selectedTab?.content?.private ?: false,
interactor = interactor,
engine = components.core.engine,
)
}
}

@ -8,15 +8,11 @@ import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
import mozilla.components.browser.state.selector.normalTabs
import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.display.DisplayToolbar
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.toolbar.AutocompleteProvider
import mozilla.components.feature.tabs.toolbar.TabCounterToolbarButton
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.feature.toolbar.ToolbarBehaviorController
import mozilla.components.feature.toolbar.ToolbarFeature
import mozilla.components.feature.toolbar.ToolbarPresenter
@ -28,6 +24,9 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.theme.ThemeManager
/**
* Feature configuring the toolbar when in display mode.
*/
abstract class ToolbarIntegration(
context: Context,
toolbar: BrowserToolbar,
@ -77,18 +76,14 @@ abstract class ToolbarIntegration(
}
}
@Suppress("LongParameterList")
class DefaultToolbarIntegration(
context: Context,
toolbar: BrowserToolbar,
toolbarMenu: ToolbarMenu,
domainAutocompleteProvider: BaseDomainAutocompleteProvider,
historyStorage: AutocompleteProvider,
lifecycleOwner: LifecycleOwner,
sessionId: String? = null,
isPrivate: Boolean,
interactor: BrowserToolbarInteractor,
engine: Engine,
) : ToolbarIntegration(
context = context,
toolbar = toolbar,
@ -150,22 +145,6 @@ class DefaultToolbarIntegration(
tabsAction.updateCount(tabCount)
toolbar.addBrowserAction(tabsAction)
val engineForSpeculativeConnects = if (!isPrivate) engine else null
ToolbarAutocompleteFeature(
toolbar,
engineForSpeculativeConnects,
).apply {
updateAutocompleteProviders(
listOfNotNull(
when (context.settings().shouldShowHistorySuggestions) {
true -> historyStorage
false -> null
},
domainAutocompleteProvider,
),
)
}
}
override fun start() {

@ -45,7 +45,6 @@ import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.searchEngines
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
@ -53,10 +52,8 @@ import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.menu.candidate.DrawableMenuIcon
import mozilla.components.concept.menu.candidate.TextMenuCandidate
import mozilla.components.concept.toolbar.AutocompleteProvider
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.feature.qr.QrFeature
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.lib.state.ext.consumeFlow
import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.service.glean.private.NoExtras
@ -231,6 +228,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
toolbarView = ToolbarView(
requireContext(),
requireContext().settings(),
requireComponents,
interactor,
isPrivate,
binding.toolbar,
@ -239,27 +237,6 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
inlineAutocompleteEditText = it.view.findViewById(R.id.mozac_browser_toolbar_edit_url_view)
}
if (requireContext().settings().shouldAutocompleteInAwesomebar) {
val engineForSpeculativeConnects = if (!isPrivate) requireComponents.core.engine else null
ToolbarAutocompleteFeature(
binding.toolbar,
engineForSpeculativeConnects,
{ store.state.searchEngineSource.searchEngine?.type != SearchEngine.Type.APPLICATION },
).apply {
updateAutocompleteProviders(
listOfNotNull(
historyStorageProvider(),
// Assume the history provider has priority 0 and set priority 1 for the domains provider
// to ensure the first source checked for autocomplete suggestions is history.
ShippedDomainsProvider(1).also { shippedDomainsProvider ->
shippedDomainsProvider.initialize(requireContext())
},
),
)
}
}
val awesomeBar = binding.awesomeBar
awesomeBarView = AwesomeBarView(
@ -663,14 +640,6 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
dismissAllowingStateLoss()
}
private fun historyStorageProvider(): AutocompleteProvider? {
return if (requireContext().settings().shouldShowHistorySuggestions) {
requireComponents.core.historyStorage
} else {
null
}
}
@Suppress("DEPRECATION")
// https://github.com/mozilla-mobile/fenix/issues/19920
private fun createQrFeature(): QrFeature {

@ -13,11 +13,14 @@ import androidx.core.content.ContextCompat
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.content.res.resolveAttribute
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.search.SearchEngineSource
import org.mozilla.fenix.search.SearchFragmentState
import org.mozilla.fenix.utils.Settings
@ -55,6 +58,7 @@ interface ToolbarInteractor : SearchSelectorInteractor {
class ToolbarView(
private val context: Context,
private val settings: Settings,
private val components: Components,
private val interactor: ToolbarInteractor,
private val isPrivate: Boolean,
val view: BrowserToolbar,
@ -64,6 +68,13 @@ class ToolbarView(
@VisibleForTesting
internal var isInitialized = false
@VisibleForTesting
internal val autocompleteFeature = ToolbarAutocompleteFeature(
toolbar = view,
engine = if (!isPrivate) components.core.engine else null,
shouldAutocomplete = { settings.shouldAutocompleteInAwesomebar },
)
init {
view.apply {
editMode()
@ -145,6 +156,8 @@ class ToolbarView(
isInitialized = true
}
configureAutocomplete(searchState.searchEngineSource)
val searchEngine = searchState.searchEngineSource.searchEngine
view.edit.hint = when (searchEngine?.type) {
@ -182,4 +195,71 @@ class ToolbarView(
view.edit.setIcon(icon, searchEngine.name)
}
}
private fun configureAutocomplete(searchEngineSource: SearchEngineSource) {
when (settings.showUnifiedSearchFeature) {
true -> configureAutocompleteWithUnifiedSearch(searchEngineSource)
else -> configureAutocompleteWithoutUnifiedSearch(searchEngineSource)
}
}
private fun configureAutocompleteWithoutUnifiedSearch(searchEngineSource: SearchEngineSource) {
when (searchEngineSource) {
is SearchEngineSource.Default -> {
autocompleteFeature.updateAutocompleteProviders(
listOfNotNull(
when (settings.shouldShowHistorySuggestions) {
true -> components.core.historyStorage
false -> null
},
components.core.domainsAutocompleteProvider,
),
)
}
else -> {
autocompleteFeature.updateAutocompleteProviders(emptyList())
}
}
}
private fun configureAutocompleteWithUnifiedSearch(searchEngineSource: SearchEngineSource) {
when (searchEngineSource) {
is SearchEngineSource.Default -> {
autocompleteFeature.updateAutocompleteProviders(
listOfNotNull(
when (settings.shouldShowHistorySuggestions) {
true -> components.core.historyStorage
false -> null
},
components.core.domainsAutocompleteProvider,
),
)
}
is SearchEngineSource.Tabs -> {
autocompleteFeature.updateAutocompleteProviders(
listOf(
components.core.sessionAutocompleteProvider,
components.backgroundServices.syncedTabsAutocompleteProvider,
),
)
}
is SearchEngineSource.Bookmarks -> {
autocompleteFeature.updateAutocompleteProviders(
listOf(
components.core.bookmarksStorage,
),
)
}
is SearchEngineSource.History -> {
autocompleteFeature.updateAutocompleteProviders(
listOf(
components.core.historyStorage,
),
)
}
else -> {
autocompleteFeature.updateAutocompleteProviders(emptyList())
}
}
}
}

@ -38,13 +38,10 @@ class DefaultToolbarIntegrationTest {
context = testContext,
toolbar = mockk(relaxed = true),
toolbarMenu = mockk(relaxed = true),
domainAutocompleteProvider = mockk(relaxed = true),
historyStorage = mockk(),
lifecycleOwner = mockk(),
sessionId = null,
isPrivate = false,
interactor = mockk(),
engine = mockk(),
)
}

@ -5,34 +5,46 @@
package org.mozilla.fenix.search.toolbar
import android.content.Context
import android.graphics.Bitmap
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.graphics.drawable.toBitmap
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.mockkConstructor
import io.mockk.mockkObject
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.edit.EditToolbar
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.feature.awesomebar.provider.SessionAutocompleteProvider
import mozilla.components.feature.syncedtabs.SyncedTabsAutocompleteProvider
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.search.SearchEngineSource
import org.mozilla.fenix.search.SearchFragmentState
import org.mozilla.fenix.utils.Settings
import java.util.UUID
@RunWith(FenixRobolectricTestRunner::class)
@ -127,6 +139,7 @@ class ToolbarViewTest {
@Test
fun `GIVEN search term is set WHEN switching to edit mode THEN the cursor is set at the end of the search term`() {
every { context.settings().showUnifiedSearchFeature } returns true
every { context.settings().shouldShowHistorySuggestions } returns true
val view = buildToolbarView(false)
mockkObject(FeatureFlags)
@ -140,6 +153,7 @@ class ToolbarViewTest {
@Test
fun `GIVEN no search term is set WHEN switching to edit mode THEN the cursor is set at the end of the search term`() {
every { context.settings().showUnifiedSearchFeature } returns true
every { context.settings().shouldShowHistorySuggestions } returns true
val view = buildToolbarView(false)
mockkObject(FeatureFlags)
@ -255,10 +269,369 @@ class ToolbarViewTest {
assertEquals(context.getString(R.string.search_hint), toolbarView.view.edit.hint)
}
private fun buildToolbarView(isPrivate: Boolean) = ToolbarView(
context,
context.settings(),
interactor,
@Test
fun `GIVEN normal browsing mode WHEN the toolbar view is initialized THEN create an autocomplete feature with valid engine`() {
val toolbarView = buildToolbarView(false)
val autocompleteFeature = toolbarView.autocompleteFeature
assertNotNull(autocompleteFeature.engine)
}
@Test
fun `GIVEN normal private mode WHEN the toolbar view is initialized THEN create an autocomplete feature with null engine`() {
val toolbarView = buildToolbarView(true)
val autocompleteFeature = toolbarView.autocompleteFeature
assertNull(autocompleteFeature.engine)
}
@Test
fun `GIVEN autocomplete disabled WHEN the toolbar view is initialized THEN create an autocomplete with disabled functionality`() {
val settings: Settings = mockk {
every { shouldAutocompleteInAwesomebar } returns false
}
val toolbarView = buildToolbarView(true, settings)
val autocompleteFeature = toolbarView.autocompleteFeature
assertFalse(autocompleteFeature.shouldAutocomplete())
}
@Test
fun `GIVEN autocomplete enabled WHEN the toolbar view is initialized THEN create an autocomplete with enabled functionality`() {
val settings: Settings = mockk {
every { shouldAutocompleteInAwesomebar } returns true
}
val toolbarView = buildToolbarView(true, settings)
val autocompleteFeature = toolbarView.autocompleteFeature
assertTrue(autocompleteFeature.shouldAutocomplete())
}
@Test
fun `GIVEN unified search is disabled and history suggestions enabled a new search state with the default search engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val domainsProvider: BaseDomainAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
every { core.domainsAutocompleteProvider } returns domainsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns false
every { shouldShowHistorySuggestions } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(historyProvider, domainsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN unified search is disabled, history suggestions disabled and a new search state with the default search engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val domainsProvider: BaseDomainAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
every { core.domainsAutocompleteProvider } returns domainsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns false
every { shouldShowHistorySuggestions } returns false
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(domainsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN unified search is disabled and a new search state with other than the default search engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val domainsProvider: BaseDomainAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
every { core.domainsAutocompleteProvider } returns domainsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns false
every { shouldShowHistorySuggestions } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Tabs(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Bookmarks(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.History(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Shortcut(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.None))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN history suggestions enabled and a new search state with the default search engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val domainsProvider: BaseDomainAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
every { core.domainsAutocompleteProvider } returns domainsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
every { shouldShowHistorySuggestions } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(historyProvider, domainsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN history suggestions disabled and a new search state with the default search engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val domainsProvider: BaseDomainAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
every { core.domainsAutocompleteProvider } returns domainsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
every { shouldShowHistorySuggestions } returns false
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(domainsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN a new search state with the tabs engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val localSessionProvider: SessionAutocompleteProvider = mockk(relaxed = true)
val syncedSessionsProvider: SyncedTabsAutocompleteProvider = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.sessionAutocompleteProvider } returns localSessionProvider
every { backgroundServices.syncedTabsAutocompleteProvider } returns syncedSessionsProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Tabs(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(localSessionProvider, syncedSessionsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN a new search state with the bookmarks engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val bookmarksProvider: PlacesBookmarksStorage = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.bookmarksStorage } returns bookmarksProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Bookmarks(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(bookmarksProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN a new search state with the history engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val components: Components = mockk(relaxed = true) {
every { core.historyStorage } returns historyProvider
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.History(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(historyProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN a new search state with no engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
}
val toolbarView = buildToolbarView(
false,
settings = settings,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.None))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN a new search state with a shortcut engine source selected WHEN updating the toolbar THEN reconfigure autocomplete suggestions`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
)
toolbarView.update(defaultState.copy(searchEngineSource = SearchEngineSource.Shortcut(fakeSearchEngine)))
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = emptyList(),
refreshAutocomplete = true,
)
}
}
}
private fun buildToolbarView(
isPrivate: Boolean,
settings: Settings = context.settings(),
components: Components = mockk(relaxed = true),
) = ToolbarView(
context = context,
settings = settings,
components = components,
interactor = interactor,
isPrivate = isPrivate,
view = toolbar,
fromHomeFragment = false,
@ -272,3 +645,14 @@ class ToolbarViewTest {
isGeneral = isGeneral,
)
}
/**
* Get a fake [SearchEngine] to use where a simple mock won't suffice.
*/
private val fakeSearchEngine = SearchEngine(
id = "fakeId",
name = "fakeName",
icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8),
type = SearchEngine.Type.CUSTOM,
resultUrls = emptyList(),
)

Loading…
Cancel
Save