diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStore.kt new file mode 100644 index 000000000..043607625 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStore.kt @@ -0,0 +1,64 @@ +/* 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.creditcards + +import mozilla.components.concept.storage.CreditCard +import mozilla.components.lib.state.Action +import mozilla.components.lib.state.State +import mozilla.components.lib.state.Store + +/** + * The [Store] for holding the [CreditCardsListState] and applying [CreditCardsAction]s. + */ +class CreditCardsFragmentStore(initialState: CreditCardsListState) : + Store( + initialState, ::creditCardsFragmentStateReducer + ) + +/** + * The state for [CreditCardsManagementFragment]. + * + * @property creditCards The list of [CreditCard]s to display in the credit card list. + * @property isLoading True if the credit cards are still being loaded from storage, + * otherwise false. + */ +data class CreditCardsListState( + val creditCards: List, + val isLoading: Boolean = true +) : State + +/** + * Actions to dispatch through the [CreditCardsFragmentStore] to modify the [CreditCardsListState] + * through the [creditCardsFragmentStateReducer]. + */ +sealed class CreditCardsAction : Action { + /** + * Updates the list of credit cards with the provided [creditCards]. + * + * @param creditCards The list of [CreditCard]s to display in the credit card list. + */ + data class UpdateCreditCards(val creditCards: List) : CreditCardsAction() +} + +/** + * Reduces the credit cards state from the current state with the provided [action] to be performed. + * + * @param state The current credit cards state. + * @param action The action to be performed on the state. + * @return the new [CreditCardsListState] with the [action] executed. + */ +private fun creditCardsFragmentStateReducer( + state: CreditCardsListState, + action: CreditCardsAction +): CreditCardsListState { + return when (action) { + is CreditCardsAction.UpdateCreditCards -> { + state.copy( + creditCards = action.creditCards, + isLoading = false + ) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt new file mode 100644 index 000000000..be0ceaffa --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt @@ -0,0 +1,86 @@ +/* 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.creditcards + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import kotlinx.android.synthetic.main.fragment_saved_cards.view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import mozilla.components.lib.state.ext.consumeFrom +import org.mozilla.fenix.R +import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.showToolbar +import org.mozilla.fenix.settings.creditcards.controller.DefaultCreditCardsManagementController +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor +import org.mozilla.fenix.settings.creditcards.interactor.DefaultCreditCardsManagementInteractor +import org.mozilla.fenix.settings.creditcards.view.CreditCardsManagementView + +/** + * Displays a list of saved credit cards. + */ +class CreditCardsManagementFragment : Fragment() { + + private lateinit var creditCardsStore: CreditCardsFragmentStore + private lateinit var interactor: CreditCardsManagementInteractor + private lateinit var creditCardsView: CreditCardsManagementView + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_saved_cards, container, false) + + creditCardsStore = StoreProvider.get(this) { + CreditCardsFragmentStore(CreditCardsListState(creditCards = emptyList())) + } + + interactor = DefaultCreditCardsManagementInteractor( + controller = DefaultCreditCardsManagementController( + navController = findNavController() + ) + ) + + creditCardsView = CreditCardsManagementView(view.saved_cards_layout, interactor) + + loadCreditCards() + + return view + } + + @ExperimentalCoroutinesApi + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + consumeFrom(creditCardsStore) { state -> + creditCardsView.update(state) + } + } + + override fun onResume() { + super.onResume() + showToolbar(getString(R.string.credit_cards_saved_cards)) + } + + /** + * Fetches all the credit cards from the autofill storage and updates the + * [CreditCardsFragmentStore] with the list of credit cards. + */ + private fun loadCreditCards() { + lifecycleScope.launch(Dispatchers.IO) { + val creditCards = requireContext().components.core.autofillStorage.getAllCreditCards() + + lifecycleScope.launch(Dispatchers.Main) { + creditCardsStore.dispatch(CreditCardsAction.UpdateCreditCards(creditCards)) + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt index 8febafc58..aa19cff8b 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt @@ -54,11 +54,19 @@ class CreditCardsSettingFragment : PreferenceFragmentCompat() { ) } + @Suppress("MaxLineLength") override fun onPreferenceTreeClick(preference: Preference): Boolean { when (preference.key) { getPreferenceKey(R.string.pref_key_credit_cards_add_credit_card) -> { val directions = - CreditCardsSettingFragmentDirections.actionCreditCardsSettingFragmentToCreditCardEditorFragment() + CreditCardsSettingFragmentDirections + .actionCreditCardsSettingFragmentToCreditCardEditorFragment() + findNavController().navigate(directions) + } + getPreferenceKey(R.string.pref_key_credit_cards_manage_saved_cards) -> { + val directions = + CreditCardsSettingFragmentDirections + .actionCreditCardsSettingFragmentToCreditCardsManagementFragment() findNavController().navigate(directions) } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardsManagementController.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardsManagementController.kt new file mode 100644 index 000000000..d40478348 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardsManagementController.kt @@ -0,0 +1,35 @@ +/* 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.creditcards.controller + +import androidx.navigation.NavController +import org.mozilla.fenix.settings.creditcards.CreditCardsManagementFragmentDirections + +/** + * [CreditCardsManagementFragment] controller. An interface that handles the view manipulation of + * the credit cards manager triggered by the Interactor. + */ +interface CreditCardsManagementController { + + /** + * @see [CreditCardsManagementInteractor.onSelectCreditCard] + */ + fun handleCreditCardClicked() +} + +/** + * The default implementation of [CreditCardsManagementController]. + */ +class DefaultCreditCardsManagementController( + private val navController: NavController +) : CreditCardsManagementController { + + override fun handleCreditCardClicked() { + navController.navigate( + CreditCardsManagementFragmentDirections + .actionCreditCardsManagementFragmentToCreditCardEditorFragment() + ) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardsManagementInteractor.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardsManagementInteractor.kt new file mode 100644 index 000000000..97e125cee --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardsManagementInteractor.kt @@ -0,0 +1,31 @@ +/* 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.creditcards.interactor + +import org.mozilla.fenix.settings.creditcards.controller.CreditCardsManagementController + +/** + * Interface for the credit cards management Interactor. + */ +interface CreditCardsManagementInteractor { + + /** + * Navigates to the credit card editor to edit the selected credit card. Called when a user + * taps on a credit card item. + */ + fun onSelectCreditCard() +} + +/** + * The default implementation of [CreditCardEditorInteractor] + */ +class DefaultCreditCardsManagementInteractor( + private val controller: CreditCardsManagementController +) : CreditCardsManagementInteractor { + + override fun onSelectCreditCard() { + controller.handleCreditCardClicked() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardItemViewHolder.kt new file mode 100644 index 000000000..616d4a251 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardItemViewHolder.kt @@ -0,0 +1,56 @@ +/* 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.creditcards.view + +import android.view.View +import kotlinx.android.synthetic.main.credit_card_list_item.* +import mozilla.components.concept.storage.CreditCard +import org.mozilla.fenix.R +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor +import org.mozilla.fenix.utils.view.ViewHolder +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +/** + * View holder for a credit card list item. + */ +class CreditCardItemViewHolder( + view: View, + private val interactor: CreditCardsManagementInteractor +) : ViewHolder(view) { + + fun bind(creditCard: CreditCard) { + credit_card_number.text = creditCard.cardNumber + + bindCreditCardExpiryDate(creditCard) + + itemView.setOnClickListener { + interactor.onSelectCreditCard() + } + } + + /** + * Set the credit card expiry date formatted according to the locale. + */ + private fun bindCreditCardExpiryDate(creditCard: CreditCard) { + val dateFormat = SimpleDateFormat(DATE_PATTERN, Locale.getDefault()) + + val calendar = Calendar.getInstance() + calendar.set(Calendar.DAY_OF_MONTH, 1) + // Subtract 1 from the expiry month since Calendar.Month is based on a 0-indexed. + calendar.set(Calendar.MONTH, creditCard.expiryMonth.toInt() - 1) + calendar.set(Calendar.YEAR, creditCard.expiryYear.toInt()) + + expiry_date.text = dateFormat.format(calendar.time) + } + + companion object { + const val LAYOUT_ID = R.layout.credit_card_list_item + + // Date format pattern for the credit card expiry date. + private const val DATE_PATTERN = "MM/yyyy" + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsAdapter.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsAdapter.kt new file mode 100644 index 000000000..55d5c0328 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsAdapter.kt @@ -0,0 +1,38 @@ +/* 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.creditcards.view + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import mozilla.components.concept.storage.CreditCard +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor + +/** + * Adapter for a list of credit cards to be displayed. + */ +class CreditCardsAdapter( + private val interactor: CreditCardsManagementInteractor +) : ListAdapter(DiffCallback) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CreditCardItemViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(CreditCardItemViewHolder.LAYOUT_ID, parent, false) + return CreditCardItemViewHolder(view, interactor) + } + + override fun onBindViewHolder(holder: CreditCardItemViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + internal object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: CreditCard, newItem: CreditCard) = + oldItem.guid == newItem.guid + + override fun areContentsTheSame(oldItem: CreditCard, newItem: CreditCard) = + oldItem == newItem + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt new file mode 100644 index 000000000..8bc175076 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt @@ -0,0 +1,49 @@ +/* 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.creditcards.view + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.component_credit_cards.* +import org.mozilla.fenix.R +import org.mozilla.fenix.settings.creditcards.CreditCardsListState +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor + +/** + * Shows a list of credit cards. + */ +class CreditCardsManagementView( + override val containerView: ViewGroup, + val interactor: CreditCardsManagementInteractor +) : LayoutContainer { + + private val creditCardsAdapter = CreditCardsAdapter(interactor) + + init { + LayoutInflater.from(containerView.context).inflate(LAYOUT_ID, containerView, true) + + credit_cards_list.apply { + adapter = creditCardsAdapter + layoutManager = LinearLayoutManager(containerView.context) + } + } + + /** + * Updates the display of the credit cards based on the given [CreditCardsListState]. + */ + fun update(state: CreditCardsListState) { + progress_bar.isVisible = state.isLoading + credit_cards_list.isVisible = state.creditCards.isNotEmpty() + + creditCardsAdapter.submitList(state.creditCards) + } + + companion object { + const val LAYOUT_ID = R.layout.component_credit_cards + } +} diff --git a/app/src/main/res/layout/component_credit_cards.xml b/app/src/main/res/layout/component_credit_cards.xml new file mode 100644 index 000000000..34471f4b5 --- /dev/null +++ b/app/src/main/res/layout/component_credit_cards.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/credit_card_list_item.xml b/app/src/main/res/layout/credit_card_list_item.xml new file mode 100644 index 000000000..386eed434 --- /dev/null +++ b/app/src/main/res/layout/credit_card_list_item.xml @@ -0,0 +1,45 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_saved_cards.xml b/app/src/main/res/layout/fragment_saved_cards.xml new file mode 100644 index 000000000..d0cee56d7 --- /dev/null +++ b/app/src/main/res/layout/fragment_saved_cards.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 552306844..c982d10d8 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -27,7 +27,7 @@ android:id="@+id/action_global_search_dialog" app:destination="@id/searchDialogFragment" app:popUpTo="@id/searchDialogFragment" - app:popUpToInclusive="true"/> + app:popUpToInclusive="true" /> + app:popUpToInclusive="true" /> + app:argType="mozilla.components.browser.state.state.content.PermissionHighlightsState" /> + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 343a1a0c5..f3096b3c1 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -221,6 +221,8 @@ This should be the same value as radio_button_padding_horizontal. --> 16dp 16sp + 16dp + 48dp 48dp diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 5ff80b4a4..77013d210 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -179,6 +179,8 @@ pref_key_credit_cards_sync_cards_across_devices pref_key_credit_cards_add_credit_card + + pref_key_credit_cards_manage_saved_cards pref_key_open_links_in_a_private_tab diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6d882c688..999b4e396 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1524,6 +1524,8 @@ Sync cards across devices Add credit card + + Manage saved cards Add card @@ -1542,6 +1544,8 @@ Save Cancel + + Saved cards Add search engine diff --git a/app/src/main/res/xml/credit_cards_preferences.xml b/app/src/main/res/xml/credit_cards_preferences.xml index 21e9cb551..ea745e992 100644 --- a/app/src/main/res/xml/credit_cards_preferences.xml +++ b/app/src/main/res/xml/credit_cards_preferences.xml @@ -11,10 +11,13 @@ android:title="@string/preferences_credit_cards_save_and_autofill_cards" /> + android:title="@string/preferences_credit_cards_sync_cards_across_devices" + app:allowDividerBelow="true" /> + android:layout="@layout/preference_credit_cards_add_credit_card" /> + diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardItemViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardItemViewHolderTest.kt new file mode 100644 index 000000000..546804102 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardItemViewHolderTest.kt @@ -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.settings.creditcards + +import android.view.LayoutInflater +import android.view.View +import io.mockk.mockk +import io.mockk.verify +import kotlinx.android.synthetic.main.credit_card_list_item.view.* +import mozilla.components.concept.storage.CreditCard +import mozilla.components.support.test.robolectric.testContext +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor +import org.mozilla.fenix.settings.creditcards.view.CreditCardItemViewHolder + +@RunWith(FenixRobolectricTestRunner::class) +class CreditCardItemViewHolderTest { + + private lateinit var view: View + private lateinit var interactor: CreditCardsManagementInteractor + + private val creditCard = CreditCard( + guid = "id", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + + @Before + fun setup() { + view = LayoutInflater.from(testContext).inflate(CreditCardItemViewHolder.LAYOUT_ID, null) + interactor = mockk(relaxed = true) + } + + @Test + fun `GIVEN a new credit card item on bind THEN set the card number and expiry date text`() { + CreditCardItemViewHolder(view, interactor).bind(creditCard) + + assertEquals(creditCard.cardNumber, view.credit_card_number.text) + assertEquals("0${creditCard.expiryMonth}/${creditCard.expiryYear}", view.expiry_date.text) + } + + @Test + fun `WHEN a credit item is clicked THEN interactor is called`() { + CreditCardItemViewHolder(view, interactor).bind(creditCard) + + view.performClick() + verify { interactor.onSelectCreditCard() } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsAdapterTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsAdapterTest.kt new file mode 100644 index 000000000..001701e97 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsAdapterTest.kt @@ -0,0 +1,69 @@ +/* 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.creditcards + +import mozilla.components.concept.storage.CreditCard +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.mozilla.fenix.settings.creditcards.view.CreditCardsAdapter + +class CreditCardsAdapterTest { + + @Test + fun testDiffCallback() { + val creditCard1 = CreditCard( + guid = "id", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + val creditCard2 = CreditCard( + guid = "id", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + + assertTrue( + CreditCardsAdapter.DiffCallback.areItemsTheSame(creditCard1, creditCard2) + ) + assertTrue( + CreditCardsAdapter.DiffCallback.areContentsTheSame(creditCard1, creditCard2) + ) + + val creditCard3 = CreditCard( + guid = "id3", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + + assertFalse( + CreditCardsAdapter.DiffCallback.areItemsTheSame(creditCard1, creditCard3) + ) + assertFalse( + CreditCardsAdapter.DiffCallback.areContentsTheSame(creditCard1, creditCard3) + ) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStoreTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStoreTest.kt new file mode 100644 index 000000000..0b7f24e47 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsFragmentStoreTest.kt @@ -0,0 +1,37 @@ +/* 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.creditcards + +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import mozilla.components.concept.storage.CreditCard +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +class CreditCardsFragmentStoreTest { + + private lateinit var creditCardsState: CreditCardsListState + private lateinit var creditCardsStore: CreditCardsFragmentStore + + @Before + fun setup() { + creditCardsState = CreditCardsListState(creditCards = emptyList()) + creditCardsStore = CreditCardsFragmentStore(creditCardsState) + } + + @Test + fun testUpdateCreditCards() = runBlocking { + assertTrue(creditCardsStore.state.isLoading) + + val creditCards: List = listOf(mockk(), mockk()) + creditCardsStore.dispatch(CreditCardsAction.UpdateCreditCards(creditCards)).join() + + assertEquals(creditCards, creditCardsStore.state.creditCards) + assertFalse(creditCardsStore.state.isLoading) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementViewTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementViewTest.kt new file mode 100644 index 000000000..5034010b8 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementViewTest.kt @@ -0,0 +1,56 @@ +/* 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.creditcards + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.view.isVisible +import io.mockk.mockk +import kotlinx.android.synthetic.main.component_credit_cards.view.* +import mozilla.components.concept.storage.CreditCard +import mozilla.components.support.test.robolectric.testContext +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.R +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor +import org.mozilla.fenix.settings.creditcards.view.CreditCardsManagementView + +@RunWith(FenixRobolectricTestRunner::class) +class CreditCardsManagementViewTest { + + private lateinit var view: ViewGroup + private lateinit var interactor: CreditCardsManagementInteractor + private lateinit var creditCardsView: CreditCardsManagementView + + @Before + fun setup() { + view = LayoutInflater.from(testContext).inflate(CreditCardsManagementView.LAYOUT_ID, null) + .findViewById(R.id.credit_cards_wrapper) + interactor = mockk(relaxed = true) + + creditCardsView = CreditCardsManagementView(view, interactor) + } + + @Test + fun testUpdate() { + creditCardsView.update(CreditCardsListState(creditCards = emptyList())) + + assertTrue(view.progress_bar.isVisible) + assertFalse(view.credit_cards_list.isVisible) + + val creditCards: List = listOf(mockk(), mockk()) + creditCardsView.update(CreditCardsListState( + creditCards = creditCards, + isLoading = false + )) + + assertFalse(view.progress_bar.isVisible) + assertTrue(view.credit_cards_list.isVisible) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementControllerTest.kt new file mode 100644 index 000000000..c70a37a73 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementControllerTest.kt @@ -0,0 +1,41 @@ +/* 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.creditcards + +import androidx.navigation.NavController +import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import org.mozilla.fenix.settings.creditcards.controller.DefaultCreditCardsManagementController + +class DefaultCreditCardsManagementControllerTest { + + private val navController: NavController = mockk(relaxed = true) + + private lateinit var controller: DefaultCreditCardsManagementController + + @Before + fun setup() { + controller = spyk( + DefaultCreditCardsManagementController( + navController = navController + ) + ) + } + + @Test + fun handleCreditCardClicked() { + controller.handleCreditCardClicked() + + verify { + navController.navigate( + CreditCardsManagementFragmentDirections + .actionCreditCardsManagementFragmentToCreditCardEditorFragment() + ) + } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementInteractorTest.kt new file mode 100644 index 000000000..46173ad53 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardsManagementInteractorTest.kt @@ -0,0 +1,30 @@ +/* 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.creditcards + +import io.mockk.mockk +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import org.mozilla.fenix.settings.creditcards.controller.CreditCardsManagementController +import org.mozilla.fenix.settings.creditcards.interactor.DefaultCreditCardsManagementInteractor + +class DefaultCreditCardsManagementInteractorTest { + + private val controller: CreditCardsManagementController = mockk(relaxed = true) + + private lateinit var interactor: DefaultCreditCardsManagementInteractor + + @Before + fun setup() { + interactor = DefaultCreditCardsManagementInteractor(controller) + } + + @Test + fun onSelectCreditCard() { + interactor.onSelectCreditCard() + verify { controller.handleCreditCardClicked() } + } +}