tor-browser

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

commit a44e6ff6ffc043f664d03812775b7cb00ff7ff68
parent 95e4c34b2164a01edcf582eb662da439ec7eea9b
Author: mcarare <48995920+mcarare@users.noreply.github.com>
Date:   Tue,  4 Nov 2025 15:15:10 +0000

Bug 1997939 - Extract DownloadCancelDialogFragment creation in BrowserScreenMiddleware r=android-reviewers,avirvara

This patch refactors the `BrowserScreenMiddleware` to extract the creation and styling of the `DownloadCancelDialogFragment` into new, testable methods.

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

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/store/BrowserScreenMiddleware.kt | 57+++++++++++++++++++++++++++++++++++++++------------------
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/browser/store/BrowserScreenMiddlewareTest.kt | 96++++++++++++++++++++++---------------------------------------------------------
2 files changed, 65 insertions(+), 88 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/store/BrowserScreenMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/store/BrowserScreenMiddleware.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.browser.store +import android.content.Context import android.view.Gravity import androidx.annotation.VisibleForTesting import mozilla.components.concept.base.crash.Breadcrumb @@ -74,31 +75,51 @@ class BrowserScreenMiddleware( crashReporter.recordCrashBreadcrumb( Breadcrumb("DownloadCancelDialogFragment shown in browser screen"), ) - val dialog = DownloadCancelDialogFragment.newInstance( + val dialog = createDownloadCancelDialog(environment.context, store, downloadCount, tabId) + + dialog.show(environment.fragmentManager, CANCEL_PRIVATE_DOWNLOADS_DIALOG_FRAGMENT_TAG) + } + + /** + * Creates and configures a new instance of [DownloadCancelDialogFragment]. + */ + @VisibleForTesting + internal fun createDownloadCancelDialog( + context: Context, + store: Store<BrowserScreenState, BrowserScreenAction>, + downloadCount: Int, + tabId: String?, + ): DownloadCancelDialogFragment { + return DownloadCancelDialogFragment.newInstance( downloadCount = downloadCount, tabId = tabId, source = null, - promptStyling = DownloadCancelDialogFragment.PromptStyling( - gravity = Gravity.BOTTOM, - shouldWidthMatchParent = true, - positiveButtonBackgroundColor = ThemeManager.resolveAttribute( - R.attr.accent, - environment.context, - ), - positiveButtonTextColor = ThemeManager.resolveAttribute( - R.attr.textOnColorPrimary, - environment.context, - ), - positiveButtonRadius = environment.context.pixelSizeFor( - R.dimen.tab_corner_radius, - ).toFloat(), - ), - + promptStyling = createDialogPromptStyling(context), onPositiveButtonClicked = { _, _ -> store.dispatch(CancelPrivateDownloadsOnPrivateTabsClosedAccepted) }, ) - dialog.show(environment.fragmentManager, CANCEL_PRIVATE_DOWNLOADS_DIALOG_FRAGMENT_TAG) + } + + /** + * Creates the specific styling configuration for the download cancellation prompt. + */ + fun createDialogPromptStyling(context: Context): DownloadCancelDialogFragment.PromptStyling { + return DownloadCancelDialogFragment.PromptStyling( + gravity = Gravity.BOTTOM, + shouldWidthMatchParent = true, + positiveButtonBackgroundColor = ThemeManager.resolveAttribute( + R.attr.accent, + context, + ), + positiveButtonTextColor = ThemeManager.resolveAttribute( + R.attr.textOnColorPrimary, + context, + ), + positiveButtonRadius = context.pixelSizeFor( + R.dimen.tab_corner_radius, + ).toFloat(), + ) } /** diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/browser/store/BrowserScreenMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/browser/store/BrowserScreenMiddlewareTest.kt @@ -5,122 +5,78 @@ package org.mozilla.fenix.browser.store import android.content.Context -import android.view.Gravity import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.mockk.Runs import io.mockk.every -import io.mockk.just import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.slot +import io.mockk.spyk import io.mockk.verify import mozilla.components.feature.downloads.ui.DownloadCancelDialogFragment import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.state.Middleware import mozilla.components.support.test.middleware.CaptureActionsMiddleware import mozilla.components.support.test.robolectric.testContext -import mozilla.components.support.test.rule.MainCoroutineRule import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mozilla.fenix.R import org.mozilla.fenix.browser.store.BrowserScreenAction.CancelPrivateDownloadsOnPrivateTabsClosedAccepted import org.mozilla.fenix.browser.store.BrowserScreenAction.EnvironmentCleared import org.mozilla.fenix.browser.store.BrowserScreenAction.EnvironmentRehydrated import org.mozilla.fenix.browser.store.BrowserScreenMiddleware.Companion.CANCEL_PRIVATE_DOWNLOADS_DIALOG_FRAGMENT_TAG import org.mozilla.fenix.browser.store.BrowserScreenStore.Environment import org.mozilla.fenix.helpers.lifecycle.TestLifecycleOwner -import org.mozilla.fenix.theme.ThemeManager @RunWith(AndroidJUnit4::class) class BrowserScreenMiddlewareTest { - @get:Rule - private val coroutinesTestRule = MainCoroutineRule() + private val lifecycleOwner = TestLifecycleOwner(Lifecycle.State.RESUMED) private val fragmentManager: FragmentManager = mockk(relaxed = true) + private val crashReporter: CrashReporter = mockk(relaxed = true) @Test fun `WHEN the last private tab is closing THEN record a breadcrumb and show a warning dialog`() { - val crashReporter: CrashReporter = mockk(relaxed = true) - val middleware = BrowserScreenMiddleware(crashReporter) + val middleware = spyk(BrowserScreenMiddleware(crashReporter)) val store = buildStore(listOf(middleware)) - val warningDialog: DownloadCancelDialogFragment = mockk { - every { show(any<FragmentManager>(), any<String>()) } just Runs - } + val warningDialog: DownloadCancelDialogFragment = mockk(relaxed = true) + + every { middleware.createDownloadCancelDialog(any(), any(), any(), any()) } returns warningDialog + + store.dispatch(BrowserScreenAction.ClosingLastPrivateTab(tabId = "tabId", inProgressPrivateDownloads = 3)) - mockkObject(DownloadCancelDialogFragment.Companion) { - every { DownloadCancelDialogFragment.Companion.newInstance(any(), any(), any(), any(), any(), any(), any()) } returns warningDialog - - store.dispatch(BrowserScreenAction.ClosingLastPrivateTab("tabId", 3)) - - verify { crashReporter.recordCrashBreadcrumb(any()) } - verify { - DownloadCancelDialogFragment.Companion.newInstance( - downloadCount = 3, - tabId = "tabId", - source = null, - promptStyling = DownloadCancelDialogFragment.PromptStyling( - gravity = Gravity.BOTTOM, - shouldWidthMatchParent = true, - positiveButtonBackgroundColor = ThemeManager.resolveAttribute( - R.attr.accent, - testContext, - ), - positiveButtonTextColor = ThemeManager.resolveAttribute( - R.attr.textOnColorPrimary, - testContext, - ), - positiveButtonRadius = testContext.resources.getDimensionPixelSize( - R.dimen.tab_corner_radius, - ).toFloat(), - ), - onPositiveButtonClicked = any(), - onNegativeButtonClicked = null, - ) - } - verify { warningDialog.show(fragmentManager, CANCEL_PRIVATE_DOWNLOADS_DIALOG_FRAGMENT_TAG) } + verify { crashReporter.recordCrashBreadcrumb(any()) } + verify { + middleware.createDownloadCancelDialog( + context = testContext, + store = store, + downloadCount = 3, + tabId = "tabId", + ) } + verify { warningDialog.show(fragmentManager, CANCEL_PRIVATE_DOWNLOADS_DIALOG_FRAGMENT_TAG) } } @Test fun `GIVEN a warning dialog for closing private tabs is shown WHEN the warning is accepted THEN inform about this`() { - val middleware = BrowserScreenMiddleware(mockk(relaxed = true)) + val middleware = spyk(BrowserScreenMiddleware(crashReporter)) val captureActionsMiddleware = CaptureActionsMiddleware<BrowserScreenState, BrowserScreenAction>() val store = buildStore(listOf(middleware, captureActionsMiddleware)) - val warningDialog: DownloadCancelDialogFragment = mockk { - every { show(any<FragmentManager>(), any<String>()) } just Runs - } - val positiveActionCaptor = slot<((tabId: String?, source: String?) -> Unit)>() - - mockkObject(DownloadCancelDialogFragment.Companion) { - every { DownloadCancelDialogFragment.Companion.newInstance(any()) } returns warningDialog - - store.dispatch(BrowserScreenAction.ClosingLastPrivateTab("tabId", 3)) - verify { - DownloadCancelDialogFragment.Companion.newInstance( - downloadCount = any(), - tabId = any(), - source = any(), - promptStyling = any(), - onPositiveButtonClicked = capture(positiveActionCaptor), - onNegativeButtonClicked = any(), - ) - } - } + val warningDialog: DownloadCancelDialogFragment = mockk(relaxed = true) + + every { middleware.createDownloadCancelDialog(any(), any(), any(), any()) } returns warningDialog - positiveActionCaptor.captured.invoke("test", "source") + store.dispatch(BrowserScreenAction.ClosingLastPrivateTab("tabId", 3)) + + store.dispatch(CancelPrivateDownloadsOnPrivateTabsClosedAccepted) captureActionsMiddleware.assertLastAction(CancelPrivateDownloadsOnPrivateTabsClosedAccepted::class) {} } @Test fun `GIVEN an environment was already set WHEN it is cleared THEN reset it to null`() { - val middleware = BrowserScreenMiddleware(mockk()) + val middleware = BrowserScreenMiddleware(crashReporter) val store = buildStore(listOf(middleware)) assertNotNull(middleware.environment)