Add tests for search (#12437)
parent
e9fb1a61c7
commit
1ff64cab67
|
@ -96,9 +96,7 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen
|
||||||
is SearchFragmentAction.UpdateQuery ->
|
is SearchFragmentAction.UpdateQuery ->
|
||||||
state.copy(query = action.query)
|
state.copy(query = action.query)
|
||||||
is SearchFragmentAction.SelectNewDefaultSearchEngine ->
|
is SearchFragmentAction.SelectNewDefaultSearchEngine ->
|
||||||
state.copy(
|
state.copy(searchEngineSource = SearchEngineSource.Default(action.engine))
|
||||||
searchEngineSource = SearchEngineSource.Default(action.engine)
|
|
||||||
)
|
|
||||||
is SearchFragmentAction.AllowSearchSuggestionsInPrivateModePrompt ->
|
is SearchFragmentAction.AllowSearchSuggestionsInPrivateModePrompt ->
|
||||||
state.copy(showSearchSuggestionsHint = action.show)
|
state.copy(showSearchSuggestionsHint = action.show)
|
||||||
is SearchFragmentAction.SetShowSearchSuggestions ->
|
is SearchFragmentAction.SetShowSearchSuggestions ->
|
||||||
|
|
|
@ -34,16 +34,15 @@ class ShortcutsSuggestionProvider(
|
||||||
override suspend fun onInputChanged(text: String): List<AwesomeBar.Suggestion> {
|
override suspend fun onInputChanged(text: String): List<AwesomeBar.Suggestion> {
|
||||||
val suggestions = mutableListOf<AwesomeBar.Suggestion>()
|
val suggestions = mutableListOf<AwesomeBar.Suggestion>()
|
||||||
|
|
||||||
searchEngineProvider.installedSearchEngines(context).list.forEach {
|
searchEngineProvider.installedSearchEngines(context).list.mapTo(suggestions) {
|
||||||
suggestions.add(
|
AwesomeBar.Suggestion(
|
||||||
AwesomeBar.Suggestion(
|
provider = this,
|
||||||
provider = this,
|
id = it.identifier,
|
||||||
id = it.identifier,
|
icon = it.icon,
|
||||||
icon = it.icon,
|
title = it.name,
|
||||||
title = it.name,
|
onSuggestionClicked = {
|
||||||
onSuggestionClicked = {
|
selectShortcutEngine(it)
|
||||||
selectShortcutEngine(it)
|
}
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +54,8 @@ class ShortcutsSuggestionProvider(
|
||||||
title = context.getString(R.string.search_shortcuts_engine_settings),
|
title = context.getString(R.string.search_shortcuts_engine_settings),
|
||||||
onSuggestionClicked = {
|
onSuggestionClicked = {
|
||||||
selectShortcutEngineSettings()
|
selectShortcutEngineSettings()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return suggestions
|
return suggestions
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,24 +22,24 @@ import org.mozilla.fenix.theme.ThemeManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for the Toolbar Interactor. This interface is implemented by objects that want
|
* Interface for the Toolbar Interactor. This interface is implemented by objects that want
|
||||||
* to respond to user interaction on the [BrowserToolbarView]
|
* to respond to user interaction on the [ToolbarView]
|
||||||
*/
|
*/
|
||||||
interface ToolbarInteractor {
|
interface ToolbarInteractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a user hits the return key while [BrowserToolbarView] has focus.
|
* Called when a user hits the return key while [ToolbarView] has focus.
|
||||||
* @param url the text inside the [BrowserToolbarView] when committed
|
* @param url the text inside the [ToolbarView] when committed
|
||||||
*/
|
*/
|
||||||
fun onUrlCommitted(url: String)
|
fun onUrlCommitted(url: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a user removes focus from the [BrowserToolbarView]
|
* Called when a user removes focus from the [ToolbarView]
|
||||||
*/
|
*/
|
||||||
fun onEditingCanceled()
|
fun onEditingCanceled()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever the text inside the [BrowserToolbarView] changes
|
* Called whenever the text inside the [ToolbarView] changes
|
||||||
* @param text the current text displayed by [BrowserToolbarView]
|
* @param text the current text displayed by [ToolbarView]
|
||||||
*/
|
*/
|
||||||
fun onTextChanged(text: String)
|
fun onTextChanged(text: String)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ class ToolbarView(
|
||||||
|
|
||||||
override fun onTextChanged(text: String) {
|
override fun onTextChanged(text: String) {
|
||||||
url = text
|
url = text
|
||||||
this@ToolbarView.interactor.onTextChanged(text)
|
interactor.onTextChanged(text)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,17 @@
|
||||||
package org.mozilla.fenix.search
|
package org.mozilla.fenix.search
|
||||||
|
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import mozilla.components.browser.search.SearchEngine
|
import mozilla.components.browser.search.SearchEngine
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertNotSame
|
import org.junit.Assert.assertNotSame
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
class SearchFragmentStoreTest {
|
class SearchFragmentStoreTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -57,6 +61,43 @@ class SearchFragmentStoreTest {
|
||||||
assertEquals(false, store.state.showSearchShortcuts)
|
assertEquals(false, store.state.showSearchShortcuts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun showSearchSuggestions() = runBlocking {
|
||||||
|
val initialState = emptyDefaultState()
|
||||||
|
val store = SearchFragmentStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(SearchFragmentAction.SetShowSearchSuggestions(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertTrue(store.state.showSearchSuggestions)
|
||||||
|
|
||||||
|
store.dispatch(SearchFragmentAction.SetShowSearchSuggestions(false)).join()
|
||||||
|
assertFalse(store.state.showSearchSuggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun allowSearchInPrivateMode() = runBlocking {
|
||||||
|
val initialState = emptyDefaultState()
|
||||||
|
val store = SearchFragmentStore(initialState)
|
||||||
|
|
||||||
|
store.dispatch(SearchFragmentAction.AllowSearchSuggestionsInPrivateModePrompt(true)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertTrue(store.state.showSearchSuggestionsHint)
|
||||||
|
|
||||||
|
store.dispatch(SearchFragmentAction.AllowSearchSuggestionsInPrivateModePrompt(false)).join()
|
||||||
|
assertFalse(store.state.showSearchSuggestionsHint)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun selectNewDefaultEngine() = runBlocking {
|
||||||
|
val initialState = emptyDefaultState()
|
||||||
|
val store = SearchFragmentStore(initialState)
|
||||||
|
val engine = mockk<SearchEngine>()
|
||||||
|
|
||||||
|
store.dispatch(SearchFragmentAction.SelectNewDefaultSearchEngine(engine)).join()
|
||||||
|
assertNotSame(initialState, store.state)
|
||||||
|
assertEquals(SearchEngineSource.Default(engine), store.state.searchEngineSource)
|
||||||
|
}
|
||||||
|
|
||||||
private fun emptyDefaultState(): SearchFragmentState = SearchFragmentState(
|
private fun emptyDefaultState(): SearchFragmentState = SearchFragmentState(
|
||||||
tabId = null,
|
tabId = null,
|
||||||
url = "",
|
url = "",
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* 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.awesomebar
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.unmockkStatic
|
||||||
|
import io.mockk.verifySequence
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
|
import mozilla.components.browser.search.SearchEngine
|
||||||
|
import mozilla.components.browser.search.provider.SearchEngineList
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.components.searchengine.FenixSearchEngineProvider
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class ShortcutsSuggestionProviderTest {
|
||||||
|
|
||||||
|
private lateinit var context: Context
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
mockkStatic(AppCompatResources::class)
|
||||||
|
context = mockk {
|
||||||
|
every { getString(R.string.search_shortcuts_engine_settings) } returns "Search engine settings"
|
||||||
|
}
|
||||||
|
|
||||||
|
every { AppCompatResources.getDrawable(context, R.drawable.ic_settings) } returns null
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun teardown() {
|
||||||
|
unmockkStatic(AppCompatResources::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `should clear is always false`() {
|
||||||
|
val provider = ShortcutsSuggestionProvider(mockk(), mockk(), mockk(), mockk())
|
||||||
|
assertFalse(provider.shouldClearSuggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `returns suggestions from search engine provider`() = runBlockingTest {
|
||||||
|
val engineOne = mockk<SearchEngine> {
|
||||||
|
every { identifier } returns "1"
|
||||||
|
every { name } returns "EngineOne"
|
||||||
|
every { icon } returns mockk()
|
||||||
|
}
|
||||||
|
val engineTwo = mockk<SearchEngine> {
|
||||||
|
every { identifier } returns "2"
|
||||||
|
every { name } returns "EngineTwo"
|
||||||
|
every { icon } returns mockk()
|
||||||
|
}
|
||||||
|
val searchEngineProvider = mockk<FenixSearchEngineProvider> {
|
||||||
|
every { installedSearchEngines(context) } returns SearchEngineList(
|
||||||
|
list = listOf(engineOne, engineTwo),
|
||||||
|
default = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val provider = ShortcutsSuggestionProvider(searchEngineProvider, context, mockk(), mockk())
|
||||||
|
|
||||||
|
val suggestions = provider.onInputChanged("")
|
||||||
|
assertEquals(3, suggestions.size)
|
||||||
|
|
||||||
|
assertEquals(provider, suggestions[0].provider)
|
||||||
|
assertEquals(engineOne.identifier, suggestions[0].id)
|
||||||
|
assertEquals(engineOne.icon, suggestions[0].icon)
|
||||||
|
assertEquals(engineOne.name, suggestions[0].title)
|
||||||
|
|
||||||
|
assertEquals(provider, suggestions[1].provider)
|
||||||
|
assertEquals(engineTwo.identifier, suggestions[1].id)
|
||||||
|
assertEquals(engineTwo.icon, suggestions[1].icon)
|
||||||
|
assertEquals(engineTwo.name, suggestions[1].title)
|
||||||
|
|
||||||
|
assertEquals(provider, suggestions[2].provider)
|
||||||
|
assertEquals("Search engine settings", suggestions[2].id)
|
||||||
|
assertEquals("Search engine settings", suggestions[2].title)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `callbacks are triggered when suggestions are clicked`() = runBlockingTest {
|
||||||
|
val engineOne = mockk<SearchEngine>(relaxed = true)
|
||||||
|
val searchEngineProvider = mockk<FenixSearchEngineProvider> {
|
||||||
|
every { installedSearchEngines(context) } returns SearchEngineList(
|
||||||
|
list = listOf(engineOne),
|
||||||
|
default = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val selectShortcutEngine = mockk<(SearchEngine) -> Unit>(relaxed = true)
|
||||||
|
val selectShortcutEngineSettings = mockk<() -> Unit>(relaxed = true)
|
||||||
|
val provider = ShortcutsSuggestionProvider(
|
||||||
|
searchEngineProvider,
|
||||||
|
context,
|
||||||
|
selectShortcutEngine,
|
||||||
|
selectShortcutEngineSettings
|
||||||
|
)
|
||||||
|
|
||||||
|
val suggestions = provider.onInputChanged("")
|
||||||
|
assertEquals(2, suggestions.size)
|
||||||
|
|
||||||
|
suggestions[0].onSuggestionClicked?.invoke()
|
||||||
|
suggestions[1].onSuggestionClicked?.invoke()
|
||||||
|
|
||||||
|
verifySequence {
|
||||||
|
selectShortcutEngine(engineOne)
|
||||||
|
selectShortcutEngineSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* 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 io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.spyk
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||||
|
import mozilla.components.concept.engine.Engine
|
||||||
|
import mozilla.components.concept.toolbar.Toolbar
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class ToolbarViewTest {
|
||||||
|
|
||||||
|
@MockK(relaxed = true) private lateinit var interactor: ToolbarInteractor
|
||||||
|
@MockK private lateinit var engine: Engine
|
||||||
|
private lateinit var toolbar: BrowserToolbar
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
toolbar = spyk(BrowserToolbar(testContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `sets up interactor listeners`() {
|
||||||
|
val urlCommitListener = slot<(String) -> Boolean>()
|
||||||
|
val editListener = slot<Toolbar.OnEditListener>()
|
||||||
|
every { toolbar.setOnUrlCommitListener(capture(urlCommitListener)) } just Runs
|
||||||
|
every { toolbar.setOnEditListener(capture(editListener)) } just Runs
|
||||||
|
|
||||||
|
buildToolbarView(isPrivate = false)
|
||||||
|
|
||||||
|
assertFalse(urlCommitListener.captured("test"))
|
||||||
|
verify { interactor.onUrlCommitted("test") }
|
||||||
|
|
||||||
|
assertFalse(editListener.captured.onCancelEditing())
|
||||||
|
verify { interactor.onEditingCanceled() }
|
||||||
|
|
||||||
|
editListener.captured.onTextChanged("https://example.com")
|
||||||
|
verify { interactor.onTextChanged("https://example.com") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildToolbarView(isPrivate: Boolean) = ToolbarView(
|
||||||
|
testContext,
|
||||||
|
interactor,
|
||||||
|
historyStorage = null,
|
||||||
|
isPrivate = isPrivate,
|
||||||
|
view = toolbar,
|
||||||
|
engine = engine
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue