You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/test/java/org/mozilla/fenix/search/toolbar/ToolbarViewTest.kt

891 lines
39 KiB
Kotlin

/* 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.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.state.state.SearchState
import mozilla.components.browser.state.state.searchEngines
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.browser.toolbar.BrowserToolbar
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 mozilla.components.ui.autocomplete.InlineAutocompleteEditText
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.Core
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.search.SearchDialogFragment
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)
class ToolbarViewTest {
@MockK(relaxed = true)
private lateinit var interactor: ToolbarInteractor
private lateinit var context: Context
private lateinit var toolbar: BrowserToolbar
private val defaultState: SearchFragmentState = SearchFragmentState(
tabId = null,
url = "",
searchTerms = "",
query = "",
searchEngineSource = SearchEngineSource.Default(
mockk {
every { name } returns "Search Engine"
every { icon } returns testContext.getDrawable(R.drawable.ic_search)!!.toBitmap()
every { type } returns SearchEngine.Type.BUNDLED
every { isGeneral } returns true
},
),
defaultEngine = null,
showSearchTermHistory = true,
showSearchShortcutsSetting = false,
showSearchSuggestionsHint = false,
showSearchSuggestions = false,
showSearchShortcuts = false,
areShortcutsAvailable = true,
showClipboardSuggestions = false,
showHistorySuggestionsForCurrentEngine = true,
showAllHistorySuggestions = false,
showBookmarksSuggestionsForCurrentEngine = false,
showAllBookmarkSuggestions = false,
showSyncedTabsSuggestionsForCurrentEngine = false,
showAllSyncedTabsSuggestions = false,
showSessionSuggestionsForCurrentEngine = false,
showAllSessionSuggestions = false,
showSponsoredSuggestions = false,
showNonSponsoredSuggestions = false,
searchAccessPoint = MetricsUtils.Source.NONE,
)
@Before
fun setup() {
MockKAnnotations.init(this)
context = ContextThemeWrapper(testContext, R.style.NormalTheme)
every { context.settings() } returns mockk(relaxed = true)
toolbar = spyk(BrowserToolbar(context))
}
@Test
fun `sets toolbar to normal mode`() {
buildToolbarView(isPrivate = false)
assertFalse(toolbar.private)
}
@Test
fun `sets toolbar to private mode`() {
buildToolbarView(isPrivate = true)
assertTrue(toolbar.private)
}
@Test
fun `View gets initialized only once`() {
val view = buildToolbarView(false)
assertFalse(view.isInitialized)
view.update(defaultState)
view.update(defaultState)
view.update(defaultState)
verify(exactly = 1) { toolbar.setSearchTerms(any()) }
assertTrue(view.isInitialized)
}
@Test
fun `search term updates the url`() {
val view = buildToolbarView(false)
view.update(defaultState)
view.update(defaultState)
view.update(defaultState)
// editMode gets called when the view is initialized.
verify(exactly = 2) { toolbar.editMode() }
// search term changes update the url and invoke the interactor.
verify(exactly = 2) { toolbar.url = any() }
verify(exactly = 2) { interactor.onTextChanged(any()) }
}
@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
every { context.settings().shouldShowBookmarkSuggestions } returns true
every { context.settings().isTabletAndTabStripEnabled } returns false
every { context.settings().enableIncompleteToolbarRedesign } returns false
val view = buildToolbarView(false)
mockkObject(FeatureFlags)
view.update(defaultState.copy(searchTerms = "search terms"))
// editMode gets called when the view is initialized.
verify(exactly = 1) { toolbar.editMode(Toolbar.CursorPlacement.ALL) }
verify(exactly = 1) { toolbar.editMode(Toolbar.CursorPlacement.END) }
}
@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
every { context.settings().shouldShowBookmarkSuggestions } returns true
every { context.settings().isTabletAndTabStripEnabled } returns false
every { context.settings().enableIncompleteToolbarRedesign } returns false
val view = buildToolbarView(false)
mockkObject(FeatureFlags)
view.update(defaultState)
// editMode gets called when the view is initialized.
verify(exactly = 2) { toolbar.editMode(Toolbar.CursorPlacement.ALL) }
}
@Test
fun `URL gets set to the states query`() {
val toolbarView = buildToolbarView(false)
toolbarView.update(defaultState.copy(query = "Query"))
assertEquals("Query", toolbarView.view.url)
}
@Test
fun `URL gets set to the states pastedText if exists`() {
val toolbarView = buildToolbarView(false)
toolbarView.update(defaultState.copy(query = "Query", pastedText = "Pasted"))
assertEquals("Pasted", toolbarView.view.url)
}
@Test
fun `searchTerms get set if pastedText is null or empty`() {
val toolbarView = buildToolbarView(false)
toolbarView.update(defaultState.copy(query = "Query", pastedText = "", searchTerms = "Search Terms"))
verify { toolbar.setSearchTerms("Search Terms") }
}
@Test
fun `searchTerms don't get set if pastedText has a value`() {
val toolbarView = buildToolbarView(false)
toolbarView.update(
defaultState.copy(query = "Query", pastedText = "PastedText", searchTerms = "Search Terms"),
)
verify(exactly = 0) { toolbar.setSearchTerms("Search Terms") }
}
@Test
fun `WHEN the default general search engine is selected THEN show text for default engine`() {
val toolbarView = buildToolbarView(false)
val defaultEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = defaultEngine.name + ", " + context.getString(R.string.search_hint)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns defaultEngine.id
every { searchState.searchEngines } returns listOf(defaultEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(defaultEngine, true)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a general search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val generalEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = generalEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns generalEngine.id
every { searchState.searchEngines } returns listOf(generalEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(generalEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a topic specific search engine is selected THEN show hint for topic specific engine`() {
val toolbarView = buildToolbarView(false)
val topicSpecificEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, false)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.application_search_hint)
val expectedContentDescription = topicSpecificEngine.name + ", " + context.getString(R.string.application_search_hint)
every { fragment.requireContext().getString(R.string.application_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns topicSpecificEngine.id
every { searchState.searchEngines } returns listOf(topicSpecificEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(topicSpecificEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN the default additional general search engine is selected THEN show hint for default engine`() {
val toolbarView = buildToolbarView(false)
val defaultEngine = buildSearchEngine(SearchEngine.Type.BUNDLED_ADDITIONAL, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = defaultEngine.name + ", " + context.getString(R.string.search_hint)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns defaultEngine.id
every { searchState.searchEngines } returns listOf(defaultEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(defaultEngine, true)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a general additional search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val generalEngine = buildSearchEngine(SearchEngine.Type.BUNDLED_ADDITIONAL, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = generalEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns generalEngine.id
every { searchState.searchEngines } returns listOf(generalEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(generalEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN the default custom search engine is selected THEN show hint for default engine`() {
val toolbarView = buildToolbarView(false)
val customEngine = buildSearchEngine(SearchEngine.Type.CUSTOM, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = customEngine.name + ", " + context.getString(R.string.search_hint)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns customEngine.id
every { searchState.searchEngines } returns listOf(customEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(customEngine, true)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a custom search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val customEngine = buildSearchEngine(SearchEngine.Type.CUSTOM, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = customEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns customEngine.id
every { searchState.searchEngines } returns listOf(customEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(customEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN history is selected as engine THEN show hint specific for history`() {
val toolbarView = buildToolbarView(false)
val historyEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.HISTORY_SEARCH_ENGINE_ID)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.history_search_hint)
val expectedContentDescription = historyEngine.name + ", " + context.getString(R.string.history_search_hint)
every { fragment.requireContext().getString(R.string.history_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns historyEngine.id
every { searchState.searchEngines } returns listOf(historyEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(historyEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN bookmarks is selected as engine THEN show hint specific for bookmarks`() {
val toolbarView = buildToolbarView(false)
val bookmarksEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.BOOKMARKS_SEARCH_ENGINE_ID)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.bookmark_search_hint)
val expectedContentDescription = bookmarksEngine.name + ", " + context.getString(R.string.bookmark_search_hint)
every { fragment.requireContext().getString(R.string.bookmark_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns bookmarksEngine.id
every { searchState.searchEngines } returns listOf(bookmarksEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(bookmarksEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN tabs is selected as engine THEN show hint specific for tabs`() {
val toolbarView = buildToolbarView(false)
val tabsEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.TABS_SEARCH_ENGINE_ID)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.tab_search_hint)
val expectedContentDescription = tabsEngine.name + ", " + context.getString(R.string.tab_search_hint)
every { fragment.requireContext().getString(R.string.tab_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns tabsEngine.id
every { searchState.searchEngines } returns listOf(tabsEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(tabsEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@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
every { isTabletAndTabStripEnabled } 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
every { isTabletAndTabStripEnabled } returns false
}
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,
)
}
}
}
@Test
fun `GIVEN show bookmark suggestions and unified search are both enabled WHEN the toolbar view is initialized THEN add bookmark storage to autocomplete providers`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val bookmarksStorage: PlacesBookmarksStorage = 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
every { core.bookmarksStorage } returns bookmarksStorage
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
every { shouldShowHistorySuggestions } returns true
every { shouldShowBookmarkSuggestions } returns true
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(historyProvider, bookmarksStorage, domainsProvider),
refreshAutocomplete = true,
)
}
}
}
@Test
fun `GIVEN show bookmark suggestions is disabled and unified search is enabled WHEN the toolbar view is initialized THEN don't add bookmark storage to autocomplete providers`() {
mockkConstructor(ToolbarAutocompleteFeature::class) {
val historyProvider: PlacesHistoryStorage = mockk(relaxed = true)
val bookmarksStorage: PlacesBookmarksStorage = 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
every { core.bookmarksStorage } returns bookmarksStorage
}
val settings: Settings = mockk(relaxed = true) {
every { showUnifiedSearchFeature } returns true
every { shouldShowHistorySuggestions } returns true
every { shouldShowBookmarkSuggestions } returns false
}
val toolbarView = buildToolbarView(
isPrivate = false,
settings = settings,
components = components,
)
toolbarView.update(defaultState)
verify {
toolbarView.autocompleteFeature.updateAutocompleteProviders(
providers = listOf(historyProvider, domainsProvider),
refreshAutocomplete = true,
)
}
}
}
private fun buildToolbarView(
isPrivate: Boolean,
settings: Settings = context.settings(),
components: Components = mockk(relaxed = true),
) = ToolbarView(
settings = settings,
components = components,
interactor = interactor,
isPrivate = isPrivate,
view = toolbar,
fromHomeFragment = false,
)
private fun buildSearchEngine(
type: SearchEngine.Type,
isGeneral: Boolean,
id: String = UUID.randomUUID().toString(),
) = SearchEngine(
id = id,
name = UUID.randomUUID().toString(),
icon = testContext.getDrawable(R.drawable.ic_search)!!.toBitmap(),
type = type,
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(),
)