For #18268, #18269 - [Saved cards] Display a list of Saved cards fetched from the credit card storage (#18808)

upstream-sync
Gabriel Luong 3 years ago committed by GitHub
parent 15fc01c7f9
commit 37b6079d83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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<CreditCardsListState, CreditCardsAction>(
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<CreditCard>,
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<CreditCard>) : 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
)
}
}
}

@ -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))
}
}
}
}

@ -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)
}
}

@ -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()
)
}
}

@ -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()
}
}

@ -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"
}
}

@ -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<CreditCard, CreditCardItemViewHolder>(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<CreditCard>() {
override fun areItemsTheSame(oldItem: CreditCard, newItem: CreditCard) =
oldItem.guid == newItem.guid
override fun areContentsTheSame(oldItem: CreditCard, newItem: CreditCard) =
oldItem == newItem
}
}

@ -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
}
}

@ -0,0 +1,30 @@
<?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/. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/credit_cards_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:indeterminate="true"
android:layout_width="match_parent"
android:layout_height="8dp"
android:translationY="-3dp"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/credit_cards_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:listitem="@layout/credit_card_list_item" />
</FrameLayout>

@ -0,0 +1,45 @@
<?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.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeight">
<TextView
android:id="@+id/credit_card_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/saved_logins_item_margin_start"
android:layout_marginEnd="@dimen/saved_logins_item_margin_end"
android:ellipsize="middle"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?primaryText"
app:layout_constraintBottom_toTopOf="@id/expiry_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="mozilla.org" />
<TextView
android:id="@+id/expiry_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/credit_cards_saved_cards_item_margin_start"
android:layout_marginEnd="@dimen/credit_cards_saved_cards_item_margin_end"
android:ellipsize="middle"
android:singleLine="true"
android:textColor="?secondaryText"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/credit_card_number"
app:layout_constraintVertical_chainStyle="packed"
tools:text="02/2022" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,11 @@
<?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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/saved_cards_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="org.mozilla.fenix.settings.creditcards.CreditCardsManagementFragment" />

@ -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" />
<action
android:id="@+id/action_global_recently_closed"
@ -117,7 +117,7 @@
android:id="@+id/action_global_tabTrayDialogFragment"
app:destination="@id/tabTrayDialogFragment"
app:popUpTo="@id/tabTrayDialogFragment"
app:popUpToInclusive="true"/>
app:popUpToInclusive="true" />
<action
android:id="@+id/action_global_tabsTrayFragment"
app:destination="@id/tabsTrayFragment"
@ -790,7 +790,7 @@
app:argType="string" />
<argument
android:name="permissionHighlights"
app:argType="mozilla.components.browser.state.state.content.PermissionHighlightsState"/>
app:argType="mozilla.components.browser.state.state.content.PermissionHighlightsState" />
</dialog>
<fragment
android:id="@+id/accountProblemFragment"
@ -1051,10 +1051,29 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_creditCardsSettingFragment_to_creditCardsManagementFragment"
app:destination="@id/creditCardsManagementFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/creditCardEditorFragment"
android:name="org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment"
android:label="@string/credit_cards_add_card" />
<fragment
android:id="@+id/creditCardsManagementFragment"
android:name="org.mozilla.fenix.settings.creditcards.CreditCardsManagementFragment"
android:label="@string/credit_cards_saved_cards">
<action
android:id="@+id/action_creditCardsManagementFragment_to_creditCardEditorFragment"
app:destination="@id/creditCardEditorFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
</navigation>
</navigation>

@ -221,6 +221,8 @@
This should be the same value as radio_button_padding_horizontal. -->
<dimen name="credit_cards_add_credit_card_text_horizontal_margin">16dp</dimen>
<dimen name="credit_cards_add_credit_card_text_size">16sp</dimen>
<dimen name="credit_cards_saved_cards_item_margin_start">16dp</dimen>
<dimen name="credit_cards_saved_cards_item_margin_end">48dp</dimen>
<!-- a11y -->
<dimen name="accessibility_min_height">48dp</dimen>

@ -179,6 +179,8 @@
<string name="pref_key_credit_cards_sync_cards_across_devices" translatable="false">pref_key_credit_cards_sync_cards_across_devices</string>
<!-- Key for the "Add credit card" preference in the "Credit cards" fragment -->
<string name="pref_key_credit_cards_add_credit_card" translatable="false">pref_key_credit_cards_add_credit_card</string>
<!-- Key for the "Manage saved cards" preference in the "Credit cards" fragment -->
<string name="pref_key_credit_cards_manage_saved_cards" translatable="false">pref_key_credit_cards_manage_saved_cards</string>
<!-- Privacy Settings -->
<string name="pref_key_open_links_in_a_private_tab" translatable="false">pref_key_open_links_in_a_private_tab</string>

@ -1524,6 +1524,8 @@
<string name="preferences_credit_cards_sync_cards_across_devices">Sync cards across devices</string>
<!-- Preference option for adding a credit card -->
<string name="preferences_credit_cards_add_credit_card">Add credit card</string>
<!-- Preference option for managing saved credit cards -->
<string name="preferences_credit_cards_manage_saved_cards">Manage saved cards</string>
<!-- Title of the "Add card" screen -->
<string name="credit_cards_add_card">Add card</string>
<!-- The header for the card number of a credit card -->
@ -1542,6 +1544,8 @@
<string name="credit_cards_save_button">Save</string>
<!-- The text for the "Cancel" button for cancelling adding or updating a credit card -->
<string name="credit_cards_cancel_button">Cancel</string>
<!-- Title of the "Saved cards" screen -->
<string name="credit_cards_saved_cards">Saved cards</string>
<!-- Title of the Add search engine screen -->
<string name="search_engine_add_custom_search_engine_title">Add search engine</string>

@ -11,10 +11,13 @@
android:title="@string/preferences_credit_cards_save_and_autofill_cards" />
<Preference
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" />
<Preference
android:key="@string/pref_key_credit_cards_add_credit_card"
android:title="@string/preferences_credit_cards_add_credit_card"
android:layout="@layout/preference_credit_cards_add_credit_card"
app:allowDividerAbove="true" />
android:layout="@layout/preference_credit_cards_add_credit_card" />
<Preference
android:key="@string/pref_key_credit_cards_manage_saved_cards"
android:title="@string/preferences_credit_cards_manage_saved_cards" />
</PreferenceScreen>

@ -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() }
}
}

@ -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)
)
}
}

@ -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<CreditCard> = listOf(mockk(), mockk())
creditCardsStore.dispatch(CreditCardsAction.UpdateCreditCards(creditCards)).join()
assertEquals(creditCards, creditCardsStore.state.creditCards)
assertFalse(creditCardsStore.state.isLoading)
}
}

@ -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<CreditCard> = listOf(mockk(), mockk())
creditCardsView.update(CreditCardsListState(
creditCards = creditCards,
isLoading = false
))
assertFalse(view.progress_bar.isVisible)
assertTrue(view.credit_cards_list.isVisible)
}
}

@ -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()
)
}
}
}

@ -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() }
}
}
Loading…
Cancel
Save