tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c514cff7436a13a691cb20dcf37f3c310de47964
parent 6224e0d18940ad45d96715b28b63850086411b7f
Author: mcarare <48995920+mcarare@users.noreply.github.com>
Date:   Tue, 16 Dec 2025 16:31:03 +0000

Bug 2006348 - Refactor DefaultTabManagerControllerTest to use StandardTestDispatcher r=android-reviewers,giorga

This patch replaces the usage of `MainCoroutineRule` and `runTestOnMain` with `StandardTestDispatcher` and `runTest`.
To support this, `TabManagerController` is updated to accept an injected `mainDispatcher`, allowing tests to control the execution context. Use of explicit dispatchers in `TabManagementFragment` is removed in favor of the default values.

Differential Revision: https://phabricator.services.mozilla.com/D276674

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/controller/TabManagerController.kt | 8+++++---
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/ui/TabManagementFragment.kt | 2--
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/tabstray/controller/DefaultTabManagerControllerTest.kt | 27++++++++++++++-------------
3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/controller/TabManagerController.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/controller/TabManagerController.kt @@ -225,6 +225,7 @@ interface TabManagerController : SyncedTabsController, InactiveTabsController, T * @param bookmarksStorage Storage layer for retrieving and saving bookmarks. * @param closeSyncedTabsUseCases Use cases for closing synced tabs. * @param ioDispatcher [CoroutineContext] used for storage operations. + * @param mainDispatcher [CoroutineContext] used for UI operations. * @param collectionStorage Storage layer for interacting with collections. * @param showUndoSnackbarForTab Lambda used to display an undo snackbar when a normal or private tab is closed. * @param showUndoSnackbarForInactiveTab Lambda used to display an undo snackbar when an inactive tab is closed. @@ -250,7 +251,8 @@ class DefaultTabManagerController( private val fenixBrowserUseCases: FenixBrowserUseCases, private val bookmarksStorage: BookmarksStorage, private val closeSyncedTabsUseCases: CloseTabsUseCases, - private val ioDispatcher: CoroutineContext, + private val ioDispatcher: CoroutineContext = Dispatchers.IO, + private val mainDispatcher: CoroutineContext = Dispatchers.Main, private val collectionStorage: TabCollectionStorage, private val showUndoSnackbarForTab: (Boolean) -> Unit, private val showUndoSnackbarForInactiveTab: (Int) -> Unit, @@ -458,7 +460,7 @@ class DefaultTabManagerController( position = null, ) } - withContext(Dispatchers.Main) { + withContext(mainDispatcher) { showBookmarkSnackbar(tabs.size, parentNode?.title) } }.getOrElse { @@ -553,7 +555,7 @@ class DefaultTabManagerController( override fun handleSyncedTabClosed(deviceId: String, tab: Tab) { CoroutineScope(ioDispatcher).launch { val operation = closeSyncedTabsUseCases.close(deviceId, tab.active().url) - withContext(Dispatchers.Main) { + withContext(mainDispatcher) { showUndoSnackbarForSyncedTab(operation) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/ui/TabManagementFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/ui/TabManagementFragment.kt @@ -32,7 +32,6 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.navigation3.runtime.entryProvider import androidx.navigation3.ui.NavDisplay -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import mozilla.appservices.places.BookmarkRoot import mozilla.components.browser.state.selector.normalTabs @@ -197,7 +196,6 @@ class TabManagementFragment : DialogFragment() { fenixBrowserUseCases = requireComponents.useCases.fenixBrowserUseCases, closeSyncedTabsUseCases = requireComponents.useCases.closeSyncedTabsUseCases, bookmarksStorage = requireComponents.core.bookmarksStorage, - ioDispatcher = Dispatchers.IO, collectionStorage = requireComponents.core.tabCollectionStorage, showUndoSnackbarForTab = ::showUndoSnackbarForTab, showUndoSnackbarForInactiveTab = ::showUndoSnackbarForInactiveTab, diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/tabstray/controller/DefaultTabManagerControllerTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/tabstray/controller/DefaultTabManagerControllerTest.kt @@ -19,6 +19,8 @@ import io.mockk.runs import io.mockk.spyk import io.mockk.verify import io.mockk.verifyOrder +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.runTest import mozilla.appservices.places.BookmarkRoot import mozilla.components.browser.state.action.TabListAction import mozilla.components.browser.state.selector.findTab @@ -42,8 +44,6 @@ import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.support.test.middleware.CaptureActionsMiddleware import mozilla.components.support.test.robolectric.testContext -import mozilla.components.support.test.rule.MainCoroutineRule -import mozilla.components.support.test.rule.runTestOnMain import mozilla.telemetry.glean.private.NoExtras import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -54,7 +54,6 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.RuleChain import org.junit.runner.RunWith import org.mozilla.fenix.GleanMetrics.Collections import org.mozilla.fenix.GleanMetrics.Events @@ -120,9 +119,7 @@ class DefaultTabManagerControllerTest { private val bookmarksStorage: BookmarksStorage = mockk(relaxed = true) private val closeSyncedTabsUseCases: CloseTabsUseCases = mockk(relaxed = true) private val collectionStorage: TabCollectionStorage = mockk(relaxed = true) - - private val coroutinesTestRule: MainCoroutineRule = MainCoroutineRule() - private val testDispatcher = coroutinesTestRule.testDispatcher + private val testDispatcher = StandardTestDispatcher() private val mockPrivateTab = mockk<TabSessionState> { every { content.private } returns true @@ -132,10 +129,8 @@ class DefaultTabManagerControllerTest { every { content.private } returns false } - val gleanTestRule = FenixGleanTestRule(testContext) - @get:Rule - val chain: RuleChain = RuleChain.outerRule(gleanTestRule).around(coroutinesTestRule) + val gleanTestRule = FenixGleanTestRule(testContext) @Before fun setup() { @@ -681,6 +676,7 @@ class DefaultTabManagerControllerTest { inactive = false, ) controller.handleSyncedTabClosed("1234", tab) + testDispatcher.scheduler.advanceUntilIdle() coVerify(exactly = 1) { closeSyncedTabsUseCases.close("1234", any()) } assertTrue(showUndoSnackbarForSyncedTabInvoked) @@ -1221,7 +1217,7 @@ class DefaultTabManagerControllerTest { } @Test - fun `GIVEN one tab selected and no bookmarks previously saved WHEN saving selected tabs to bookmarks THEN save bookmark in root, report telemetry, show snackbar`() = runTestOnMain { + fun `GIVEN one tab selected and no bookmarks previously saved WHEN saving selected tabs to bookmarks THEN save bookmark in root, report telemetry, show snackbar`() = runTest(testDispatcher) { var showBookmarkSnackbarInvoked = false coEvery { bookmarksStorage.getRecentBookmarks(eq(1), any(), any()) } returns Result.success(listOf()) @@ -1233,6 +1229,7 @@ class DefaultTabManagerControllerTest { showBookmarkSnackbarInvoked = true }, ).handleBookmarkSelectedTabsClicked() + testDispatcher.scheduler.advanceUntilIdle() verify { trayStore.dispatch(TabsTrayAction.BookmarkSelectedTabs(1)) } coVerify(exactly = 1) { bookmarksStorage.addItem(eq(BookmarkRoot.Mobile.id), any(), any(), any()) } @@ -1240,7 +1237,7 @@ class DefaultTabManagerControllerTest { } @Test - fun `GIVEN one tab selected and a previously saved bookmark WHEN saving selected tabs to bookmarks THEN save bookmark in last saved folder, report telemetry, show snackbar`() = runTestOnMain { + fun `GIVEN one tab selected and a previously saved bookmark WHEN saving selected tabs to bookmarks THEN save bookmark in last saved folder, report telemetry, show snackbar`() = runTest(testDispatcher) { var showBookmarkSnackbarInvoked = false val parentGuid = "parentGuid" @@ -1254,6 +1251,7 @@ class DefaultTabManagerControllerTest { showBookmarkSnackbarInvoked = true }, ).handleBookmarkSelectedTabsClicked() + testDispatcher.scheduler.advanceUntilIdle() verify { trayStore.dispatch(TabsTrayAction.BookmarkSelectedTabs(1)) } coVerify(exactly = 1) { bookmarksStorage.addItem(eq(parentGuid), any(), any(), any()) } @@ -1261,7 +1259,7 @@ class DefaultTabManagerControllerTest { } @Test - fun `GIVEN multiple tabs selected and no bookmarks previously saved WHEN saving selected tabs to bookmarks THEN save bookmarks in root, report telemetry, show a snackbar`() = runTestOnMain { + fun `GIVEN multiple tabs selected and no bookmarks previously saved WHEN saving selected tabs to bookmarks THEN save bookmarks in root, report telemetry, show a snackbar`() = runTest(testDispatcher) { var showBookmarkSnackbarInvoked = false coEvery { bookmarksStorage.getRecentBookmarks(eq(1), any(), any()) } returns Result.success(listOf()) @@ -1273,6 +1271,7 @@ class DefaultTabManagerControllerTest { showBookmarkSnackbarInvoked = true }, ).handleBookmarkSelectedTabsClicked() + testDispatcher.scheduler.advanceUntilIdle() verify { trayStore.dispatch(TabsTrayAction.BookmarkSelectedTabs(2)) } coVerify(exactly = 2) { bookmarksStorage.addItem(eq(BookmarkRoot.Mobile.id), any(), any(), any()) } @@ -1280,7 +1279,7 @@ class DefaultTabManagerControllerTest { } @Test - fun `GIVEN multiple tabs selected and a previously saved bookmark WHEN saving selected tabs to bookmarks THEN save bookmarks in same folder as recent bookmark, report telemetry, show a snackbar`() = runTestOnMain { + fun `GIVEN multiple tabs selected and a previously saved bookmark WHEN saving selected tabs to bookmarks THEN save bookmarks in same folder as recent bookmark, report telemetry, show a snackbar`() = runTest(testDispatcher) { var showBookmarkSnackbarInvoked = false val parentGuid = "parentGuid" @@ -1294,6 +1293,7 @@ class DefaultTabManagerControllerTest { showBookmarkSnackbarInvoked = true }, ).handleBookmarkSelectedTabsClicked() + testDispatcher.scheduler.advanceUntilIdle() verify { trayStore.dispatch(TabsTrayAction.BookmarkSelectedTabs(2)) } coVerify(exactly = 2) { bookmarksStorage.addItem(eq(parentGuid), any(), any(), any()) } @@ -1569,6 +1569,7 @@ class DefaultTabManagerControllerTest { closeSyncedTabsUseCases = closeSyncedTabsUseCases, collectionStorage = collectionStorage, ioDispatcher = testDispatcher, + mainDispatcher = testDispatcher, showUndoSnackbarForTab = showUndoSnackbarForTab, showUndoSnackbarForInactiveTab = showUndoSnackbarForInactiveTab, showUndoSnackbarForSyncedTab = showUndoSnackbarForSyncedTab,