Bug 1856979 - Translations UI Post-Translate Popup
parent
3b1aa89e19
commit
0505682776
@ -0,0 +1,142 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
|
import mozilla.components.browser.state.selector.findTab
|
||||||
|
import mozilla.components.browser.state.state.BrowserState
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.initialFromLanguage
|
||||||
|
import mozilla.components.concept.engine.translate.initialToLanguage
|
||||||
|
import mozilla.components.lib.state.helpers.AbstractBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for observing Translation state from [BrowserStore].
|
||||||
|
*/
|
||||||
|
class TranslationsDialogBinding(
|
||||||
|
browserStore: BrowserStore,
|
||||||
|
private val translationsDialogStore: TranslationsDialogStore,
|
||||||
|
private val sessionId: String,
|
||||||
|
private val getTranslatedPageTitle: (localizedFrom: String?, localizedTo: String?) -> String,
|
||||||
|
) : AbstractBinding<BrowserState>(browserStore) {
|
||||||
|
|
||||||
|
override suspend fun onState(flow: Flow<BrowserState>) {
|
||||||
|
flow.mapNotNull { state -> state.findTab(sessionId) }
|
||||||
|
.distinctUntilChangedBy {
|
||||||
|
it.translationsState
|
||||||
|
}
|
||||||
|
.collect { sessionState ->
|
||||||
|
val translationsState = sessionState.translationsState
|
||||||
|
|
||||||
|
val fromSelected =
|
||||||
|
translationsState.translationEngineState?.initialFromLanguage(
|
||||||
|
translationsState.supportedLanguages?.fromLanguages,
|
||||||
|
)
|
||||||
|
|
||||||
|
fromSelected?.let {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateFromSelectedLanguage(
|
||||||
|
fromSelected,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val toSelected =
|
||||||
|
translationsState.translationEngineState?.initialToLanguage(
|
||||||
|
translationsState.supportedLanguages?.toLanguages,
|
||||||
|
)
|
||||||
|
toSelected?.let {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateToSelectedLanguage(
|
||||||
|
toSelected,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
toSelected != null && fromSelected != null &&
|
||||||
|
translationsDialogStore.state.translatedPageTitle == null
|
||||||
|
) {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslatedPageTitle(
|
||||||
|
getTranslatedPageTitle(
|
||||||
|
fromSelected.localizedDisplayName,
|
||||||
|
toSelected.localizedDisplayName,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val translateFromLanguages = translationsState.supportedLanguages?.fromLanguages
|
||||||
|
translateFromLanguages?.let {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslateFromLanguages(
|
||||||
|
translateFromLanguages,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val translateToLanguages = translationsState.supportedLanguages?.toLanguages
|
||||||
|
translateToLanguages?.let {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslateToLanguages(
|
||||||
|
translateToLanguages,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (translationsState.isTranslateProcessing) {
|
||||||
|
updateStoreIfIsTranslateProcessing()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (translationsState.isTranslated && !translationsState.isTranslateProcessing) {
|
||||||
|
updateStoreIfTranslated()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (translationsState.translationError != null) {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationError(translationsState.translationError),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStoreIfIsTranslateProcessing() {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationInProgress(
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.DismissDialog(
|
||||||
|
dismissDialogState = DismissDialogState.WaitingToBeDismissed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStoreIfTranslated() {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationInProgress(
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslated(
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (translationsDialogStore.state.dismissDialogState == DismissDialogState.WaitingToBeDismissed) {
|
||||||
|
translationsDialogStore.dispatch(
|
||||||
|
TranslationsDialogAction.DismissDialog(
|
||||||
|
dismissDialogState = DismissDialogState.Dismiss,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationOperation
|
||||||
|
import mozilla.components.lib.state.Middleware
|
||||||
|
import mozilla.components.lib.state.MiddlewareContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Middleware] implementation for updating [BrowserStore] based on translation actions.
|
||||||
|
*/
|
||||||
|
class TranslationsDialogMiddleware(
|
||||||
|
private val browserStore: BrowserStore,
|
||||||
|
private val sessionId: String,
|
||||||
|
) : Middleware<TranslationsDialogState, TranslationsDialogAction> {
|
||||||
|
|
||||||
|
override fun invoke(
|
||||||
|
context: MiddlewareContext<TranslationsDialogState, TranslationsDialogAction>,
|
||||||
|
next: (TranslationsDialogAction) -> Unit,
|
||||||
|
action: TranslationsDialogAction,
|
||||||
|
) {
|
||||||
|
when (action) {
|
||||||
|
is TranslationsDialogAction.FetchSupportedLanguages -> {
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.OperationRequestedAction(
|
||||||
|
tabId = sessionId,
|
||||||
|
operation = TranslationOperation.FETCH_SUPPORTED_LANGUAGES,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.TranslateAction -> {
|
||||||
|
context.state.initialFrom?.code?.let { fromLanguage ->
|
||||||
|
context.state.initialTo?.code?.let { toLanguage ->
|
||||||
|
TranslationsAction.TranslateAction(
|
||||||
|
tabId = sessionId,
|
||||||
|
fromLanguage = fromLanguage,
|
||||||
|
toLanguage = toLanguage,
|
||||||
|
options = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}?.let {
|
||||||
|
browserStore.dispatch(
|
||||||
|
it,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.RestoreTranslation -> {
|
||||||
|
browserStore.dispatch(TranslationsAction.TranslateRestoreAction(sessionId))
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
next(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,285 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.Language
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationError
|
||||||
|
import mozilla.components.lib.state.Action
|
||||||
|
import mozilla.components.lib.state.Middleware
|
||||||
|
import mozilla.components.lib.state.State
|
||||||
|
import mozilla.components.lib.state.Store
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [TranslationsDialogStore] holds the [TranslationsDialogState] (state tree).
|
||||||
|
*
|
||||||
|
* The only way to change the [TranslationsDialogState] inside
|
||||||
|
* [TranslationsDialogStore] is to dispatch an [Action] on it.
|
||||||
|
*/
|
||||||
|
class TranslationsDialogStore(
|
||||||
|
initialState: TranslationsDialogState,
|
||||||
|
middlewares: List<Middleware<TranslationsDialogState, TranslationsDialogAction>> = emptyList(),
|
||||||
|
) : Store<TranslationsDialogState, TranslationsDialogAction>(
|
||||||
|
initialState,
|
||||||
|
TranslationsDialogReducer::reduce,
|
||||||
|
middlewares,
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
dispatch(TranslationsDialogAction.FetchSupportedLanguages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current state of the Translations bottom sheet dialog.
|
||||||
|
*
|
||||||
|
* @property isTranslated The page is currently translated.
|
||||||
|
* @property isTranslationInProgress The page is currently attempting a translation.
|
||||||
|
* @property positiveButtonType Can be enabled,disabled or in progress.
|
||||||
|
* @property error An error that can occur during the translation process.
|
||||||
|
* @property dismissDialogState Whether the dialog bottom sheet should be dismissed.
|
||||||
|
* @property initialFrom Initial "from" language, based on the translation state and page state.
|
||||||
|
* @property initialTo Initial "to" language, based on the translation state and page state.
|
||||||
|
* @property fromLanguages Translation menu items to be shown in the translate from dropdown.
|
||||||
|
* @property toLanguages Translation menu items to be shown in the translate to dropdown.
|
||||||
|
* @property translatedPageTitle Title of the bottom sheet dialogue if the page was translated.
|
||||||
|
*/
|
||||||
|
data class TranslationsDialogState(
|
||||||
|
var isTranslated: Boolean = false,
|
||||||
|
val isTranslationInProgress: Boolean = false,
|
||||||
|
val positiveButtonType: PositiveButtonType? = null,
|
||||||
|
val error: TranslationError? = null,
|
||||||
|
val dismissDialogState: DismissDialogState? = null,
|
||||||
|
val initialFrom: Language? = null,
|
||||||
|
val initialTo: Language? = null,
|
||||||
|
val fromLanguages: List<Language>? = null,
|
||||||
|
val toLanguages: List<Language>? = null,
|
||||||
|
val translatedPageTitle: String? = null,
|
||||||
|
) : State
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to dispatch through the `TranslationsStore` to modify `TranslationsDialogState` through the reducer.
|
||||||
|
*/
|
||||||
|
sealed class TranslationsDialogAction : Action {
|
||||||
|
/**
|
||||||
|
* Invoked when the [TranslationsDialogStore] is added to the fragment.
|
||||||
|
*/
|
||||||
|
object InitTranslationsDialog : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When FetchSupportedLanguages is dispatched, an [TranslationsAction.OperationRequestedAction]
|
||||||
|
* will be dispatched to the [BrowserStore]
|
||||||
|
*/
|
||||||
|
object FetchSupportedLanguages : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the user wants to translate a website.
|
||||||
|
*/
|
||||||
|
object TranslateAction : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the user wants to restore the website to its original pre-translated content.
|
||||||
|
*/
|
||||||
|
object RestoreTranslation : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a translation error occurs during the translation process.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslationError(
|
||||||
|
val translationError: TranslationError? = null,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates translate from languages list.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslateFromLanguages(
|
||||||
|
val translateFromLanguages: List<Language>,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates translate to languages list.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslateToLanguages(
|
||||||
|
val translateToLanguages: List<Language>,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates to the current selected language from the "translateFromLanguages" list.
|
||||||
|
*/
|
||||||
|
data class UpdateFromSelectedLanguage(
|
||||||
|
val language: Language,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates to the current selected language from the "translateToLanguages" list.
|
||||||
|
*/
|
||||||
|
data class UpdateToSelectedLanguage(
|
||||||
|
val language: Language,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss the translation dialog fragment.
|
||||||
|
*/
|
||||||
|
data class DismissDialog(
|
||||||
|
val dismissDialogState: DismissDialogState,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialog content to translation in progress status.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslationInProgress(
|
||||||
|
val inProgress: Boolean,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialog content to translated status.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslated(
|
||||||
|
val isTranslated: Boolean,
|
||||||
|
) : TranslationsDialogAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialog title if the page was translated.
|
||||||
|
*/
|
||||||
|
data class UpdateTranslatedPageTitle(val title: String) : TranslationsDialogAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Positive button type from the translation bottom sheet.
|
||||||
|
*/
|
||||||
|
sealed class PositiveButtonType {
|
||||||
|
/**
|
||||||
|
* The translating indicator will appear.
|
||||||
|
*/
|
||||||
|
object InProgress : PositiveButtonType()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button is in a disabled state.
|
||||||
|
*/
|
||||||
|
object Disabled : PositiveButtonType()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button is in a enabled state.
|
||||||
|
*/
|
||||||
|
object Enabled : PositiveButtonType()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss translation bottom sheet type.
|
||||||
|
*/
|
||||||
|
sealed class DismissDialogState {
|
||||||
|
/**
|
||||||
|
* The dialog should be dismissed.
|
||||||
|
*/
|
||||||
|
object Dismiss : DismissDialogState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the step when translation is in progress and the dialog is waiting to be dismissed.
|
||||||
|
*/
|
||||||
|
object WaitingToBeDismissed : DismissDialogState()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object TranslationsDialogReducer {
|
||||||
|
/**
|
||||||
|
* Reduces the translations dialog state from the current state and an action performed on it.
|
||||||
|
*
|
||||||
|
* @param state The current translations dialog state.
|
||||||
|
* @param action The action to perform.
|
||||||
|
* @return The new [TranslationsDialogState].
|
||||||
|
*/
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
fun reduce(
|
||||||
|
state: TranslationsDialogState,
|
||||||
|
action: TranslationsDialogAction,
|
||||||
|
): TranslationsDialogState {
|
||||||
|
return when (action) {
|
||||||
|
is TranslationsDialogAction.UpdateFromSelectedLanguage -> {
|
||||||
|
state.copy(
|
||||||
|
initialFrom = action.language,
|
||||||
|
positiveButtonType = if (state.initialTo != null && action.language != state.initialTo) {
|
||||||
|
PositiveButtonType.Enabled
|
||||||
|
} else {
|
||||||
|
PositiveButtonType.Disabled
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateToSelectedLanguage -> {
|
||||||
|
state.copy(
|
||||||
|
initialTo = action.language,
|
||||||
|
positiveButtonType = if (state.initialFrom != null && action.language != state.initialFrom) {
|
||||||
|
PositiveButtonType.Enabled
|
||||||
|
} else {
|
||||||
|
PositiveButtonType.Disabled
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslateToLanguages -> {
|
||||||
|
state.copy(toLanguages = action.translateToLanguages)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslateFromLanguages -> {
|
||||||
|
state.copy(fromLanguages = action.translateFromLanguages)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.DismissDialog -> {
|
||||||
|
state.copy(dismissDialogState = action.dismissDialogState)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslationInProgress -> {
|
||||||
|
state.copy(
|
||||||
|
isTranslationInProgress = action.inProgress,
|
||||||
|
positiveButtonType = if (action.inProgress) {
|
||||||
|
PositiveButtonType.InProgress
|
||||||
|
} else {
|
||||||
|
state.positiveButtonType
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.InitTranslationsDialog -> {
|
||||||
|
state.copy(
|
||||||
|
positiveButtonType = if (state.initialTo == null || state.initialFrom == null) {
|
||||||
|
PositiveButtonType.Disabled
|
||||||
|
} else {
|
||||||
|
state.positiveButtonType
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslationError -> {
|
||||||
|
state.copy(
|
||||||
|
error = action.translationError,
|
||||||
|
positiveButtonType = if (
|
||||||
|
action.translationError is TranslationError.LanguageNotSupportedError
|
||||||
|
) {
|
||||||
|
PositiveButtonType.Disabled
|
||||||
|
} else {
|
||||||
|
PositiveButtonType.Enabled
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslated -> {
|
||||||
|
state.copy(
|
||||||
|
isTranslated = action.isTranslated,
|
||||||
|
positiveButtonType = PositiveButtonType.Disabled,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.UpdateTranslatedPageTitle -> {
|
||||||
|
state.copy(translatedPageTitle = action.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
is TranslationsDialogAction.TranslateAction,
|
||||||
|
TranslationsDialogAction.FetchSupportedLanguages,
|
||||||
|
TranslationsDialogAction.RestoreTranslation,
|
||||||
|
-> {
|
||||||
|
// handled by [TranslationsDialogMiddleware]
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,308 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.state.BrowserState
|
||||||
|
import mozilla.components.browser.state.state.createTab
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.DetectedLanguages
|
||||||
|
import mozilla.components.concept.engine.translate.Language
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationEngineState
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationError
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationOperation
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationPair
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationSupport
|
||||||
|
import mozilla.components.support.test.ext.joinBlocking
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||||
|
import mozilla.components.support.test.rule.runTestOnMain
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mockito.spy
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class TranslationsDialogBindingTest {
|
||||||
|
@get:Rule
|
||||||
|
val coroutineRule = MainCoroutineRule()
|
||||||
|
|
||||||
|
lateinit var browserStore: BrowserStore
|
||||||
|
private lateinit var translationsDialogStore: TranslationsDialogStore
|
||||||
|
|
||||||
|
private val tabId = "1"
|
||||||
|
private val tab = createTab(url = tabId, id = tabId)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN fromLanguage and toLanguage get updated in the browserStore THEN translations dialog actions dispatched with the update`() =
|
||||||
|
runTestOnMain {
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
translationsDialogStore = spy(TranslationsDialogStore(TranslationsDialogState()))
|
||||||
|
browserStore = BrowserStore(
|
||||||
|
BrowserState(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabId = tabId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val binding = TranslationsDialogBinding(
|
||||||
|
browserStore = browserStore,
|
||||||
|
translationsDialogStore = translationsDialogStore,
|
||||||
|
sessionId = tabId,
|
||||||
|
getTranslatedPageTitle = { localizedFrom, localizedTo ->
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
localizedFrom,
|
||||||
|
localizedTo,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
binding.start()
|
||||||
|
|
||||||
|
val detectedLanguages = DetectedLanguages(
|
||||||
|
documentLangTag = englishLanguage.code,
|
||||||
|
supportedDocumentLang = true,
|
||||||
|
userPreferredLangTag = spanishLanguage.code,
|
||||||
|
)
|
||||||
|
|
||||||
|
val translationEngineState = TranslationEngineState(
|
||||||
|
detectedLanguages = detectedLanguages,
|
||||||
|
error = null,
|
||||||
|
isEngineReady = true,
|
||||||
|
requestedTranslationPair = TranslationPair(
|
||||||
|
fromLanguage = englishLanguage.code,
|
||||||
|
toLanguage = spanishLanguage.code,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val supportLanguages = TranslationSupport(
|
||||||
|
fromLanguages = listOf(englishLanguage),
|
||||||
|
toLanguages = listOf(spanishLanguage),
|
||||||
|
)
|
||||||
|
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.SetSupportedLanguagesAction(
|
||||||
|
tabId = tab.id,
|
||||||
|
supportedLanguages = supportLanguages,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateStateChangeAction(
|
||||||
|
tabId = tabId,
|
||||||
|
translationEngineState = translationEngineState,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateFromSelectedLanguage(
|
||||||
|
englishLanguage,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateToSelectedLanguage(
|
||||||
|
spanishLanguage,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslatedPageTitle(
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
englishLanguage.localizedDisplayName,
|
||||||
|
spanishLanguage.localizedDisplayName,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN translate action is sent to the browserStore THEN update translation dialog store based on operation`() =
|
||||||
|
runTestOnMain {
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
translationsDialogStore = spy(TranslationsDialogStore(TranslationsDialogState()))
|
||||||
|
browserStore = BrowserStore(
|
||||||
|
BrowserState(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabId = tabId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val binding = TranslationsDialogBinding(
|
||||||
|
browserStore = browserStore,
|
||||||
|
translationsDialogStore = translationsDialogStore,
|
||||||
|
sessionId = tabId,
|
||||||
|
getTranslatedPageTitle = { localizedFrom, localizedTo ->
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
localizedFrom,
|
||||||
|
localizedTo,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
binding.start()
|
||||||
|
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateAction(
|
||||||
|
tabId = tabId,
|
||||||
|
fromLanguage = englishLanguage.code,
|
||||||
|
toLanguage = spanishLanguage.code,
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationInProgress(
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.DismissDialog(
|
||||||
|
dismissDialogState = DismissDialogState.WaitingToBeDismissed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN translate from languages list and translate to languages list are sent to the browserStore THEN update translation dialog store based on operation`() =
|
||||||
|
runTestOnMain {
|
||||||
|
translationsDialogStore = spy(TranslationsDialogStore(TranslationsDialogState()))
|
||||||
|
browserStore = BrowserStore(
|
||||||
|
BrowserState(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabId = tabId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val binding = TranslationsDialogBinding(
|
||||||
|
browserStore = browserStore,
|
||||||
|
translationsDialogStore = translationsDialogStore,
|
||||||
|
sessionId = tabId,
|
||||||
|
getTranslatedPageTitle = { localizedFrom, localizedTo ->
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
localizedFrom,
|
||||||
|
localizedTo,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
binding.start()
|
||||||
|
|
||||||
|
val toLanguage = Language("de", "German")
|
||||||
|
val fromLanguage = Language("es", "Spanish")
|
||||||
|
val supportedLanguages = TranslationSupport(listOf(fromLanguage), listOf(toLanguage))
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.SetSupportedLanguagesAction(
|
||||||
|
tabId = tab.id,
|
||||||
|
supportedLanguages = supportedLanguages,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslateFromLanguages(
|
||||||
|
listOf(fromLanguage),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslateToLanguages(
|
||||||
|
listOf(toLanguage),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN translate action success is sent to the browserStore THEN update translation dialog store based on operation`() =
|
||||||
|
runTestOnMain {
|
||||||
|
translationsDialogStore =
|
||||||
|
spy(TranslationsDialogStore(TranslationsDialogState(dismissDialogState = DismissDialogState.WaitingToBeDismissed)))
|
||||||
|
browserStore = BrowserStore(
|
||||||
|
BrowserState(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabId = tabId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val binding = TranslationsDialogBinding(
|
||||||
|
browserStore = browserStore,
|
||||||
|
translationsDialogStore = translationsDialogStore,
|
||||||
|
sessionId = tabId,
|
||||||
|
getTranslatedPageTitle = { localizedFrom, localizedTo ->
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
localizedFrom,
|
||||||
|
localizedTo,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
binding.start()
|
||||||
|
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateSuccessAction(
|
||||||
|
tabId = tab.id,
|
||||||
|
operation = TranslationOperation.TRANSLATE,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslated(
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationInProgress(
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.DismissDialog(
|
||||||
|
dismissDialogState = DismissDialogState.Dismiss,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN translate fetch error is sent to the browserStore THEN update translation dialog store based on operation`() =
|
||||||
|
runTestOnMain {
|
||||||
|
translationsDialogStore =
|
||||||
|
spy(TranslationsDialogStore(TranslationsDialogState()))
|
||||||
|
browserStore = BrowserStore(
|
||||||
|
BrowserState(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabId = tabId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val binding = TranslationsDialogBinding(
|
||||||
|
browserStore = browserStore,
|
||||||
|
translationsDialogStore = translationsDialogStore,
|
||||||
|
sessionId = tabId,
|
||||||
|
getTranslatedPageTitle = { localizedFrom, localizedTo ->
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
localizedFrom,
|
||||||
|
localizedTo,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
binding.start()
|
||||||
|
|
||||||
|
val fetchError = TranslationError.CouldNotLoadLanguagesError(null)
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateExceptionAction(
|
||||||
|
tabId = tab.id,
|
||||||
|
operation = TranslationOperation.FETCH_SUPPORTED_LANGUAGES,
|
||||||
|
translationError = fetchError,
|
||||||
|
),
|
||||||
|
).joinBlocking()
|
||||||
|
|
||||||
|
verify(translationsDialogStore).dispatch(
|
||||||
|
TranslationsDialogAction.UpdateTranslationError(fetchError),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.Language
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationOperation
|
||||||
|
import mozilla.components.support.test.ext.joinBlocking
|
||||||
|
import mozilla.components.support.test.libstate.ext.waitUntilIdle
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class TranslationsDialogMiddlewareTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN translationState WHEN FetchSupportedLanguages action is called THEN call OperationRequestedAction from BrowserStore`() =
|
||||||
|
runTest {
|
||||||
|
val browserStore = mockk<BrowserStore>(relaxed = true)
|
||||||
|
val translationsDialogMiddleware =
|
||||||
|
TranslationsDialogMiddleware(browserStore = browserStore, sessionId = "tab1")
|
||||||
|
|
||||||
|
val translationStore = TranslationsDialogStore(
|
||||||
|
initialState = TranslationsDialogState(),
|
||||||
|
middlewares = listOf(translationsDialogMiddleware),
|
||||||
|
)
|
||||||
|
translationStore.dispatch(TranslationsDialogAction.FetchSupportedLanguages).joinBlocking()
|
||||||
|
|
||||||
|
translationStore.waitUntilIdle()
|
||||||
|
|
||||||
|
verify {
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.OperationRequestedAction(
|
||||||
|
tabId = "tab1",
|
||||||
|
operation = TranslationOperation.FETCH_SUPPORTED_LANGUAGES,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN translationState WHEN TranslateAction from TranslationDialogStore is called THEN call TranslateAction from BrowserStore`() =
|
||||||
|
runTest {
|
||||||
|
val browserStore = mockk<BrowserStore>(relaxed = true)
|
||||||
|
val translationsDialogMiddleware =
|
||||||
|
TranslationsDialogMiddleware(browserStore = browserStore, sessionId = "tab1")
|
||||||
|
|
||||||
|
val translationStore = TranslationsDialogStore(
|
||||||
|
initialState = TranslationsDialogState(
|
||||||
|
initialFrom = Language("en", "English"),
|
||||||
|
initialTo = Language("fr", "France"),
|
||||||
|
),
|
||||||
|
middlewares = listOf(translationsDialogMiddleware),
|
||||||
|
)
|
||||||
|
translationStore.dispatch(TranslationsDialogAction.TranslateAction).joinBlocking()
|
||||||
|
|
||||||
|
translationStore.waitUntilIdle()
|
||||||
|
|
||||||
|
verify {
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateAction(
|
||||||
|
tabId = "tab1",
|
||||||
|
fromLanguage = "en",
|
||||||
|
toLanguage = "fr",
|
||||||
|
options = null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN translationState WHEN RestoreTranslation from TranslationDialogStore is called THEN call TranslateRestoreAction from BrowserStore`() =
|
||||||
|
runTest {
|
||||||
|
val browserStore = mockk<BrowserStore>(relaxed = true)
|
||||||
|
val translationsDialogMiddleware =
|
||||||
|
TranslationsDialogMiddleware(browserStore = browserStore, sessionId = "tab1")
|
||||||
|
|
||||||
|
val translationStore = TranslationsDialogStore(
|
||||||
|
initialState = TranslationsDialogState(),
|
||||||
|
middlewares = listOf(translationsDialogMiddleware),
|
||||||
|
)
|
||||||
|
translationStore.dispatch(TranslationsDialogAction.RestoreTranslation).joinBlocking()
|
||||||
|
|
||||||
|
translationStore.waitUntilIdle()
|
||||||
|
|
||||||
|
verify {
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.TranslateRestoreAction(
|
||||||
|
tabId = "tab1",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
/* 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.translations
|
||||||
|
|
||||||
|
import mozilla.components.concept.engine.translate.Language
|
||||||
|
import mozilla.components.concept.engine.translate.TranslationError
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class TranslationsDialogReducerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateFromSelectedLanguage THEN a new state with updated fromSelectedLanguage is returned`() {
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
|
||||||
|
val translationsDialogState = TranslationsDialogState(initialTo = spanishLanguage)
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateFromSelectedLanguage(englishLanguage),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(englishLanguage, updatedState.initialFrom)
|
||||||
|
assertEquals(PositiveButtonType.Enabled, updatedState.positiveButtonType)
|
||||||
|
|
||||||
|
val updatedStateTwo = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateFromSelectedLanguage(spanishLanguage),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(PositiveButtonType.Disabled, updatedStateTwo.positiveButtonType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateToSelectedLanguage THEN a new state with updated toSelectedLanguage is returned`() {
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
|
||||||
|
val translationsDialogState = TranslationsDialogState(initialFrom = spanishLanguage)
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateToSelectedLanguage(englishLanguage),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(englishLanguage, updatedState.initialTo)
|
||||||
|
assertEquals(PositiveButtonType.Enabled, updatedState.positiveButtonType)
|
||||||
|
|
||||||
|
val updatedStateTwo = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateToSelectedLanguage(spanishLanguage),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(PositiveButtonType.Disabled, updatedStateTwo.positiveButtonType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateTranslateToLanguages THEN a new state with updated translateToLanguages is returned`() {
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslateToLanguages(
|
||||||
|
listOf(
|
||||||
|
spanishLanguage,
|
||||||
|
englishLanguage,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(listOf(spanishLanguage, englishLanguage), updatedState.toLanguages)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateTranslateFromLanguages THEN a new state with updated translatefromLanguages is returned`() {
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslateFromLanguages(
|
||||||
|
listOf(
|
||||||
|
spanishLanguage,
|
||||||
|
englishLanguage,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(listOf(spanishLanguage, englishLanguage), updatedState.fromLanguages)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for DismissDialog THEN a new state with updated dismiss dialog is returned`() {
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.DismissDialog(DismissDialogState.Dismiss),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(DismissDialogState.Dismiss, updatedState.dismissDialogState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateInProgress THEN a new state with translation in progress is returned`() {
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslationInProgress(true),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(true, updatedState.isTranslationInProgress)
|
||||||
|
assertEquals(PositiveButtonType.InProgress, updatedState.positiveButtonType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for InitTranslationsDialog THEN a new state for PositiveButtonType is returned`() {
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.InitTranslationsDialog,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(PositiveButtonType.Disabled, updatedState.positiveButtonType)
|
||||||
|
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
val translationsDialogStateTwo = TranslationsDialogState(
|
||||||
|
initialFrom = spanishLanguage,
|
||||||
|
initialTo = englishLanguage,
|
||||||
|
positiveButtonType = PositiveButtonType.Enabled,
|
||||||
|
)
|
||||||
|
|
||||||
|
val updatedStateTwo = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogStateTwo,
|
||||||
|
TranslationsDialogAction.InitTranslationsDialog,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(PositiveButtonType.Enabled, updatedStateTwo.positiveButtonType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateTranslationError THEN a new state with translation error is returned`() {
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslationError(
|
||||||
|
TranslationError.LanguageNotSupportedError(
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(updatedState.error is TranslationError.LanguageNotSupportedError)
|
||||||
|
assertEquals(PositiveButtonType.Disabled, updatedState.positiveButtonType)
|
||||||
|
|
||||||
|
val updatedStateTwo = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslationError(
|
||||||
|
TranslationError.CouldNotLoadLanguagesError(
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(updatedStateTwo.error is TranslationError.CouldNotLoadLanguagesError)
|
||||||
|
assertEquals(PositiveButtonType.Enabled, updatedStateTwo.positiveButtonType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateTranslated THEN a new state with translation translated is returned`() {
|
||||||
|
val translationsDialogState = TranslationsDialogState()
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslated(
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(PositiveButtonType.Disabled, updatedState.positiveButtonType)
|
||||||
|
assertEquals(true, updatedState.isTranslated)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN the reducer is called for UpdateTranslatedPageTitle THEN a new state with translation title is returned`() {
|
||||||
|
val spanishLanguage = Language("es", "Spanish")
|
||||||
|
val englishLanguage = Language("en", "English")
|
||||||
|
val translationsDialogState =
|
||||||
|
TranslationsDialogState(initialTo = englishLanguage, initialFrom = spanishLanguage)
|
||||||
|
|
||||||
|
val updatedState = TranslationsDialogReducer.reduce(
|
||||||
|
translationsDialogState,
|
||||||
|
TranslationsDialogAction.UpdateTranslatedPageTitle(
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
spanishLanguage.localizedDisplayName,
|
||||||
|
englishLanguage.localizedDisplayName,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testContext.getString(
|
||||||
|
R.string.translations_bottom_sheet_title_translation_completed,
|
||||||
|
spanishLanguage.localizedDisplayName,
|
||||||
|
englishLanguage.localizedDisplayName,
|
||||||
|
),
|
||||||
|
updatedState.translatedPageTitle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue