diff --git a/app/src/main/java/org/mozilla/fenix/components/Core.kt b/app/src/main/java/org/mozilla/fenix/components/Core.kt index 354f3caac9..91a0f6a06a 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Core.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Core.kt @@ -38,6 +38,7 @@ import mozilla.components.feature.pwa.ManifestStorage import mozilla.components.feature.pwa.WebAppShortcutManager import mozilla.components.feature.readerview.ReaderViewMiddleware import mozilla.components.feature.recentlyclosed.RecentlyClosedMiddleware +import mozilla.components.feature.recentlyclosed.RecentlyClosedTabsStorage import mozilla.components.feature.search.middleware.AdsTelemetryMiddleware import mozilla.components.feature.search.middleware.SearchMiddleware import mozilla.components.feature.search.region.RegionMiddleware @@ -193,7 +194,7 @@ class Core( val middlewareList = mutableListOf( LastAccessMiddleware(), - RecentlyClosedMiddleware(context, RECENTLY_CLOSED_MAX, engine), + RecentlyClosedMiddleware(recentlyClosedTabsStorage, RECENTLY_CLOSED_MAX), DownloadMiddleware(context, DownloadService::class.java), ReaderViewMiddleware(), TelemetryMiddleware( @@ -311,6 +312,8 @@ class Core( */ val lazyRemoteTabsStorage = lazyMonitored { RemoteTabsStorage() } + val recentlyClosedTabsStorage = lazyMonitored { RecentlyClosedTabsStorage(context, engine, crashReporter) } + // For most other application code (non-startup), these wrappers are perfectly fine and more ergonomic. val historyStorage: PlacesHistoryStorage get() = lazyHistoryStorage.value val bookmarksStorage: PlacesBookmarksStorage get() = lazyBookmarksStorage.value diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedAdapter.kt index a3a6abb34a..adef6fb8e1 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedAdapter.kt @@ -8,15 +8,15 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import org.mozilla.fenix.selection.SelectionHolder class RecentlyClosedAdapter( private val interactor: RecentlyClosedFragmentInteractor -) : ListAdapter(DiffCallback), - SelectionHolder { +) : ListAdapter(DiffCallback), + SelectionHolder { - private var selectedTabs: Set = emptySet() + private var selectedTabs: Set = emptySet() override fun onCreateViewHolder( parent: ViewGroup, @@ -31,20 +31,20 @@ class RecentlyClosedAdapter( holder.bind(getItem(position)) } - override val selectedItems: Set + override val selectedItems: Set get() = selectedTabs - fun updateData(tabs: List, selectedTabs: Set) { + fun updateData(tabs: List, selectedTabs: Set) { this.selectedTabs = selectedTabs notifyItemRangeChanged(0, tabs.size) submitList(tabs) } - private object DiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: RecoverableTab, newItem: RecoverableTab) = + private object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: TabState, newItem: TabState) = oldItem.id == newItem.id - override fun areContentsTheSame(oldItem: RecoverableTab, newItem: RecoverableTab) = + override fun areContentsTheSame(oldItem: TabState, newItem: TabState) = oldItem == newItem } } diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedController.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedController.kt index 423a65929d..ea5b33a081 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedController.kt @@ -6,10 +6,13 @@ package org.mozilla.fenix.library.recentlyclosed import androidx.navigation.NavController import androidx.navigation.NavOptions +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import mozilla.components.browser.state.action.RecentlyClosedAction -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.prompt.ShareData +import mozilla.components.feature.recentlyclosed.RecentlyClosedTabsStorage import mozilla.components.feature.tabs.TabsUseCases import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity @@ -20,15 +23,15 @@ import org.mozilla.fenix.components.metrics.MetricController @Suppress("TooManyFunctions") interface RecentlyClosedController { - fun handleOpen(tab: RecoverableTab, mode: BrowsingMode? = null) - fun handleOpen(tabs: Set, mode: BrowsingMode? = null) - fun handleDelete(tab: RecoverableTab) - fun handleDelete(tabs: Set) - fun handleShare(tabs: Set) + fun handleOpen(tab: TabState, mode: BrowsingMode? = null) + fun handleOpen(tabs: Set, mode: BrowsingMode? = null) + fun handleDelete(tab: TabState) + fun handleDelete(tabs: Set) + fun handleShare(tabs: Set) fun handleNavigateToHistory() - fun handleRestore(item: RecoverableTab) - fun handleSelect(tab: RecoverableTab) - fun handleDeselect(tab: RecoverableTab) + fun handleRestore(item: TabState) + fun handleSelect(tab: TabState) + fun handleDeselect(tab: TabState) fun handleBackPressed(): Boolean } @@ -37,16 +40,18 @@ class DefaultRecentlyClosedController( private val navController: NavController, private val browserStore: BrowserStore, private val recentlyClosedStore: RecentlyClosedFragmentStore, + private val recentlyClosedTabsStorage: RecentlyClosedTabsStorage, private val tabsUseCases: TabsUseCases, private val activity: HomeActivity, private val metrics: MetricController, - private val openToBrowser: (item: RecoverableTab, mode: BrowsingMode?) -> Unit + private val lifecycleScope: CoroutineScope, + private val openToBrowser: (url: String, mode: BrowsingMode?) -> Unit ) : RecentlyClosedController { - override fun handleOpen(tab: RecoverableTab, mode: BrowsingMode?) { - openToBrowser(tab, mode) + override fun handleOpen(tab: TabState, mode: BrowsingMode?) { + openToBrowser(tab.url, mode) } - override fun handleOpen(tabs: Set, mode: BrowsingMode?) { + override fun handleOpen(tabs: Set, mode: BrowsingMode?) { if (mode == BrowsingMode.Normal) { metrics.track(Event.RecentlyClosedTabsMenuOpenInNormalTab) } else if (mode == BrowsingMode.Private) { @@ -56,26 +61,26 @@ class DefaultRecentlyClosedController( tabs.forEach { tab -> handleOpen(tab, mode) } } - override fun handleSelect(tab: RecoverableTab) { + override fun handleSelect(tab: TabState) { if (recentlyClosedStore.state.selectedTabs.isEmpty()) { metrics.track(Event.RecentlyClosedTabsEnterMultiselect) } recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Select(tab)) } - override fun handleDeselect(tab: RecoverableTab) { + override fun handleDeselect(tab: TabState) { if (recentlyClosedStore.state.selectedTabs.size == 1) { metrics.track(Event.RecentlyClosedTabsExitMultiselect) } recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Deselect(tab)) } - override fun handleDelete(tab: RecoverableTab) { + override fun handleDelete(tab: TabState) { metrics.track(Event.RecentlyClosedTabsDeleteTab) browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(tab)) } - override fun handleDelete(tabs: Set) { + override fun handleDelete(tabs: Set) { metrics.track(Event.RecentlyClosedTabsMenuDelete) recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll) tabs.forEach { tab -> @@ -91,7 +96,7 @@ class DefaultRecentlyClosedController( ) } - override fun handleShare(tabs: Set) { + override fun handleShare(tabs: Set) { metrics.track(Event.RecentlyClosedTabsMenuShare) val shareData = tabs.map { ShareData(url = it.url, title = it.title) } navController.navigate( @@ -101,18 +106,19 @@ class DefaultRecentlyClosedController( ) } - override fun handleRestore(item: RecoverableTab) { - metrics.track(Event.RecentlyClosedTabsOpenTab) + override fun handleRestore(item: TabState) { + lifecycleScope.launch { + metrics.track(Event.RecentlyClosedTabsOpenTab) + tabsUseCases.restore(item, recentlyClosedTabsStorage.engineStateStorage()) - tabsUseCases.restore(item) - - browserStore.dispatch( - RecentlyClosedAction.RemoveClosedTabAction(item) - ) + browserStore.dispatch( + RecentlyClosedAction.RemoveClosedTabAction(item) + ) - activity.openToBrowser( - from = BrowserDirection.FromRecentlyClosed - ) + activity.openToBrowser( + from = BrowserDirection.FromRecentlyClosed + ) + } } override fun handleBackPressed(): Boolean { diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt index fff9b6a133..8cfba0c779 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt @@ -12,6 +12,7 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map @@ -120,6 +121,8 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera activity = activity as HomeActivity, tabsUseCases = requireComponents.useCases.tabsUseCases, metrics = metrics, + recentlyClosedTabsStorage = requireComponents.core.recentlyClosedTabsStorage.value, + lifecycleScope = lifecycleScope, openToBrowser = ::openItem ) recentlyClosedInteractor = RecentlyClosedFragmentInteractor(recentlyClosedController) @@ -135,11 +138,11 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera _recentlyClosedFragmentView = null } - private fun openItem(tab: RecoverableTab, mode: BrowsingMode? = null) { + private fun openItem(url: String, mode: BrowsingMode? = null) { mode?.let { (activity as HomeActivity).browsingModeManager.mode = it } (activity as HomeActivity).openToBrowserAndLoad( - searchTermOrURL = tab.url, + searchTermOrURL = url, newTab = true, from = BrowserDirection.FromRecentlyClosed ) diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractor.kt index 15e3edb860..4699820ae0 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractor.kt @@ -4,7 +4,7 @@ package org.mozilla.fenix.library.recentlyclosed -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState /** * Interactor for the recently closed screen @@ -14,7 +14,7 @@ class RecentlyClosedFragmentInteractor( private val recentlyClosedController: RecentlyClosedController ) : RecentlyClosedInteractor { - override fun onDelete(tab: RecoverableTab) { + override fun onDelete(tab: TabState) { recentlyClosedController.handleDelete(tab) } @@ -22,15 +22,15 @@ class RecentlyClosedFragmentInteractor( recentlyClosedController.handleNavigateToHistory() } - override fun open(item: RecoverableTab) { + override fun open(item: TabState) { recentlyClosedController.handleRestore(item) } - override fun select(item: RecoverableTab) { + override fun select(item: TabState) { recentlyClosedController.handleSelect(item) } - override fun deselect(item: RecoverableTab) { + override fun deselect(item: TabState) { recentlyClosedController.handleDeselect(item) } } diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentStore.kt index 849f6bcd03..c9e851d32c 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentStore.kt @@ -4,7 +4,7 @@ package org.mozilla.fenix.library.recentlyclosed -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.lib.state.Action import mozilla.components.lib.state.State import mozilla.components.lib.state.Store @@ -23,9 +23,9 @@ class RecentlyClosedFragmentStore(initialState: RecentlyClosedFragmentState) : * `RecentlyClosedFragmentState` through the reducer. */ sealed class RecentlyClosedFragmentAction : Action { - data class Change(val list: List) : RecentlyClosedFragmentAction() - data class Select(val tab: RecoverableTab) : RecentlyClosedFragmentAction() - data class Deselect(val tab: RecoverableTab) : RecentlyClosedFragmentAction() + data class Change(val list: List) : RecentlyClosedFragmentAction() + data class Select(val tab: TabState) : RecentlyClosedFragmentAction() + data class Deselect(val tab: TabState) : RecentlyClosedFragmentAction() object DeselectAll : RecentlyClosedFragmentAction() } @@ -34,8 +34,8 @@ sealed class RecentlyClosedFragmentAction : Action { * @property items List of recently closed tabs to display */ data class RecentlyClosedFragmentState( - val items: List = emptyList(), - val selectedTabs: Set + val items: List = emptyList(), + val selectedTabs: Set ) : State /** diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentView.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentView.kt index c20b08a2a2..ab0ec87da4 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentView.kt @@ -10,13 +10,13 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import org.mozilla.fenix.R import org.mozilla.fenix.databinding.ComponentRecentlyClosedBinding import org.mozilla.fenix.library.LibraryPageView import org.mozilla.fenix.selection.SelectionInteractor -interface RecentlyClosedInteractor : SelectionInteractor { +interface RecentlyClosedInteractor : SelectionInteractor { /** * Called when the view more history option is tapped. */ @@ -27,7 +27,7 @@ interface RecentlyClosedInteractor : SelectionInteractor { * * @param tab the recently closed tab to delete. */ - fun onDelete(tab: RecoverableTab) + fun onDelete(tab: TabState) } /** diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedItemViewHolder.kt index 4d6e20deac..a56104ad85 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedItemViewHolder.kt @@ -6,7 +6,7 @@ package org.mozilla.fenix.library.recentlyclosed import android.view.View import androidx.recyclerview.widget.RecyclerView -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import org.mozilla.fenix.R import org.mozilla.fenix.databinding.HistoryListItemBinding import org.mozilla.fenix.ext.hideAndDisable @@ -16,12 +16,12 @@ import org.mozilla.fenix.selection.SelectionHolder class RecentlyClosedItemViewHolder( view: View, private val recentlyClosedFragmentInteractor: RecentlyClosedFragmentInteractor, - private val selectionHolder: SelectionHolder, + private val selectionHolder: SelectionHolder, ) : RecyclerView.ViewHolder(view) { private val binding = HistoryListItemBinding.bind(view) - private var item: RecoverableTab? = null + private var item: TabState? = null init { binding.historyLayout.overflowView.apply { @@ -34,7 +34,7 @@ class RecentlyClosedItemViewHolder( } } - fun bind(item: RecoverableTab) { + fun bind(item: TabState) { binding.historyLayout.titleView.text = item.title.ifEmpty { item.url } binding.historyLayout.urlView.text = item.url diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddleware.kt b/app/src/main/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddleware.kt index 6a7bd8c4af..10fb6a9c58 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddleware.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddleware.kt @@ -45,9 +45,9 @@ class SearchTermTabGroupMiddleware : Middleware { } is TabListAction.RestoreAction -> { action.tabs.forEach { tab -> - tab.historyMetadata?.searchTerm?.let { searchTerm -> + tab.state.historyMetadata?.searchTerm?.let { searchTerm -> context.dispatch( - TabGroupAction.AddTabAction(SEARCH_TERM_TAB_GROUPS, searchTerm, tab.id) + TabGroupAction.AddTabAction(SEARCH_TERM_TAB_GROUPS, searchTerm, tab.state.id) ) } } diff --git a/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryLifecycleObserver.kt b/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryLifecycleObserver.kt index 2d3c43b677..6d71f9f2cc 100644 --- a/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryLifecycleObserver.kt +++ b/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryLifecycleObserver.kt @@ -68,11 +68,11 @@ class TelemetryLifecycleObserver( crashedTabs = crashedTabs ) } -} -private data class TabState( - val timestamp: Long = Clock.elapsedRealtime(), - val totalTabs: Int, - val crashedTabs: Int, - val activeEngineTabs: Int -) + private data class TabState( + val timestamp: Long = Clock.elapsedRealtime(), + val totalTabs: Int, + val crashedTabs: Int, + val activeEngineTabs: Int + ) +} diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index 4616504b73..7c11c6cf16 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -25,6 +25,7 @@ import mozilla.components.browser.state.state.ReaderState import mozilla.components.browser.state.state.SearchState import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.Engine @@ -212,22 +213,24 @@ class DefaultSessionControlControllerTest { @Test fun `handleCollectionOpenTabClicked with existing selected tab`() { val recoverableTab = RecoverableTab( - id = "test", - parentId = null, - url = "https://www.mozilla.org", - title = "Mozilla", - state = null, - contextId = null, - readerState = ReaderState(), - lastAccess = 0, - private = false + engineSessionState = null, + state = TabState( + id = "test", + parentId = null, + url = "https://www.mozilla.org", + title = "Mozilla", + contextId = null, + readerState = ReaderState(), + lastAccess = 0, + private = false + ) ) val tab = mockk { every { restore(activity, engine, restoreSessionId = false) } returns recoverableTab } - val restoredTab = createTab(id = recoverableTab.id, url = recoverableTab.url) + val restoredTab = createTab(id = recoverableTab.state.id, url = recoverableTab.state.url) val otherTab = createTab(id = "otherTab", url = "https://mozilla.org") store.dispatch(TabListAction.AddTabAction(otherTab)).joinBlocking() store.dispatch(TabListAction.SelectTabAction(otherTab.id)).joinBlocking() @@ -243,22 +246,24 @@ class DefaultSessionControlControllerTest { @Test fun `handleCollectionOpenTabClicked without existing selected tab`() { val recoverableTab = RecoverableTab( - id = "test", - parentId = null, - url = "https://www.mozilla.org", - title = "Mozilla", - state = null, - contextId = null, - readerState = ReaderState(), - lastAccess = 0, - private = false + engineSessionState = null, + state = TabState( + id = "test", + parentId = null, + url = "https://www.mozilla.org", + title = "Mozilla", + contextId = null, + readerState = ReaderState(), + lastAccess = 0, + private = false + ) ) val tab = mockk { every { restore(activity, engine, restoreSessionId = false) } returns recoverableTab } - val restoredTab = createTab(id = recoverableTab.id, url = recoverableTab.url) + val restoredTab = createTab(id = recoverableTab.state.id, url = recoverableTab.state.url) store.dispatch(TabListAction.AddTabAction(restoredTab)).joinBlocking() createController().handleCollectionOpenTabClicked(tab) diff --git a/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/DefaultRecentlyClosedControllerTest.kt b/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/DefaultRecentlyClosedControllerTest.kt index a0e5c0f3ff..6b202d2fba 100644 --- a/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/DefaultRecentlyClosedControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/DefaultRecentlyClosedControllerTest.kt @@ -6,20 +6,25 @@ package org.mozilla.fenix.library.recentlyclosed import androidx.navigation.NavController import androidx.navigation.NavOptions -import io.mockk.Runs +import io.mockk.mockk +import io.mockk.coEvery +import io.mockk.verifyAll import io.mockk.clearMocks import io.mockk.every -import io.mockk.just -import io.mockk.mockk import io.mockk.verify -import io.mockk.verifyAll -import kotlinx.coroutines.test.TestCoroutineDispatcher +import io.mockk.coVerify +import io.mockk.just +import io.mockk.Runs +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import mozilla.components.browser.state.action.RecentlyClosedAction -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.prompt.ShareData +import mozilla.components.feature.recentlyclosed.RecentlyClosedTabsStorage import mozilla.components.feature.tabs.TabsUseCases -import org.junit.After +import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -35,7 +40,6 @@ import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class DefaultRecentlyClosedControllerTest { - private val dispatcher = TestCoroutineDispatcher() private val navController: NavController = mockk(relaxed = true) private val activity: HomeActivity = mockk(relaxed = true) private val browserStore: BrowserStore = mockk(relaxed = true) @@ -45,39 +49,34 @@ class DefaultRecentlyClosedControllerTest { @Before fun setUp() { - every { tabsUseCases.restore.invoke(any(), true) } just Runs - } - - @After - fun tearDown() { - dispatcher.cleanupTestCoroutines() + coEvery { tabsUseCases.restore.invoke(any(), any(), true) } just Runs } @Test fun handleOpen() { - val item: RecoverableTab = mockk(relaxed = true) + val item: TabState = mockk(relaxed = true) - var actualtab: RecoverableTab? = null + var tabUrl: String? = null var actualBrowsingMode: BrowsingMode? = null val controller = createController( - openToBrowser = { tab, browsingMode -> - actualtab = tab + openToBrowser = { url, browsingMode -> + tabUrl = url actualBrowsingMode = browsingMode } ) controller.handleOpen(item, BrowsingMode.Private) - assertEquals(item, actualtab) + assertEquals(item.url, tabUrl) assertEquals(actualBrowsingMode, BrowsingMode.Private) - actualtab = null + tabUrl = null actualBrowsingMode = null controller.handleOpen(item, BrowsingMode.Normal) - assertEquals(item, actualtab) + assertEquals(item.url, tabUrl) assertEquals(actualBrowsingMode, BrowsingMode.Normal) } @@ -85,34 +84,34 @@ class DefaultRecentlyClosedControllerTest { fun `open multiple tabs`() { val tabs = createFakeTabList(2) - val actualTabs = mutableListOf() + val tabUrls = mutableListOf() val actualBrowsingModes = mutableListOf() val controller = createController( - openToBrowser = { tab, mode -> - actualTabs.add(tab) + openToBrowser = { url, mode -> + tabUrls.add(url) actualBrowsingModes.add(mode) } ) controller.handleOpen(tabs.toSet(), BrowsingMode.Normal) - assertEquals(2, actualTabs.size) - assertEquals(tabs[0], actualTabs[0]) - assertEquals(tabs[1], actualTabs[1]) + assertEquals(2, tabUrls.size) + assertEquals(tabs[0].url, tabUrls[0]) + assertEquals(tabs[1].url, tabUrls[1]) assertEquals(BrowsingMode.Normal, actualBrowsingModes[0]) assertEquals(BrowsingMode.Normal, actualBrowsingModes[1]) verifyAll { metrics.track(Event.RecentlyClosedTabsMenuOpenInNormalTab) } clearMocks(metrics) - actualTabs.clear() + tabUrls.clear() actualBrowsingModes.clear() controller.handleOpen(tabs.toSet(), BrowsingMode.Private) - assertEquals(2, actualTabs.size) - assertEquals(tabs[0], actualTabs[0]) - assertEquals(tabs[1], actualTabs[1]) + assertEquals(2, tabUrls.size) + assertEquals(tabs[0].url, tabUrls[0]) + assertEquals(tabs[1].url, tabUrls[1]) assertEquals(BrowsingMode.Private, actualBrowsingModes[0]) assertEquals(BrowsingMode.Private, actualBrowsingModes[1]) verifyAll { metrics.track(Event.RecentlyClosedTabsMenuOpenInPrivateTab) } @@ -164,7 +163,7 @@ class DefaultRecentlyClosedControllerTest { @Test fun handleDelete() { - val item: RecoverableTab = mockk(relaxed = true) + val item: TabState = mockk(relaxed = true) createController().handleDelete(item) @@ -221,14 +220,12 @@ class DefaultRecentlyClosedControllerTest { } @Test - fun handleRestore() { - val item: RecoverableTab = mockk(relaxed = true) - - createController().handleRestore(item) + fun handleRestore() = runBlocking { + val item: TabState = mockk(relaxed = true) - dispatcher.advanceUntilIdle() + createController(scope = this).handleRestore(item) - verify { tabsUseCases.restore.invoke(item, true) } + coVerify { tabsUseCases.restore.invoke(eq(item), any(), true) } verify { metrics.track(Event.RecentlyClosedTabsOpenTab) } } @@ -253,24 +250,27 @@ class DefaultRecentlyClosedControllerTest { } private fun createController( - openToBrowser: (RecoverableTab, BrowsingMode?) -> Unit = { _, _ -> } + scope: CoroutineScope = CoroutineScope(Dispatchers.IO), + openToBrowser: (String, BrowsingMode?) -> Unit = { _, _ -> }, ): RecentlyClosedController { return DefaultRecentlyClosedController( navController, browserStore, recentlyClosedStore, + RecentlyClosedTabsStorage(testContext, mockk(), mockk()), tabsUseCases, activity, metrics, + scope, openToBrowser ) } - private fun createFakeTab(id: String = "FakeId", url: String = "www.fake.com"): RecoverableTab = - RecoverableTab(id, url) + private fun createFakeTab(id: String = "FakeId", url: String = "www.fake.com"): TabState = + TabState(id, url) - private fun createFakeTabList(size: Int): List { - val fakeTabs = mutableListOf() + private fun createFakeTabList(size: Int): List { + val fakeTabs = mutableListOf() for (i in 0 until size) { fakeTabs.add(createFakeTab(id = "FakeId$i")) } diff --git a/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractorTest.kt index f8f85db528..94b7a20a7a 100644 --- a/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragmentInteractorTest.kt @@ -6,7 +6,7 @@ package org.mozilla.fenix.library.recentlyclosed import io.mockk.mockk import io.mockk.verify -import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import org.junit.Before import org.junit.Test @@ -26,7 +26,7 @@ class RecentlyClosedFragmentInteractorTest { @Test fun onDelete() { - val tab = RecoverableTab(id = "tab-id", title = "Mozilla", url = "mozilla.org", lastAccess = 1L) + val tab = TabState(id = "tab-id", title = "Mozilla", url = "mozilla.org", lastAccess = 1L) interactor.onDelete(tab) verify { diff --git a/app/src/test/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddlewareTest.kt b/app/src/test/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddlewareTest.kt index 02124c0f2a..bd6dac475a 100644 --- a/app/src/test/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddlewareTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabstray/SearchTermTabGroupMiddlewareTest.kt @@ -16,6 +16,7 @@ import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.TabGroup import mozilla.components.browser.state.state.TabPartition import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.storage.HistoryMetadataKey import mozilla.components.lib.state.MiddlewareContext @@ -86,9 +87,12 @@ class SearchTermTabGroupMiddlewareTest { TabListAction.RestoreAction( listOf( RecoverableTab( - id = "testId", - url = "url", - historyMetadata = HistoryMetadataKey("url", "search term", "url") + engineSessionState = null, + state = TabState( + id = "testId", + url = "url", + historyMetadata = HistoryMetadataKey("url", "search term", "url") + ) ) ), restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING diff --git a/app/src/test/java/org/mozilla/fenix/telemetry/TelemetryMiddlewareTest.kt b/app/src/test/java/org/mozilla/fenix/telemetry/TelemetryMiddlewareTest.kt index 86677b1ec4..260036c481 100644 --- a/app/src/test/java/org/mozilla/fenix/telemetry/TelemetryMiddlewareTest.kt +++ b/app/src/test/java/org/mozilla/fenix/telemetry/TelemetryMiddlewareTest.kt @@ -14,6 +14,7 @@ import mozilla.components.browser.state.engine.EngineMiddleware import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.browser.state.state.recover.TabState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.service.glean.testing.GleanTestRule import mozilla.components.support.base.android.Clock @@ -165,8 +166,8 @@ class TelemetryMiddlewareTest { fun `WHEN tabs are restored THEN the open tab count is updated`() { assertEquals(0, settings.openTabsCount) val tabsToRestore = listOf( - RecoverableTab(url = "https://mozilla.org", id = "1"), - RecoverableTab(url = "https://firefox.com", id = "2") + RecoverableTab(null, TabState(url = "https://mozilla.org", id = "1")), + RecoverableTab(null, TabState(url = "https://firefox.com", id = "2")) ) store.dispatch( @@ -206,9 +207,9 @@ class TelemetryMiddlewareTest { store.dispatch( TabListAction.RestoreAction( listOf( - RecoverableTab(url = "https://www.mozilla.org", id = "foreground"), - RecoverableTab(url = "https://getpocket.com", id = "background_pocket"), - RecoverableTab(url = "https://theverge.com", id = "background_verge") + RecoverableTab(null, TabState(url = "https://www.mozilla.org", id = "foreground")), + RecoverableTab(null, TabState(url = "https://getpocket.com", id = "background_pocket")), + RecoverableTab(null, TabState(url = "https://theverge.com", id = "background_verge")) ), selectedTabId = "foreground", restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING @@ -230,9 +231,9 @@ class TelemetryMiddlewareTest { store.dispatch( TabListAction.RestoreAction( listOf( - RecoverableTab(url = "https://www.mozilla.org", id = "foreground"), - RecoverableTab(url = "https://getpocket.com", id = "background_pocket"), - RecoverableTab(url = "https://theverge.com", id = "background_verge") + RecoverableTab(null, TabState(url = "https://www.mozilla.org", id = "foreground")), + RecoverableTab(null, TabState(url = "https://getpocket.com", id = "background_pocket")), + RecoverableTab(null, TabState(url = "https://theverge.com", id = "background_verge")) ), selectedTabId = "foreground", restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING @@ -264,9 +265,9 @@ class TelemetryMiddlewareTest { store.dispatch( TabListAction.RestoreAction( listOf( - RecoverableTab(url = "https://www.mozilla.org", id = "foreground"), - RecoverableTab(url = "https://getpocket.com", id = "background_pocket"), - RecoverableTab(url = "https://theverge.com", id = "background_verge") + RecoverableTab(null, TabState(url = "https://www.mozilla.org", id = "foreground")), + RecoverableTab(null, TabState(url = "https://getpocket.com", id = "background_pocket")), + RecoverableTab(null, TabState(url = "https://theverge.com", id = "background_verge")) ), selectedTabId = "foreground", restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING @@ -301,9 +302,9 @@ class TelemetryMiddlewareTest { store.dispatch( TabListAction.RestoreAction( listOf( - RecoverableTab(url = "https://www.mozilla.org", id = "foreground"), - RecoverableTab(url = "https://getpocket.com", id = "background_pocket"), - RecoverableTab(url = "https://theverge.com", id = "background_verge") + RecoverableTab(null, TabState(url = "https://www.mozilla.org", id = "foreground")), + RecoverableTab(null, TabState(url = "https://getpocket.com", id = "background_pocket")), + RecoverableTab(null, TabState(url = "https://theverge.com", id = "background_verge")) ), selectedTabId = "foreground", restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING