mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-17 15:26:23 +00:00
Bug 1848100 - Implement add-ons installation failed listener
This commit is contained in:
parent
ccddbd3319
commit
61431c6b59
@ -21,12 +21,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.concept.engine.webextension.WebExtensionInstallException
|
||||
import mozilla.components.feature.addons.Addon
|
||||
import mozilla.components.feature.addons.AddonManager
|
||||
import mozilla.components.feature.addons.AddonManagerException
|
||||
import mozilla.components.feature.addons.ui.AddonsManagerAdapter
|
||||
import mozilla.components.feature.addons.ui.translateName
|
||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||
import org.mozilla.fenix.BuildConfig
|
||||
import org.mozilla.fenix.Config
|
||||
@ -34,14 +32,12 @@ import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.mozilla.fenix.databinding.FragmentAddOnsManagementBinding
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getRootView
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.ext.runIfFragmentIsAttached
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.ext.showToolbar
|
||||
import org.mozilla.fenix.extension.WebExtensionPromptFeature
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
import java.util.concurrent.CancellationException
|
||||
|
||||
/**
|
||||
* Fragment use for managing add-ons.
|
||||
@ -56,11 +52,6 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
|
||||
private val webExtensionPromptFeature = ViewBoundFeatureWrapper<WebExtensionPromptFeature>()
|
||||
private var addons: List<Addon> = emptyList()
|
||||
|
||||
/**
|
||||
* Whether or not an add-on installation is in progress.
|
||||
*/
|
||||
private var isInstallationInProgress = false
|
||||
|
||||
private var installExternalAddonComplete: Boolean
|
||||
set(value) {
|
||||
arguments?.putBoolean(BUNDLE_KEY_INSTALL_EXTERNAL_ADDON_COMPLETE, value)
|
||||
@ -138,7 +129,6 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
|
||||
excludedAddonIDs,
|
||||
)
|
||||
}
|
||||
isInstallationInProgress = false
|
||||
binding?.addOnsProgressBar?.isVisible = false
|
||||
binding?.addOnsEmptyMessage?.isVisible = false
|
||||
|
||||
@ -163,7 +153,6 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
|
||||
getString(R.string.mozac_feature_addons_failed_to_query_add_ons),
|
||||
)
|
||||
}
|
||||
isInstallationInProgress = false
|
||||
binding?.addOnsProgressBar?.isVisible = false
|
||||
binding?.addOnsEmptyMessage?.isVisible = true
|
||||
}
|
||||
@ -230,30 +219,12 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
|
||||
addon,
|
||||
onSuccess = {
|
||||
runIfFragmentIsAttached {
|
||||
isInstallationInProgress = false
|
||||
adapter?.updateAddon(it)
|
||||
binding?.addonProgressOverlay?.overlayCardView?.visibility = View.GONE
|
||||
}
|
||||
},
|
||||
onError = { _, e ->
|
||||
this@AddonsManagementFragment.view?.let { view ->
|
||||
// No need to display an error message if installation was cancelled by the user.
|
||||
if (e !is CancellationException && e !is WebExtensionInstallException.UserCancelled) {
|
||||
val rootView = activity?.getRootView() ?: view
|
||||
var messageId = R.string.mozac_feature_addons_failed_to_install
|
||||
if (e is WebExtensionInstallException.Blocklisted) {
|
||||
messageId = R.string.mozac_feature_addons_blocklisted
|
||||
}
|
||||
context?.let {
|
||||
showErrorSnackBar(
|
||||
text = getString(messageId, addon.translateName(it)),
|
||||
anchorView = rootView,
|
||||
)
|
||||
}
|
||||
}
|
||||
binding?.addonProgressOverlay?.overlayCardView?.visibility = View.GONE
|
||||
isInstallationInProgress = false
|
||||
}
|
||||
onError = { _, _ ->
|
||||
binding?.addonProgressOverlay?.overlayCardView?.visibility = View.GONE
|
||||
},
|
||||
)
|
||||
binding?.addonProgressOverlay?.cancelButton?.setOnClickListener {
|
||||
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.extension
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
@ -15,12 +16,15 @@ import kotlinx.coroutines.flow.mapNotNull
|
||||
import mozilla.components.browser.state.action.WebExtensionAction
|
||||
import mozilla.components.browser.state.state.extension.WebExtensionPromptRequest
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.webextension.WebExtensionInstallException
|
||||
import mozilla.components.feature.addons.Addon
|
||||
import mozilla.components.feature.addons.toInstalledState
|
||||
import mozilla.components.feature.addons.ui.AddonInstallationDialogFragment
|
||||
import mozilla.components.feature.addons.ui.PermissionsDialogFragment
|
||||
import mozilla.components.lib.state.ext.flowScoped
|
||||
import mozilla.components.support.base.feature.LifecycleAwareFeature
|
||||
import mozilla.components.support.ktx.android.content.appVersionName
|
||||
import mozilla.components.ui.widgets.withCenterAlignedButtons
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
@ -51,26 +55,49 @@ class WebExtensionPromptFeature(
|
||||
flow.mapNotNull { state ->
|
||||
state.webExtensionPromptRequest
|
||||
}.distinctUntilChanged().collect { promptRequest ->
|
||||
// The install flow in Fenix relies on an [Addon] object so let's convert the (GeckoView)
|
||||
// extension into a minimal add-on. The missing metadata will be fetched when the user
|
||||
// opens the add-ons manager.
|
||||
val addon = Addon.newFromWebExtension(promptRequest.extension)
|
||||
|
||||
when (promptRequest) {
|
||||
is WebExtensionPromptRequest.Permissions -> handlePermissionRequest(
|
||||
addon,
|
||||
promptRequest,
|
||||
)
|
||||
is WebExtensionPromptRequest.AfterInstallation -> {
|
||||
handleAfterInstallationRequest(promptRequest)
|
||||
}
|
||||
|
||||
is WebExtensionPromptRequest.PostInstallation -> handlePostInstallationRequest(
|
||||
addon.copy(installedState = promptRequest.extension.toInstalledState()),
|
||||
)
|
||||
is WebExtensionPromptRequest.BeforeInstallation.InstallationFailed -> {
|
||||
handleBeforeInstallationRequest(promptRequest)
|
||||
consumePromptRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tryToReAttachButtonHandlersToPreviousDialog()
|
||||
}
|
||||
|
||||
private fun handleAfterInstallationRequest(promptRequest: WebExtensionPromptRequest.AfterInstallation) {
|
||||
// The install flow in Fenix relies on an [Addon] object so let's convert the (GeckoView)
|
||||
// extension into a minimal add-on. The missing metadata will be fetched when the user
|
||||
// opens the add-ons manager.
|
||||
val addon = Addon.newFromWebExtension(promptRequest.extension)
|
||||
when (promptRequest) {
|
||||
is WebExtensionPromptRequest.AfterInstallation.Permissions -> handlePermissionRequest(
|
||||
addon,
|
||||
promptRequest,
|
||||
)
|
||||
is WebExtensionPromptRequest.AfterInstallation.PostInstallation -> handlePostInstallationRequest(
|
||||
addon.copy(installedState = promptRequest.extension.toInstalledState()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBeforeInstallationRequest(promptRequest: WebExtensionPromptRequest.BeforeInstallation) {
|
||||
when (promptRequest) {
|
||||
is WebExtensionPromptRequest.BeforeInstallation.InstallationFailed -> {
|
||||
handleInstallationFailedRequest(
|
||||
exception = promptRequest.exception,
|
||||
)
|
||||
consumePromptRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePostInstallationRequest(
|
||||
addon: Addon,
|
||||
) {
|
||||
@ -79,13 +106,73 @@ class WebExtensionPromptFeature(
|
||||
|
||||
private fun handlePermissionRequest(
|
||||
addon: Addon,
|
||||
promptRequest: WebExtensionPromptRequest.Permissions,
|
||||
promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions,
|
||||
) {
|
||||
if (hasExistingPermissionDialogFragment()) {
|
||||
return
|
||||
if (hasExistingPermissionDialogFragment()) return
|
||||
showPermissionDialog(
|
||||
addon,
|
||||
promptRequest,
|
||||
)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun handleInstallationFailedRequest(
|
||||
exception: WebExtensionInstallException,
|
||||
) {
|
||||
val addonName = exception.extensionName ?: ""
|
||||
var title = context.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val message = when (exception) {
|
||||
is WebExtensionInstallException.Blocklisted -> {
|
||||
context.getString(R.string.mozac_feature_addons_blocklisted, addonName)
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.UserCancelled -> {
|
||||
// We don't want to show an error message when users cancel installation.
|
||||
return
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.Unknown -> {
|
||||
// Making sure we don't have a
|
||||
// Title = Failed to install
|
||||
// Message = Failed to install $addonName
|
||||
title = ""
|
||||
if (addonName.isNotEmpty()) {
|
||||
context.getString(R.string.mozac_feature_addons_failed_to_install, addonName)
|
||||
} else {
|
||||
context.getString(R.string.mozac_feature_addons_failed_to_install_generic)
|
||||
}
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.NetworkFailure -> {
|
||||
context.getString(R.string.mozac_feature_addons_failed_to_install_network_error)
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.CorruptFile -> {
|
||||
context.getString(R.string.mozac_feature_addons_failed_to_install_corrupt_error)
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.NotSigned -> {
|
||||
context.getString(
|
||||
R.string.mozac_feature_addons_failed_to_install_not_signed_error,
|
||||
)
|
||||
}
|
||||
|
||||
is WebExtensionInstallException.Incompatible -> {
|
||||
val appName = context.getString(R.string.app_name)
|
||||
val version = context.appVersionName
|
||||
context.getString(
|
||||
R.string.mozac_feature_addons_failed_to_install_incompatible_error,
|
||||
addonName,
|
||||
appName,
|
||||
version,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
showPermissionDialog(addon, promptRequest)
|
||||
showDialog(
|
||||
title = title,
|
||||
message = message,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,7 +185,7 @@ class WebExtensionPromptFeature(
|
||||
@VisibleForTesting
|
||||
internal fun showPermissionDialog(
|
||||
addon: Addon,
|
||||
promptRequest: WebExtensionPromptRequest.Permissions,
|
||||
promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions,
|
||||
) {
|
||||
if (!isInstallationInProgress && !hasExistingPermissionDialogFragment()) {
|
||||
val dialog = PermissionsDialogFragment.newInstance(
|
||||
@ -135,8 +222,8 @@ class WebExtensionPromptFeature(
|
||||
findPreviousPermissionDialogFragment()?.let { dialog ->
|
||||
dialog.onPositiveButtonClicked = { addon ->
|
||||
store.state.webExtensionPromptRequest?.let { promptRequest ->
|
||||
if (addon.id == promptRequest.extension.id &&
|
||||
promptRequest is WebExtensionPromptRequest.Permissions
|
||||
if (promptRequest is WebExtensionPromptRequest.AfterInstallation.Permissions &&
|
||||
addon.id == promptRequest.extension.id
|
||||
) {
|
||||
handleApprovedPermissions(promptRequest)
|
||||
}
|
||||
@ -144,7 +231,7 @@ class WebExtensionPromptFeature(
|
||||
}
|
||||
dialog.onNegativeButtonClicked = {
|
||||
store.state.webExtensionPromptRequest?.let { promptRequest ->
|
||||
if (promptRequest is WebExtensionPromptRequest.Permissions) {
|
||||
if (promptRequest is WebExtensionPromptRequest.AfterInstallation.Permissions) {
|
||||
handleDeniedPermissions(promptRequest)
|
||||
}
|
||||
}
|
||||
@ -154,8 +241,8 @@ class WebExtensionPromptFeature(
|
||||
findPreviousPostInstallationDialogFragment()?.let { dialog ->
|
||||
dialog.onConfirmButtonClicked = { addon, allowInPrivateBrowsing ->
|
||||
store.state.webExtensionPromptRequest?.let { promptRequest ->
|
||||
if (addon.id == promptRequest.extension.id &&
|
||||
promptRequest is WebExtensionPromptRequest.PostInstallation
|
||||
if (promptRequest is WebExtensionPromptRequest.AfterInstallation.PostInstallation &&
|
||||
addon.id == promptRequest.extension.id
|
||||
) {
|
||||
handlePostInstallationButtonClicked(
|
||||
allowInPrivateBrowsing = allowInPrivateBrowsing,
|
||||
@ -173,12 +260,12 @@ class WebExtensionPromptFeature(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDeniedPermissions(promptRequest: WebExtensionPromptRequest.Permissions) {
|
||||
private fun handleDeniedPermissions(promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions) {
|
||||
promptRequest.onConfirm(false)
|
||||
consumePromptRequest()
|
||||
}
|
||||
|
||||
private fun handleApprovedPermissions(promptRequest: WebExtensionPromptRequest.Permissions) {
|
||||
private fun handleApprovedPermissions(promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions) {
|
||||
promptRequest.onConfirm(true)
|
||||
consumePromptRequest()
|
||||
}
|
||||
@ -267,6 +354,24 @@ class WebExtensionPromptFeature(
|
||||
consumePromptRequest()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun showDialog(
|
||||
title: String,
|
||||
message: String,
|
||||
) {
|
||||
context.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setTitle(title)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
.setCancelable(false)
|
||||
.setMessage(
|
||||
message,
|
||||
)
|
||||
.show()
|
||||
.withCenterAlignedButtons()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PERMISSIONS_DIALOG_FRAGMENT_TAG = "ADDONS_PERMISSIONS_DIALOG_FRAGMENT"
|
||||
private const val POST_INSTALLATION_DIALOG_FRAGMENT_TAG =
|
||||
|
@ -6,15 +6,11 @@ package org.mozilla.fenix.addons
|
||||
|
||||
import android.content.Context
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import io.mockk.CapturingSlot
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.concept.engine.webextension.WebExtensionInstallException
|
||||
import mozilla.components.feature.addons.Addon
|
||||
import mozilla.components.feature.addons.AddonManager
|
||||
import mozilla.components.feature.addons.ui.translateName
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.R
|
||||
@ -61,24 +57,4 @@ class AddonsManagementFragmentTest {
|
||||
fragment.installExternalAddon(supportedAddons, "d1")
|
||||
verify { fragment.showErrorSnackBar(addonAlreadyInstalledErrorMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN add-on is installed WHEN add-on is blocklisted THEN error is shown`() {
|
||||
val addonManger = mockk<AddonManager>()
|
||||
val addon = Addon("1")
|
||||
val onError = CapturingSlot<((String, Throwable) -> Unit)>()
|
||||
val expectedErrorMessage = fragment.getString(
|
||||
R.string.mozac_feature_addons_blocklisted,
|
||||
addon.translateName(context),
|
||||
)
|
||||
|
||||
every { fragment.provideAccessibilityServicesEnabled() } returns false
|
||||
every { fragment.provideAddonManger() } returns addonManger
|
||||
every { addonManger.installAddon(addon, any(), capture(onError)) } returns mockk()
|
||||
|
||||
fragment.installAddon(addon)
|
||||
onError.captured("", WebExtensionInstallException.Blocklisted(mockk()))
|
||||
|
||||
verify { fragment.showErrorSnackBar(expectedErrorMessage) }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,219 @@
|
||||
/* 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.extension
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.state.action.WebExtensionAction.UpdatePromptRequestWebExtensionAction
|
||||
import mozilla.components.browser.state.state.extension.WebExtensionPromptRequest
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.webextension.WebExtensionInstallException
|
||||
import mozilla.components.support.ktx.android.content.appVersionName
|
||||
import mozilla.components.support.test.ext.joinBlocking
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class WebExtensionPromptFeatureTest {
|
||||
|
||||
private lateinit var webExtensionPromptFeature: WebExtensionPromptFeature
|
||||
private lateinit var store: BrowserStore
|
||||
|
||||
@get:Rule
|
||||
val coroutinesTestRule = MainCoroutineRule()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
store = BrowserStore()
|
||||
webExtensionPromptFeature = spyk(
|
||||
WebExtensionPromptFeature(
|
||||
store = store,
|
||||
context = testContext,
|
||||
fragmentManager = mockk(relaxed = true),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN InstallationFailed is dispatched THEN handleInstallationFailedRequest is called`() {
|
||||
webExtensionPromptFeature.start()
|
||||
|
||||
every { webExtensionPromptFeature.handleInstallationFailedRequest(any()) } just runs
|
||||
|
||||
store.dispatch(
|
||||
UpdatePromptRequestWebExtensionAction(
|
||||
WebExtensionPromptRequest.BeforeInstallation.InstallationFailed(
|
||||
mockk(),
|
||||
mockk(),
|
||||
),
|
||||
),
|
||||
).joinBlocking()
|
||||
|
||||
verify { webExtensionPromptFeature.handleInstallationFailedRequest(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with network error THEN showDialog with the correct message`() {
|
||||
val expectedTitle =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val exception = WebExtensionInstallException.NetworkFailure(
|
||||
extensionName = "name",
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(
|
||||
R.string.mozac_feature_addons_failed_to_install_network_error,
|
||||
"name",
|
||||
)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with Blocklisted error THEN showDialog with the correct message`() {
|
||||
val expectedTitle =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val extensionName = "extensionName"
|
||||
val exception = WebExtensionInstallException.Blocklisted(
|
||||
extensionName = extensionName,
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_blocklisted, extensionName)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with UserCancelled error THEN do not showDialog`() {
|
||||
val expectedTitle = ""
|
||||
val extensionName = "extensionName"
|
||||
val exception = WebExtensionInstallException.UserCancelled(
|
||||
extensionName = extensionName,
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, extensionName)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify(exactly = 0) { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with Unknown error THEN showDialog with the correct message`() {
|
||||
val expectedTitle = ""
|
||||
val extensionName = "extensionName"
|
||||
val exception = WebExtensionInstallException.Unknown(
|
||||
extensionName = extensionName,
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, extensionName)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with Unknown error and no extension name THEN showDialog with the correct message`() {
|
||||
val expectedTitle = ""
|
||||
val exception = WebExtensionInstallException.Unknown(
|
||||
extensionName = null,
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install_generic)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with CorruptFile error THEN showDialog with the correct message`() {
|
||||
val expectedTitle =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val exception = WebExtensionInstallException.CorruptFile(
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install_corrupt_error)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with NotSigned error THEN showDialog with the correct message`() {
|
||||
val expectedTitle =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val exception = WebExtensionInstallException.NotSigned(
|
||||
throwable = Exception(),
|
||||
)
|
||||
val expectedMessage =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install_not_signed_error)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN calling handleInstallationFailedRequest with Incompatible error THEN showDialog with the correct message`() {
|
||||
val expectedTitle =
|
||||
testContext.getString(R.string.mozac_feature_addons_failed_to_install, "")
|
||||
val extensionName = "extensionName"
|
||||
val exception = WebExtensionInstallException.Incompatible(
|
||||
extensionName = extensionName,
|
||||
throwable = Exception(),
|
||||
)
|
||||
val appName = testContext.getString(R.string.app_name)
|
||||
val version = testContext.appVersionName
|
||||
val expectedMessage =
|
||||
testContext.getString(
|
||||
R.string.mozac_feature_addons_failed_to_install_incompatible_error,
|
||||
extensionName,
|
||||
appName,
|
||||
version,
|
||||
)
|
||||
|
||||
webExtensionPromptFeature.handleInstallationFailedRequest(
|
||||
exception = exception,
|
||||
)
|
||||
|
||||
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user