For #18262 - [Credit cards] Turn the "Sync cards across devices" button into a "Sync cards" toggle (#19207)

* For #18262 - Turns "Sync cards/logins" into toggle
upstream-sync
Codrut Topliceanu 3 years ago committed by GitHub
parent 32d7b78e94
commit 277034546f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -108,7 +108,6 @@ class DeepLinkTest {
fun openSettingsLogins() { fun openSettingsLogins() {
robot.openSettingsLogins { robot.openSettingsLogins {
verifyDefaultView() verifyDefaultView()
verifyDefaultValueSyncLogins()
verifyDefaultValueAutofillLogins() verifyDefaultValueAutofillLogins()
} }
} }

@ -170,7 +170,6 @@ class SettingsPrivacyTest {
TestHelper.scrollToElementByText("Logins and passwords") TestHelper.scrollToElementByText("Logins and passwords")
}.openLoginsAndPasswordSubMenu { }.openLoginsAndPasswordSubMenu {
verifyDefaultView() verifyDefaultView()
verifyDefaultValueSyncLogins()
verifyDefaultValueAutofillLogins() verifyDefaultValueAutofillLogins()
verifyDefaultValueExceptions() verifyDefaultValueExceptions()
}.openSavedLogins { }.openSavedLogins {
@ -203,7 +202,6 @@ class SettingsPrivacyTest {
TestHelper.scrollToElementByText("Logins and passwords") TestHelper.scrollToElementByText("Logins and passwords")
}.openLoginsAndPasswordSubMenu { }.openLoginsAndPasswordSubMenu {
verifyDefaultView() verifyDefaultView()
verifyDefaultValueSyncLogins()
}.openSavedLogins { }.openSavedLogins {
verifySecurityPromptForLogins() verifySecurityPromptForLogins()
tapSetupLater() tapSetupLater()
@ -228,7 +226,6 @@ class SettingsPrivacyTest {
}.openSettings { }.openSettings {
}.openLoginsAndPasswordSubMenu { }.openLoginsAndPasswordSubMenu {
verifyDefaultView() verifyDefaultView()
verifyDefaultValueSyncLogins()
}.openSavedLogins { }.openSavedLogins {
verifySecurityPromptForLogins() verifySecurityPromptForLogins()
tapSetupLater() tapSetupLater()

@ -26,7 +26,7 @@ import org.mozilla.fenix.helpers.ext.waitNotNull
class SettingsSubMenuLoginsAndPasswordRobot { class SettingsSubMenuLoginsAndPasswordRobot {
fun verifyDefaultView() { fun verifyDefaultView() {
mDevice.waitNotNull(Until.findObjects(By.text("Sync logins")), TestAssetHelper.waitingTime) mDevice.waitNotNull(Until.findObjects(By.text("Sync logins across devices")), TestAssetHelper.waitingTime)
assertDefaultView() assertDefaultView()
} }
@ -42,8 +42,6 @@ class SettingsSubMenuLoginsAndPasswordRobot {
fun verifyDefaultValueAutofillLogins() = assertDefaultValueAutofillLogins() fun verifyDefaultValueAutofillLogins() = assertDefaultValueAutofillLogins()
fun verifyDefaultValueSyncLogins() = assertDefaultValueSyncLogins()
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@ -71,7 +69,7 @@ class SettingsSubMenuLoginsAndPasswordRobot {
} }
fun openSyncLogins(interact: SettingsTurnOnSyncRobot.() -> Unit): SettingsTurnOnSyncRobot.Transition { fun openSyncLogins(interact: SettingsTurnOnSyncRobot.() -> Unit): SettingsTurnOnSyncRobot.Transition {
fun syncLoginsButton() = onView(ViewMatchers.withText("Sync logins")) fun syncLoginsButton() = onView(ViewMatchers.withText("Sync logins across devices"))
syncLoginsButton().click() syncLoginsButton().click()
SettingsTurnOnSyncRobot().interact() SettingsTurnOnSyncRobot().interact()
@ -96,7 +94,7 @@ fun settingsSubMenuLoginsAndPassword(interact: SettingsSubMenuLoginsAndPasswordR
private fun goBackButton() = private fun goBackButton() =
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up"))) onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
private fun assertDefaultView() = onView(ViewMatchers.withText("Sync logins")) private fun assertDefaultView() = onView(ViewMatchers.withText("Sync logins across devices"))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
private fun assertDefaultValueAutofillLogins() = onView(ViewMatchers.withText("Autofill")) private fun assertDefaultValueAutofillLogins() = onView(ViewMatchers.withText("Autofill"))

@ -0,0 +1,43 @@
/* 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.settings
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.widget.SwitchCompat
import androidx.preference.PreferenceViewHolder
import androidx.preference.SwitchPreferenceCompat
import org.mozilla.fenix.R
/**
* Variation of [SwitchPreferenceCompat] that uses a custom widgetLayoutResource in order to implement
* visibility changes to it.
* */
class SyncPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : SwitchPreferenceCompat(context, attrs) {
private var switchView: SwitchCompat? = null
/**
* Whether or not switch's toggle widget is visible.
* */
var isSwitchWidgetVisible: Boolean = false
init {
widgetLayoutResource = R.layout.preference_sync
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
switchView = holder.findViewById(R.id.switch_widget) as SwitchCompat?
switchView?.isChecked = isChecked
switchView?.visibility = if (isSwitchWidgetVisible) View.VISIBLE else View.INVISIBLE
}
}

@ -5,7 +5,6 @@
package org.mozilla.fenix.settings package org.mozilla.fenix.settings
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.preference.Preference
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AccountObserver
@ -14,33 +13,33 @@ import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.service.fxa.SyncEngine import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.fxa.manager.SyncEnginesStorage
import org.mozilla.fenix.R
/** /**
* A view to help manage the sync preference in the "Logins and passwords" and "Credit cards" * A view to help manage the sync preference in the "Logins and passwords" and "Credit cards"
* settings. The provided [syncPreference] is used to navigate to the different fragments * settings. The provided [syncPreference] is used to navigate to the different fragments
* that manages the sync account authentication. A summary status will be also added * that manages the sync account authentication. A toggle will be also added
* depending on the sync account status. * depending on the sync account status.
* *
* @param syncPreference The sync [Preference] to update and handle navigation. * @param syncPreference The sync [SyncPreference] to update and handle navigation.
* @param lifecycleOwner View lifecycle owner used to determine when to cancel UI jobs. * @param lifecycleOwner View lifecycle owner used to determine when to cancel UI jobs.
* @param accountManager An instance of [FxaAccountManager]. * @param accountManager An instance of [FxaAccountManager].
* @param syncEngine The sync engine that will be used for the sync status lookup. * @param syncEngine The sync engine that will be used for the sync status lookup.
* @param loggedOffTitle Text label for the setting when user is not logged in.
* @param loggedInTitle Text label for the setting when user is logged in.
* @param onSignInToSyncClicked A callback executed when the [syncPreference] is clicked with a * @param onSignInToSyncClicked A callback executed when the [syncPreference] is clicked with a
* preference status of "Sign in to Sync". * preference status of "Sign in to Sync".
* @param onSyncStatusClicked A callback executed when the [syncPreference] is clicked with a
* preference status of "On" or "Off".
* @param onReconnectClicked A callback executed when the [syncPreference] is clicked with a * @param onReconnectClicked A callback executed when the [syncPreference] is clicked with a
* preference status of "Reconnect". * preference status of "Reconnect".
*/ */
@Suppress("LongParameterList") @Suppress("LongParameterList")
class SyncPreferenceView( class SyncPreferenceView(
private val syncPreference: Preference, private val syncPreference: SyncPreference,
lifecycleOwner: LifecycleOwner, lifecycleOwner: LifecycleOwner,
accountManager: FxaAccountManager, accountManager: FxaAccountManager,
private val syncEngine: SyncEngine, private val syncEngine: SyncEngine,
private val loggedOffTitle: String,
private val loggedInTitle: String,
private val onSignInToSyncClicked: () -> Unit = {}, private val onSignInToSyncClicked: () -> Unit = {},
private val onSyncStatusClicked: () -> Unit = {},
private val onReconnectClicked: () -> Unit = {} private val onReconnectClicked: () -> Unit = {}
) { ) {
@ -70,49 +69,53 @@ class SyncPreferenceView(
} }
/** /**
* Shows the current status of the sync preference ("On"/"Off") for the logged in user. * Shows a switch toggle for the sync preference when the user is logged in.
*/ */
private fun updateSyncPreferenceStatus() { private fun updateSyncPreferenceStatus() {
syncPreference.apply { syncPreference.apply {
isSwitchWidgetVisible = true
val syncEnginesStatus = SyncEnginesStorage(context).getStatus() val syncEnginesStatus = SyncEnginesStorage(context).getStatus()
val loginsSyncStatus = syncEnginesStatus.getOrElse(syncEngine) { false } val syncStatus = syncEnginesStatus.getOrElse(syncEngine) { false }
summary = context.getString( title = loggedInTitle
if (loginsSyncStatus) R.string.preferences_passwords_sync_logins_on isChecked = syncStatus
else R.string.preferences_passwords_sync_logins_off
)
setOnPreferenceClickListener { setOnPreferenceChangeListener { _, newValue ->
onSyncStatusClicked() SyncEnginesStorage(context).setStatus(syncEngine, newValue as Boolean)
true true
} }
} }
} }
/** /**
* Display that the user can "Sign in to Sync" when the user is logged off. * Display that the user can sync across devices when the user is logged off.
*/ */
private fun updateSyncPreferenceNeedsLogin() { private fun updateSyncPreferenceNeedsLogin() {
syncPreference.apply { syncPreference.apply {
summary = context.getString(R.string.preferences_passwords_sync_logins_sign_in) isSwitchWidgetVisible = false
title = loggedOffTitle
setOnPreferenceClickListener { setOnPreferenceChangeListener { _, _ ->
onSignInToSyncClicked() onSignInToSyncClicked()
true false
} }
} }
} }
/** /**
* Displays that the user needs to "Reconnect" to fix their account problems with sync. * Displays the logged off title to prompt the user to to re-authenticate their sync account.
*/ */
private fun updateSyncPreferenceNeedsReauth() { private fun updateSyncPreferenceNeedsReauth() {
syncPreference.apply { syncPreference.apply {
summary = context.getString(R.string.preferences_passwords_sync_logins_reconnect) isSwitchWidgetVisible = false
setOnPreferenceClickListener { title = loggedOffTitle
setOnPreferenceChangeListener { _, _ ->
onReconnectClicked() onReconnectClicked()
true false
} }
} }
} }

@ -80,17 +80,16 @@ class CreditCardsSettingFragment : PreferenceFragmentCompat() {
syncPreference = requirePreference(R.string.pref_key_credit_cards_sync_cards_across_devices), syncPreference = requirePreference(R.string.pref_key_credit_cards_sync_cards_across_devices),
lifecycleOwner = viewLifecycleOwner, lifecycleOwner = viewLifecycleOwner,
accountManager = requireComponents.backgroundServices.accountManager, accountManager = requireComponents.backgroundServices.accountManager,
syncEngine = SyncEngine.Passwords, syncEngine = SyncEngine.CreditCards,
loggedOffTitle = requireContext()
.getString(R.string.preferences_credit_cards_sync_cards_across_devices),
loggedInTitle = requireContext()
.getString(R.string.preferences_credit_cards_sync_cards),
onSignInToSyncClicked = { onSignInToSyncClicked = {
val directions = val directions =
CreditCardsSettingFragmentDirections.actionCreditCardsSettingFragmentToTurnOnSyncFragment() CreditCardsSettingFragmentDirections.actionCreditCardsSettingFragmentToTurnOnSyncFragment()
findNavController().navigateBlockingForAsyncNavGraph(directions) findNavController().navigateBlockingForAsyncNavGraph(directions)
}, },
onSyncStatusClicked = {
val directions =
CreditCardsSettingFragmentDirections.actionGlobalAccountSettingsFragment()
findNavController().navigateBlockingForAsyncNavGraph(directions)
},
onReconnectClicked = { onReconnectClicked = {
val directions = val directions =
CreditCardsSettingFragmentDirections.actionGlobalAccountProblemFragment() CreditCardsSettingFragmentDirections.actionGlobalAccountProblemFragment()

@ -53,7 +53,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat() {
* https://github.com/mozilla-mobile/fenix/issues/12312 * https://github.com/mozilla-mobile/fenix/issues/12312
*/ */
private fun togglePrefsEnabledWhileAuthenticating(enabled: Boolean) { private fun togglePrefsEnabledWhileAuthenticating(enabled: Boolean) {
requirePreference<Preference>(R.string.pref_key_password_sync_logins).isEnabled = enabled requirePreference<Preference>(R.string.pref_key_sync_logins).isEnabled = enabled
requirePreference<Preference>(R.string.pref_key_save_logins_settings).isEnabled = enabled requirePreference<Preference>(R.string.pref_key_save_logins_settings).isEnabled = enabled
requirePreference<Preference>(R.string.pref_key_saved_logins).isEnabled = enabled requirePreference<Preference>(R.string.pref_key_saved_logins).isEnabled = enabled
} }
@ -124,20 +124,19 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat() {
} }
SyncPreferenceView( SyncPreferenceView(
syncPreference = requirePreference(R.string.pref_key_password_sync_logins), syncPreference = requirePreference(R.string.pref_key_sync_logins),
lifecycleOwner = viewLifecycleOwner, lifecycleOwner = viewLifecycleOwner,
accountManager = requireComponents.backgroundServices.accountManager, accountManager = requireComponents.backgroundServices.accountManager,
syncEngine = SyncEngine.Passwords, syncEngine = SyncEngine.Passwords,
loggedOffTitle = requireContext()
.getString(R.string.preferences_passwords_sync_logins_across_devices),
loggedInTitle = requireContext()
.getString(R.string.preferences_passwords_sync_logins),
onSignInToSyncClicked = { onSignInToSyncClicked = {
val directions = val directions =
SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
findNavController().navigateBlockingForAsyncNavGraph(directions) findNavController().navigateBlockingForAsyncNavGraph(directions)
}, },
onSyncStatusClicked = {
val directions =
SavedLoginsAuthFragmentDirections.actionGlobalAccountSettingsFragment()
findNavController().navigateBlockingForAsyncNavGraph(directions)
},
onReconnectClicked = { onReconnectClicked = {
val directions = val directions =
SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment() SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment()

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<androidx.appcompat.widget.SwitchCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:clickable="false"
android:focusable="false"
android:gravity="center_vertical"
android:orientation="vertical" />

@ -1419,10 +1419,8 @@
<string name="preferences_passwords_autofill">Autofill</string> <string name="preferences_passwords_autofill">Autofill</string>
<!-- Preference for syncing saved logins in Fenix --> <!-- Preference for syncing saved logins in Fenix -->
<string name="preferences_passwords_sync_logins">Sync logins</string> <string name="preferences_passwords_sync_logins">Sync logins</string>
<!-- Syncing saved logins in Fenix is on --> <!-- Preference for syncing saved logins in Fenix, when not signed in-->
<string name="preferences_passwords_sync_logins_on">On</string> <string name="preferences_passwords_sync_logins_across_devices">Sync logins across devices</string>
<!-- Syncing saved logins in Fenix is off -->
<string name="preferences_passwords_sync_logins_off">Off</string>
<!-- Syncing saved logins in Fenix needs reconnect to sync --> <!-- Syncing saved logins in Fenix needs reconnect to sync -->
<string name="preferences_passwords_sync_logins_reconnect">Reconnect</string> <string name="preferences_passwords_sync_logins_reconnect">Reconnect</string>
<!-- Syncing saved logins in Fenix needs login --> <!-- Syncing saved logins in Fenix needs login -->
@ -1521,6 +1519,8 @@
<string name="preferences_credit_cards_save_and_autofill_cards_summary">Data is encrypted</string> <string name="preferences_credit_cards_save_and_autofill_cards_summary">Data is encrypted</string>
<!-- Preference option for syncing credit cards across devices. This is displayed when the user is not signed into sync --> <!-- Preference option for syncing credit cards across devices. This is displayed when the user is not signed into sync -->
<string name="preferences_credit_cards_sync_cards_across_devices">Sync cards across devices</string> <string name="preferences_credit_cards_sync_cards_across_devices">Sync cards across devices</string>
<!-- Preference option for syncing credit cards across devices. This is displayed when the user is signed into sync -->
<string name="preferences_credit_cards_sync_cards">Sync cards</string>
<!-- Preference option for adding a credit card --> <!-- Preference option for adding a credit card -->
<string name="preferences_credit_cards_add_credit_card">Add credit card</string> <string name="preferences_credit_cards_add_credit_card">Add credit card</string>
<!-- Preference option for managing saved credit cards --> <!-- Preference option for managing saved credit cards -->

@ -9,7 +9,7 @@
android:key="@string/pref_key_credit_cards_save_and_autofill_cards" android:key="@string/pref_key_credit_cards_save_and_autofill_cards"
android:summary="@string/preferences_credit_cards_save_and_autofill_cards_summary" android:summary="@string/preferences_credit_cards_save_and_autofill_cards_summary"
android:title="@string/preferences_credit_cards_save_and_autofill_cards" /> android:title="@string/preferences_credit_cards_save_and_autofill_cards" />
<Preference <org.mozilla.fenix.settings.SyncPreference
android:key="@string/pref_key_credit_cards_sync_cards_across_devices" android:key="@string/pref_key_credit_cards_sync_cards_across_devices"
android:title="@string/preferences_credit_cards_sync_cards_across_devices" android:title="@string/preferences_credit_cards_sync_cards_across_devices"
app:allowDividerBelow="true" /> app:allowDividerBelow="true" />

@ -12,9 +12,8 @@
android:defaultValue="true" android:defaultValue="true"
android:key="@string/pref_key_autofill_logins" android:key="@string/pref_key_autofill_logins"
android:title="@string/preferences_passwords_autofill" /> android:title="@string/preferences_passwords_autofill" />
<Preference <org.mozilla.fenix.settings.SyncPreference
android:key="@string/pref_key_password_sync_logins" android:key="@string/pref_key_sync_logins"
android:summary="@string/preferences_passwords_sync_logins_off"
android:title="@string/preferences_passwords_sync_logins" /> android:title="@string/preferences_passwords_sync_logins" />
<Preference <Preference
android:key="@string/pref_key_saved_logins" android:key="@string/pref_key_saved_logins"

@ -19,22 +19,26 @@ import mozilla.components.concept.sync.AccountObserver
import mozilla.components.service.fxa.SyncEngine import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.fxa.manager.SyncEnginesStorage
import mozilla.components.support.test.any
import org.junit.After import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.settings.SyncPreference
import org.mozilla.fenix.settings.SyncPreferenceView import org.mozilla.fenix.settings.SyncPreferenceView
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections
class LoginsSyncPreferenceViewTest { class SyncPreferenceViewTest {
@MockK private lateinit var syncLoginsPreference: Preference @MockK private lateinit var syncPreference: SyncPreference
@MockK private lateinit var lifecycleOwner: LifecycleOwner @MockK private lateinit var lifecycleOwner: LifecycleOwner
@MockK private lateinit var accountManager: FxaAccountManager @MockK private lateinit var accountManager: FxaAccountManager
@MockK(relaxed = true) private lateinit var navController: NavController @MockK(relaxed = true) private lateinit var navController: NavController
private lateinit var accountObserver: CapturingSlot<AccountObserver> private lateinit var accountObserver: CapturingSlot<AccountObserver>
private lateinit var clickListener: CapturingSlot<Preference.OnPreferenceClickListener> private lateinit var preferenceChangeListener: CapturingSlot<Preference.OnPreferenceChangeListener>
private lateinit var widgetVisibilitySlot: CapturingSlot<Boolean>
@Before @Before
fun setup() { fun setup() {
@ -42,17 +46,29 @@ class LoginsSyncPreferenceViewTest {
mockkConstructor(SyncEnginesStorage::class) mockkConstructor(SyncEnginesStorage::class)
accountObserver = slot() accountObserver = slot()
clickListener = slot() preferenceChangeListener = slot()
widgetVisibilitySlot = slot()
val context = mockk<Context> { val context = mockk<Context> {
every { getString(R.string.preferences_passwords_sync_logins_reconnect) } returns "Reconnect" every { getString(R.string.pref_key_credit_cards_sync_cards_across_devices) } returns "pref_key_credit_cards_sync_cards_across_devices"
every { getString(R.string.preferences_passwords_sync_logins_sign_in) } returns "Sign in to Sync" every { getString(R.string.preferences_credit_cards_sync_cards_across_devices) } returns "Sync cards across devices"
every { getString(R.string.preferences_passwords_sync_logins_on) } returns "On" every { getString(R.string.preferences_credit_cards_sync_cards) } returns "Sync cards"
every { getString(R.string.preferences_passwords_sync_logins_off) } returns "Off"
every { getString(R.string.pref_key_sync_logins) } returns "pref_key_sync_logins"
every { getString(R.string.preferences_passwords_sync_logins) } returns "Sync logins"
every { getString(R.string.preferences_passwords_sync_logins_across_devices) } returns "Sync logins across devices"
} }
every { syncLoginsPreference.summary = any() } just Runs syncPreference = mockk {
every { syncLoginsPreference.onPreferenceClickListener = capture(clickListener) } just Runs every { isSwitchWidgetVisible = any() } just Runs
every { syncLoginsPreference.context } returns context every { key } returns "pref_key_sync_logins"
every { isChecked = any() } just Runs
every { title = any() } just Runs
}
every { syncPreference.title = any() } just Runs
every { syncPreference.onPreferenceChangeListener = capture(preferenceChangeListener) } just Runs
every { syncPreference.context } returns context
every { accountManager.register(capture(accountObserver), owner = lifecycleOwner) } just Runs every { accountManager.register(capture(accountObserver), owner = lifecycleOwner) } just Runs
every { anyConstructed<SyncEnginesStorage>().getStatus() } returns emptyMap() every { anyConstructed<SyncEnginesStorage>().getStatus() } returns emptyMap()
} }
@ -66,11 +82,12 @@ class LoginsSyncPreferenceViewTest {
fun `needs reauth ui on init`() { fun `needs reauth ui on init`() {
every { accountManager.authenticatedAccount() } returns mockk() every { accountManager.authenticatedAccount() } returns mockk()
every { accountManager.accountNeedsReauth() } returns true every { accountManager.accountNeedsReauth() } returns true
createView()
verify { syncLoginsPreference.summary = "Reconnect" } createView()
assertTrue(clickListener.captured.onPreferenceClick(syncLoginsPreference))
verify { syncPreference.isSwitchWidgetVisible = false }
verify { syncPreference.title = notLoggedInTitle }
assertFalse(preferenceChangeListener.captured.onPreferenceChange(syncPreference, any()))
verify { verify {
navController.navigate( navController.navigate(
SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment() SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment()
@ -82,20 +99,29 @@ class LoginsSyncPreferenceViewTest {
fun `needs reauth ui on init even if null account`() { fun `needs reauth ui on init even if null account`() {
every { accountManager.authenticatedAccount() } returns null every { accountManager.authenticatedAccount() } returns null
every { accountManager.accountNeedsReauth() } returns true every { accountManager.accountNeedsReauth() } returns true
createView() createView()
verify { syncLoginsPreference.summary = "Reconnect" } verify { syncPreference.isSwitchWidgetVisible = false }
verify { syncPreference.title = notLoggedInTitle }
assertFalse(preferenceChangeListener.captured.onPreferenceChange(syncPreference, any()))
verify {
navController.navigate(
SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment()
)
}
} }
@Test @Test
fun `needs login if account does not exist`() { fun `needs login if account does not exist`() {
every { accountManager.authenticatedAccount() } returns null every { accountManager.authenticatedAccount() } returns null
every { accountManager.accountNeedsReauth() } returns false every { accountManager.accountNeedsReauth() } returns false
createView()
verify { syncLoginsPreference.summary = "Sign in to Sync" } createView()
assertTrue(clickListener.captured.onPreferenceClick(syncLoginsPreference))
verify { syncPreference.isSwitchWidgetVisible = false }
verify { syncPreference.title = notLoggedInTitle }
assertFalse(preferenceChangeListener.captured.onPreferenceChange(syncPreference, any()))
verify { verify {
navController.navigate( navController.navigate(
SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
@ -104,59 +130,62 @@ class LoginsSyncPreferenceViewTest {
} }
@Test @Test
fun `show status for existing account`() { fun `GIVEN LoginScreen and syncLogins true WHEN updateSyncPreferenceStatus THEN setStatus false`() {
every { accountManager.authenticatedAccount() } returns mockk() every { accountManager.authenticatedAccount() } returns mockk()
every { accountManager.accountNeedsReauth() } returns false every { accountManager.accountNeedsReauth() } returns false
createView() every { anyConstructed<SyncEnginesStorage>().getStatus() } returns mapOf(
SyncEngine.Passwords to true
)
every { anyConstructed<SyncEnginesStorage>().setStatus(any(), any()) } just Runs
verify { syncLoginsPreference.summary = "Off" } createView()
assertTrue(clickListener.captured.onPreferenceClick(syncLoginsPreference))
verify { verify { syncPreference.isSwitchWidgetVisible = true }
navController.navigate( verify { syncPreference.isChecked = true }
SavedLoginsAuthFragmentDirections.actionGlobalAccountSettingsFragment() verify { syncPreference.title = loggedInTitle }
) assertTrue(preferenceChangeListener.captured.onPreferenceChange(syncPreference, false))
} verify { anyConstructed<SyncEnginesStorage>().setStatus(any(), false) }
} }
@Test @Test
fun `show status for existing account with passwords`() { fun `GIVEN LoginScreen and syncLogins false WHEN updateSyncPreferenceStatus THEN setStatus true`() {
every { anyConstructed<SyncEnginesStorage>().getStatus() } returns mapOf(
SyncEngine.Passwords to true
)
every { accountManager.authenticatedAccount() } returns mockk() every { accountManager.authenticatedAccount() } returns mockk()
every { accountManager.accountNeedsReauth() } returns false every { accountManager.accountNeedsReauth() } returns false
createView() every { anyConstructed<SyncEnginesStorage>().getStatus() } returns mapOf(
SyncEngine.Passwords to false
)
every { anyConstructed<SyncEnginesStorage>().setStatus(any(), any()) } just Runs
verify { syncLoginsPreference.summary = "On" } createView()
assertTrue(clickListener.captured.onPreferenceClick(syncLoginsPreference))
verify { verify { syncPreference.isSwitchWidgetVisible = true }
navController.navigate( verify { syncPreference.isChecked = false }
SavedLoginsAuthFragmentDirections.actionGlobalAccountSettingsFragment() verify { syncPreference.title = loggedInTitle }
) assertTrue(preferenceChangeListener.captured.onPreferenceChange(syncPreference, true))
} verify { anyConstructed<SyncEnginesStorage>().setStatus(any(), true) }
} }
private fun createView() = SyncPreferenceView( private fun createView() = SyncPreferenceView(
syncPreference = syncLoginsPreference, syncPreference = syncPreference,
lifecycleOwner = lifecycleOwner, lifecycleOwner = lifecycleOwner,
accountManager = accountManager, accountManager = accountManager,
syncEngine = SyncEngine.Passwords, syncEngine = SyncEngine.Passwords,
loggedOffTitle = notLoggedInTitle,
loggedInTitle = loggedInTitle,
onSignInToSyncClicked = { onSignInToSyncClicked = {
val directions = val directions =
SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
navController.navigate(directions) navController.navigate(directions)
}, },
onSyncStatusClicked = {
val directions =
SavedLoginsAuthFragmentDirections.actionGlobalAccountSettingsFragment()
navController.navigate(directions)
},
onReconnectClicked = { onReconnectClicked = {
val directions = val directions =
SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment() SavedLoginsAuthFragmentDirections.actionGlobalAccountProblemFragment()
navController.navigate(directions) navController.navigate(directions)
} }
) )
companion object {
const val notLoggedInTitle: String = "Sync logins across devices"
const val loggedInTitle: String = "Sync logins"
}
} }
Loading…
Cancel
Save