For #19916 - Add last viewed tab to home screen
Co-authored-by: Jonathan Almeida <jalmeida@mozilla.com>upstream-sync
parent
42d87d1a7a
commit
9d3cf79051
@ -0,0 +1,24 @@
|
||||
/* 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.ext
|
||||
|
||||
import mozilla.components.browser.state.selector.selectedTab
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
|
||||
/**
|
||||
* Returns the currently selected tab if there's one as a list.
|
||||
*
|
||||
* @return A list of the currently selected tab or an empty list.
|
||||
*/
|
||||
fun BrowserState.asRecentTabs(): List<TabSessionState> {
|
||||
val tab = selectedTab
|
||||
|
||||
return if (tab != null && !tab.content.private) {
|
||||
listOfNotNull(tab)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/* 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.home.recenttabs.controller
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import mozilla.components.feature.tabs.TabsUseCases.SelectTabUseCase
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import org.mozilla.fenix.ext.navigateBlockingForAsyncNavGraph
|
||||
import org.mozilla.fenix.home.HomeFragmentDirections
|
||||
import org.mozilla.fenix.home.recenttabs.interactor.RecentTabInteractor
|
||||
|
||||
/**
|
||||
* An interface that handles the view manipulation of the recent tabs in the Home screen.
|
||||
*/
|
||||
interface RecentTabController {
|
||||
|
||||
/**
|
||||
* @see [RecentTabInteractor.onRecentTabClicked]
|
||||
*/
|
||||
fun handleRecentTabClicked(tabId: String)
|
||||
|
||||
/**
|
||||
* @see [RecentTabInteractor.onRecentTabShowAllClicked]
|
||||
*/
|
||||
fun handleRecentTabShowAllClicked()
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of [RecentTabController].
|
||||
*
|
||||
* @param selectTabUseCase [SelectTabUseCase] used selecting a tab.
|
||||
* @param navController [NavController] used for navigation.
|
||||
*/
|
||||
class DefaultRecentTabsController(
|
||||
private val selectTabUseCase: SelectTabUseCase,
|
||||
private val navController: NavController
|
||||
) : RecentTabController {
|
||||
|
||||
override fun handleRecentTabClicked(tabId: String) {
|
||||
selectTabUseCase.invoke(tabId)
|
||||
navController.navigateBlockingForAsyncNavGraph(R.id.browserFragment)
|
||||
}
|
||||
|
||||
override fun handleRecentTabShowAllClicked() {
|
||||
navController.nav(
|
||||
R.id.homeFragment,
|
||||
HomeFragmentDirections.actionGlobalTabsTrayFragment()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/* 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.home.recenttabs.interactor
|
||||
|
||||
/**
|
||||
* Interface for recent tab related actions in the Home screen.
|
||||
*/
|
||||
interface RecentTabInteractor {
|
||||
/**
|
||||
* Opens the given tab. Called when a user clicks on a recent tab.
|
||||
*
|
||||
* @param tabId The ID of the tab to open.
|
||||
*/
|
||||
fun onRecentTabClicked(tabId: String)
|
||||
|
||||
/**
|
||||
* Show the tabs tray. Called when a user clicks on the "Show all" button besides the recent
|
||||
* tabs.
|
||||
*/
|
||||
fun onRecentTabShowAllClicked()
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* 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.home.recenttabs.view
|
||||
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.recent_tabs_list_row.*
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.home.recenttabs.interactor.RecentTabInteractor
|
||||
import org.mozilla.fenix.utils.view.ViewHolder
|
||||
|
||||
/**
|
||||
* View holder for a recent tab item.
|
||||
*
|
||||
* @param interactor [RecentTabInteractor] which will have delegated to all user interactions.
|
||||
*/
|
||||
class RecentTabViewHolder(
|
||||
view: View,
|
||||
private val interactor: RecentTabInteractor
|
||||
) : ViewHolder(view) {
|
||||
|
||||
fun bindTab(tab: TabSessionState) {
|
||||
recent_tab_title.text = tab.content.title
|
||||
recent_tab_icon.setImageBitmap(tab.content.icon)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
interactor.onRecentTabClicked(tab.id)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.recent_tabs_list_row
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/* 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.home.recenttabs.view
|
||||
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.recent_tabs_header.*
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.home.recenttabs.interactor.RecentTabInteractor
|
||||
import org.mozilla.fenix.utils.view.ViewHolder
|
||||
|
||||
/**
|
||||
* View holder for the recent tabs header and "Show all" button.
|
||||
*
|
||||
* @param interactor [RecentTabInteractor] which will have delegated to all user interactions.
|
||||
*/
|
||||
class RecentTabsHeaderViewHolder(
|
||||
view: View,
|
||||
private val interactor: RecentTabInteractor
|
||||
) : ViewHolder(view) {
|
||||
|
||||
init {
|
||||
show_all_button.setOnClickListener {
|
||||
interactor.onRecentTabShowAllClicked()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.recent_tabs_header
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/* 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.home.sessioncontrol
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.map
|
||||
import mozilla.components.browser.state.selector.normalTabs
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.lib.state.helpers.AbstractBinding
|
||||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
|
||||
import org.mozilla.fenix.home.HomeFragmentAction
|
||||
import org.mozilla.fenix.home.HomeFragmentStore
|
||||
|
||||
/**
|
||||
* View-bound feature that dispatches recent tab changes to the [HomeFragmentStore] when the
|
||||
* [BrowserStore] is updated.
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RecentTabsListFeature(
|
||||
private val browserStore: BrowserStore,
|
||||
private val homeStore: HomeFragmentStore
|
||||
) : AbstractBinding<BrowserState>(browserStore) {
|
||||
|
||||
override suspend fun onState(flow: Flow<BrowserState>) {
|
||||
flow.map { it.selectedTabId }
|
||||
.ifChanged()
|
||||
.collect { selectedTabId ->
|
||||
// Attempt to get the selected normal tab since here may not be a selected tab or
|
||||
// the selected tab may be a private tab.
|
||||
val selectedTab = browserStore.state.normalTabs.firstOrNull {
|
||||
it.id == selectedTabId
|
||||
}
|
||||
val recentTabsList = if (selectedTab != null) {
|
||||
listOf(selectedTab)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
homeStore.dispatch(HomeFragmentAction.RecentTabsChange(recentTabsList))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/Header20TextStyle"
|
||||
android:id="@+id/header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/recent_tabs_header"
|
||||
android:layout_marginVertical="16dp"
|
||||
android:maxLines="2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/show_all_button"
|
||||
style="@style/Button12TextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/recent_tabs_show_all"
|
||||
android:textColor="@color/home_show_all_button_text"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/home_list_row_background"
|
||||
android:clipToPadding="false"
|
||||
android:elevation="@dimen/home_collection_elevation"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recent_tab_icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recent_tab_title"
|
||||
style="@style/Body16TextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="start"
|
||||
android:maxLines="1"
|
||||
android:minLines="1"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="@id/recent_tab_icon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@+id/recent_tab_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/recent_tab_icon"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,64 @@
|
||||
/* 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.ext
|
||||
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.createTab
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class BrowserStateTest {
|
||||
|
||||
@Test
|
||||
fun `WHEN there is a selected tab THEN asRecentTabs returns the selected tab as a list`() {
|
||||
val tab = createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1"
|
||||
)
|
||||
val tabs = listOf(tab)
|
||||
val state = BrowserState(
|
||||
tabs = tabs,
|
||||
selectedTabId = tab.id
|
||||
)
|
||||
val recentTabs = state.asRecentTabs()
|
||||
|
||||
assertEquals(tabs, recentTabs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN there is no selected tab THEN asRecentTabs returns an empty list`() {
|
||||
val state = BrowserState(
|
||||
tabs = listOf(
|
||||
createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1"
|
||||
)
|
||||
)
|
||||
)
|
||||
val recentTabs = state.asRecentTabs()
|
||||
|
||||
assertEquals(0, recentTabs.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN the selected tab is private THEN asRecentTabs returns an empty list`() {
|
||||
val tab = createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1",
|
||||
private = true
|
||||
)
|
||||
val tabs = listOf(tab)
|
||||
val state = BrowserState(
|
||||
tabs = tabs,
|
||||
selectedTabId = tab.id
|
||||
)
|
||||
val recentTabs = state.asRecentTabs()
|
||||
|
||||
assertEquals(0, recentTabs.size)
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/* 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.home
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import mozilla.components.browser.state.action.TabListAction
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.createTab
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.support.test.ext.joinBlocking
|
||||
import mozilla.components.support.test.libstate.ext.waitUntilIdle
|
||||
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.home.sessioncontrol.RecentTabsListFeature
|
||||
|
||||
class RecentTabsListFeatureTest {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@get:Rule
|
||||
val coroutinesTestRule = MainCoroutineRule(TestCoroutineDispatcher())
|
||||
|
||||
@Test
|
||||
fun `GIVEN no selected tab WHEN the feature starts THEN dispatch an empty list`() {
|
||||
val browserStore = BrowserStore()
|
||||
val homeStore = HomeFragmentStore()
|
||||
val feature = RecentTabsListFeature(
|
||||
browserStore = browserStore,
|
||||
homeStore = homeStore
|
||||
)
|
||||
|
||||
feature.start()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(0, homeStore.state.recentTabs.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a selected tab WHEN the feature starts THEN dispatch the selected tab as a recent tab list`() {
|
||||
val tab = createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1"
|
||||
)
|
||||
val tabs = listOf(tab)
|
||||
val browserStore = BrowserStore(
|
||||
BrowserState(
|
||||
tabs = tabs,
|
||||
selectedTabId = "1"
|
||||
)
|
||||
)
|
||||
val homeStore = HomeFragmentStore()
|
||||
val feature = RecentTabsListFeature(
|
||||
browserStore = browserStore,
|
||||
homeStore = homeStore
|
||||
)
|
||||
|
||||
feature.start()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(1, homeStore.state.recentTabs.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN the browser state has an updated select tab THEN dispatch the new recent tab list`() {
|
||||
val tab1 = createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1"
|
||||
)
|
||||
val tab2 = createTab(
|
||||
url = "https://www.firefox.com",
|
||||
id = "2"
|
||||
)
|
||||
val tabs = listOf(tab1, tab2)
|
||||
val browserStore = BrowserStore(
|
||||
BrowserState(
|
||||
tabs = tabs,
|
||||
selectedTabId = "1"
|
||||
)
|
||||
)
|
||||
val homeStore = HomeFragmentStore()
|
||||
val feature = RecentTabsListFeature(
|
||||
browserStore = browserStore,
|
||||
homeStore = homeStore
|
||||
)
|
||||
|
||||
feature.start()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(1, homeStore.state.recentTabs.size)
|
||||
assertEquals(tab1, homeStore.state.recentTabs[0])
|
||||
|
||||
browserStore.dispatch(TabListAction.SelectTabAction(tab2.id)).joinBlocking()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(1, homeStore.state.recentTabs.size)
|
||||
assertEquals(tab2, homeStore.state.recentTabs[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN the browser state selects a private tab THEN dispatch an empty list`() {
|
||||
val normalTab = createTab(
|
||||
url = "https://www.mozilla.org",
|
||||
id = "1"
|
||||
)
|
||||
val privateTab = createTab(
|
||||
url = "https://www.firefox.com",
|
||||
id = "2",
|
||||
private = true
|
||||
)
|
||||
val tabs = listOf(normalTab, privateTab)
|
||||
val browserStore = BrowserStore(
|
||||
BrowserState(
|
||||
tabs = tabs,
|
||||
selectedTabId = "1"
|
||||
)
|
||||
)
|
||||
val homeStore = HomeFragmentStore()
|
||||
val feature = RecentTabsListFeature(
|
||||
browserStore = browserStore,
|
||||
homeStore = homeStore
|
||||
)
|
||||
|
||||
feature.start()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(1, homeStore.state.recentTabs.size)
|
||||
assertEquals(normalTab, homeStore.state.recentTabs[0])
|
||||
|
||||
browserStore.dispatch(TabListAction.SelectTabAction(privateTab.id)).joinBlocking()
|
||||
|
||||
homeStore.waitUntilIdle()
|
||||
|
||||
assertEquals(0, homeStore.state.recentTabs.size)
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/* 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.home.recenttabs.controller
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDirections
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import mozilla.components.browser.state.action.TabListAction
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.createTab
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.feature.tabs.TabsUseCases
|
||||
import mozilla.components.support.test.ext.joinBlocking
|
||||
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.navigateBlockingForAsyncNavGraph
|
||||
import org.mozilla.fenix.helpers.DisableNavGraphProviderAssertionRule
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RecentTabControllerTest {
|
||||
|
||||
private val testDispatcher = TestCoroutineDispatcher()
|
||||
|
||||
@get:Rule
|
||||
val coroutinesTestRule = MainCoroutineRule(testDispatcher)
|
||||
|
||||
@get:Rule
|
||||
val disableNavGraphProviderAssertionRule = DisableNavGraphProviderAssertionRule()
|
||||
|
||||
private val navController: NavController = mockk(relaxed = true)
|
||||
private val selectTabUseCase: TabsUseCases = mockk(relaxed = true)
|
||||
|
||||
private lateinit var store: BrowserStore
|
||||
private lateinit var controller: RecentTabController
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
store = BrowserStore(
|
||||
BrowserState()
|
||||
)
|
||||
controller = spyk(DefaultRecentTabsController(
|
||||
selectTabUseCase = selectTabUseCase.selectTab,
|
||||
navController = navController
|
||||
))
|
||||
|
||||
every { navController.currentDestination } returns mockk {
|
||||
every { id } returns R.id.homeFragment
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handleRecentTabClicked() {
|
||||
val tab = createTab(
|
||||
url = "https://mozilla.org",
|
||||
title = "Mozilla"
|
||||
)
|
||||
store.dispatch(TabListAction.AddTabAction(tab)).joinBlocking()
|
||||
store.dispatch(TabListAction.SelectTabAction(tab.id)).joinBlocking()
|
||||
|
||||
controller.handleRecentTabClicked(tab.id)
|
||||
|
||||
verify {
|
||||
selectTabUseCase.selectTab.invoke(tab.id)
|
||||
navController.navigateBlockingForAsyncNavGraph(R.id.browserFragment)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handleRecentTabShowAllClicked() {
|
||||
controller.handleRecentTabShowAllClicked()
|
||||
|
||||
verify {
|
||||
navController.navigate(
|
||||
match<NavDirections> { it.actionId == R.id.action_global_tabsTrayFragment },
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/* 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.home.recenttabs.view
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.recent_tabs_list_row.view.*
|
||||
import mozilla.components.browser.state.state.createTab
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class RecentTabViewHolderTest {
|
||||
|
||||
private lateinit var view: View
|
||||
private lateinit var interactor: SessionControlInteractor
|
||||
|
||||
private val tab = createTab(
|
||||
url = "https://mozilla.org",
|
||||
title = "Mozilla"
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(RecentTabViewHolder.LAYOUT_ID, null)
|
||||
interactor = mockk(relaxed = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a new recent tab on bind THEN set the title text`() {
|
||||
RecentTabViewHolder(view, interactor).bindTab(tab)
|
||||
|
||||
assertEquals(tab.content.title, view.recent_tab_title.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN a recent tab item is clicked THEN interactor iis called`() {
|
||||
RecentTabViewHolder(view, interactor).bindTab(tab)
|
||||
|
||||
view.performClick()
|
||||
|
||||
verify { interactor.onRecentTabClicked(tab.id) }
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/* 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.home.recenttabs.view
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.recent_tabs_header.view.*
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class RecentTabsHeaderViewHolderTest {
|
||||
|
||||
private lateinit var view: View
|
||||
private lateinit var interactor: SessionControlInteractor
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(RecentTabsHeaderViewHolder.LAYOUT_ID, null)
|
||||
interactor = mockk(relaxed = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN show all button is clicked THEN interactor iis called`() {
|
||||
RecentTabsHeaderViewHolder(view, interactor)
|
||||
|
||||
view.show_all_button.performClick()
|
||||
|
||||
verify { interactor.onRecentTabShowAllClicked() }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue