Add tests for login exceptions (#12681)
parent
aa31eb0fa5
commit
67fda80453
|
@ -14,29 +14,22 @@ import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsDeleteButton
|
||||||
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsHeaderViewHolder
|
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsHeaderViewHolder
|
||||||
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsListItemViewHolder
|
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsListItemViewHolder
|
||||||
|
|
||||||
sealed class AdapterItem {
|
|
||||||
object DeleteButton : AdapterItem()
|
|
||||||
object Header : AdapterItem()
|
|
||||||
data class Item(val item: LoginException) : AdapterItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter for a list of sites that are exempted from saving logins,
|
* Adapter for a list of sites that are exempted from saving logins,
|
||||||
* along with controls to remove the exception.
|
* along with controls to remove the exception.
|
||||||
*/
|
*/
|
||||||
class LoginExceptionsAdapter(
|
class LoginExceptionsAdapter(
|
||||||
private val interactor: LoginExceptionsInteractor
|
private val interactor: LoginExceptionsInteractor
|
||||||
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(DiffCallback) {
|
) : ListAdapter<LoginExceptionsAdapter.AdapterItem, RecyclerView.ViewHolder>(DiffCallback) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the list of items that are displayed.
|
* Change the list of items that are displayed.
|
||||||
* Header and footer items are added to the list as well.
|
* Header and footer items are added to the list as well.
|
||||||
*/
|
*/
|
||||||
fun updateData(exceptions: List<LoginException>) {
|
fun updateData(exceptions: List<LoginException>) {
|
||||||
val adapterItems: List<AdapterItem> =
|
val adapterItems: List<AdapterItem> = listOf(AdapterItem.Header) +
|
||||||
listOf(AdapterItem.Header) + exceptions.map { AdapterItem.Item(it) } + listOf(
|
exceptions.map { AdapterItem.Item(it) } +
|
||||||
AdapterItem.DeleteButton
|
listOf(AdapterItem.DeleteButton)
|
||||||
)
|
|
||||||
submitList(adapterItems)
|
submitList(adapterItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +63,18 @@ class LoginExceptionsAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
|
sealed class AdapterItem {
|
||||||
|
object DeleteButton : AdapterItem()
|
||||||
|
object Header : AdapterItem()
|
||||||
|
data class Item(val item: LoginException) : AdapterItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object DiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
|
||||||
override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
|
override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
|
||||||
areContentsTheSame(oldItem, newItem)
|
when (oldItem) {
|
||||||
|
AdapterItem.DeleteButton, AdapterItem.Header -> oldItem === newItem
|
||||||
|
is AdapterItem.Item -> newItem is AdapterItem.Item && oldItem.item.id == newItem.item.id
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("DiffUtilEquals")
|
@Suppress("DiffUtilEquals")
|
||||||
override fun areContentsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
|
override fun areContentsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
|
||||||
|
|
|
@ -9,9 +9,9 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.observe
|
||||||
import kotlinx.android.synthetic.main.fragment_exceptions.view.*
|
import kotlinx.android.synthetic.main.fragment_exceptions.view.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
@ -57,18 +57,15 @@ class LoginExceptionsFragment : Fragment() {
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeToLoginExceptions(): Observer<List<LoginException>> {
|
private fun subscribeToLoginExceptions() {
|
||||||
return Observer<List<LoginException>> { exceptions ->
|
requireComponents.core.loginExceptionStorage.getLoginExceptions().asLiveData()
|
||||||
exceptionsStore.dispatch(ExceptionsFragmentAction.Change(exceptions))
|
.observe(viewLifecycleOwner) { exceptions ->
|
||||||
}.also { observer ->
|
exceptionsStore.dispatch(ExceptionsFragmentAction.Change(exceptions))
|
||||||
requireComponents.core.loginExceptionStorage.getLoginExceptions().asLiveData()
|
}
|
||||||
.observe(viewLifecycleOwner, observer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
consumeFrom(exceptionsStore) {
|
consumeFrom(exceptionsStore) {
|
||||||
exceptionsView.update(it)
|
exceptionsView.update(it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.widget.FrameLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.component_exceptions.view.*
|
import kotlinx.android.synthetic.main.component_exceptions.*
|
||||||
import mozilla.components.feature.logins.exceptions.LoginException
|
import mozilla.components.feature.logins.exceptions.LoginException
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
@ -34,29 +34,29 @@ interface ExceptionsViewInteractor {
|
||||||
* View that contains and configures the Exceptions List
|
* View that contains and configures the Exceptions List
|
||||||
*/
|
*/
|
||||||
class LoginExceptionsView(
|
class LoginExceptionsView(
|
||||||
override val containerView: ViewGroup,
|
container: ViewGroup,
|
||||||
val interactor: LoginExceptionsInteractor
|
val interactor: LoginExceptionsInteractor
|
||||||
) : LayoutContainer {
|
) : LayoutContainer {
|
||||||
|
|
||||||
val view: FrameLayout = LayoutInflater.from(containerView.context)
|
override val containerView: FrameLayout = LayoutInflater.from(container.context)
|
||||||
.inflate(R.layout.component_exceptions, containerView, true)
|
.inflate(R.layout.component_exceptions, container, true)
|
||||||
.findViewById(R.id.exceptions_wrapper)
|
.findViewById(R.id.exceptions_wrapper)
|
||||||
|
|
||||||
private val exceptionsAdapter = LoginExceptionsAdapter(interactor)
|
private val exceptionsAdapter = LoginExceptionsAdapter(interactor)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
view.exceptions_learn_more.isVisible = false
|
exceptions_learn_more.isVisible = false
|
||||||
view.exceptions_empty_message.text =
|
exceptions_empty_message.text =
|
||||||
view.context.getString(R.string.preferences_passwords_exceptions_description_empty)
|
containerView.context.getString(R.string.preferences_passwords_exceptions_description_empty)
|
||||||
view.exceptions_list.apply {
|
exceptions_list.apply {
|
||||||
adapter = exceptionsAdapter
|
adapter = exceptionsAdapter
|
||||||
layoutManager = LinearLayoutManager(containerView.context)
|
layoutManager = LinearLayoutManager(containerView.context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(state: ExceptionsFragmentState) {
|
fun update(state: ExceptionsFragmentState) {
|
||||||
view.exceptions_empty_view.isVisible = state.items.isEmpty()
|
exceptions_empty_view.isVisible = state.items.isEmpty()
|
||||||
view.exceptions_list.isVisible = state.items.isNotEmpty()
|
exceptions_list.isVisible = state.items.isNotEmpty()
|
||||||
exceptionsAdapter.updateData(state.items)
|
exceptionsAdapter.updateData(state.items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,13 @@ import org.mozilla.fenix.R
|
||||||
class LoginExceptionsHeaderViewHolder(
|
class LoginExceptionsHeaderViewHolder(
|
||||||
view: View
|
view: View
|
||||||
) : RecyclerView.ViewHolder(view) {
|
) : RecyclerView.ViewHolder(view) {
|
||||||
companion object {
|
|
||||||
const val LAYOUT_ID = R.layout.exceptions_description
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
view.exceptions_description.text =
|
view.exceptions_description.text =
|
||||||
view.context.getString(R.string.preferences_passwords_exceptions_description)
|
view.context.getString(R.string.preferences_passwords_exceptions_description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LAYOUT_ID = R.layout.exceptions_description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* 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.loginexceptions
|
||||||
|
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
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.loginexceptions.viewholders.LoginExceptionsDeleteButtonViewHolder
|
||||||
|
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsHeaderViewHolder
|
||||||
|
import org.mozilla.fenix.loginexceptions.viewholders.LoginExceptionsListItemViewHolder
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class LoginExceptionsAdapterTest {
|
||||||
|
|
||||||
|
private lateinit var interactor: LoginExceptionsInteractor
|
||||||
|
private lateinit var adapter: LoginExceptionsAdapter
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
interactor = mockk()
|
||||||
|
adapter = LoginExceptionsAdapter(interactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `creates correct view holder type`() {
|
||||||
|
val parent = LinearLayout(ContextThemeWrapper(testContext, R.style.NormalTheme))
|
||||||
|
adapter.updateData(listOf(mockk(), mockk()))
|
||||||
|
assertEquals(4, adapter.itemCount)
|
||||||
|
|
||||||
|
val holders = (0 until adapter.itemCount).asSequence()
|
||||||
|
.map { i -> adapter.getItemViewType(i) }
|
||||||
|
.map { viewType -> adapter.onCreateViewHolder(parent, viewType) }
|
||||||
|
.toList()
|
||||||
|
assertEquals(4, holders.size)
|
||||||
|
|
||||||
|
assertTrue(holders[0] is LoginExceptionsHeaderViewHolder)
|
||||||
|
assertTrue(holders[1] is LoginExceptionsListItemViewHolder)
|
||||||
|
assertTrue(holders[2] is LoginExceptionsListItemViewHolder)
|
||||||
|
assertTrue(holders[3] is LoginExceptionsDeleteButtonViewHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `headers and delete should check if the other object is the same`() {
|
||||||
|
assertTrue(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header
|
||||||
|
))
|
||||||
|
assertTrue(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton
|
||||||
|
))
|
||||||
|
assertFalse(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton
|
||||||
|
))
|
||||||
|
assertTrue(LoginExceptionsAdapter.DiffCallback.areContentsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header
|
||||||
|
))
|
||||||
|
assertTrue(LoginExceptionsAdapter.DiffCallback.areContentsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton
|
||||||
|
))
|
||||||
|
assertFalse(LoginExceptionsAdapter.DiffCallback.areContentsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `items with the same id should be marked as same`() {
|
||||||
|
assertTrue(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 12L
|
||||||
|
}),
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 12L
|
||||||
|
})
|
||||||
|
))
|
||||||
|
assertFalse(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 14L
|
||||||
|
}),
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 12L
|
||||||
|
})
|
||||||
|
))
|
||||||
|
assertFalse(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 14L
|
||||||
|
}),
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Header
|
||||||
|
))
|
||||||
|
assertFalse(LoginExceptionsAdapter.DiffCallback.areItemsTheSame(
|
||||||
|
LoginExceptionsAdapter.AdapterItem.DeleteButton,
|
||||||
|
LoginExceptionsAdapter.AdapterItem.Item(mockk {
|
||||||
|
every { id } returns 14L
|
||||||
|
})
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* 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.loginexceptions
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.android.synthetic.main.component_exceptions.*
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
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.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class LoginExceptionsViewTest {
|
||||||
|
|
||||||
|
private lateinit var parent: ViewGroup
|
||||||
|
private lateinit var interactor: LoginExceptionsInteractor
|
||||||
|
private lateinit var view: LoginExceptionsView
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
parent = FrameLayout(testContext)
|
||||||
|
interactor = mockk()
|
||||||
|
view = LoginExceptionsView(parent, interactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `sets empty message text`() {
|
||||||
|
assertEquals(
|
||||||
|
"Logins and passwords that are not saved will be shown here.",
|
||||||
|
view.exceptions_empty_message.text
|
||||||
|
)
|
||||||
|
assertTrue(view.exceptions_list.adapter is LoginExceptionsAdapter)
|
||||||
|
assertTrue(view.exceptions_list.layoutManager is LinearLayoutManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hide list when there are no items`() {
|
||||||
|
view.update(ExceptionsFragmentState(
|
||||||
|
items = emptyList()
|
||||||
|
))
|
||||||
|
|
||||||
|
assertTrue(view.exceptions_empty_view.isVisible)
|
||||||
|
assertFalse(view.exceptions_list.isVisible)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `shows list when there are items`() {
|
||||||
|
view.update(ExceptionsFragmentState(
|
||||||
|
items = listOf(mockk())
|
||||||
|
))
|
||||||
|
|
||||||
|
assertFalse(view.exceptions_empty_view.isVisible)
|
||||||
|
assertTrue(view.exceptions_list.isVisible)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* 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.loginexceptions.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.verify
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.loginexceptions.LoginExceptionsInteractor
|
||||||
|
|
||||||
|
class LoginExceptionsDeleteButtonViewHolderTest {
|
||||||
|
|
||||||
|
private lateinit var view: View
|
||||||
|
private lateinit var deleteButton: MaterialButton
|
||||||
|
private lateinit var interactor: LoginExceptionsInteractor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
deleteButton = mockk()
|
||||||
|
view = mockk {
|
||||||
|
every { findViewById<MaterialButton>(R.id.removeAllExceptions) } returns deleteButton
|
||||||
|
}
|
||||||
|
interactor = mockk()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `delete button calls interactor`() {
|
||||||
|
val slot = slot<View.OnClickListener>()
|
||||||
|
every { deleteButton.setOnClickListener(capture(slot)) } just Runs
|
||||||
|
LoginExceptionsDeleteButtonViewHolder(view, interactor)
|
||||||
|
|
||||||
|
every { interactor.onDeleteAll() } just Runs
|
||||||
|
slot.captured.onClick(mockk())
|
||||||
|
verify { interactor.onDeleteAll() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.loginexceptions.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class LoginExceptionsHeaderViewHolderTest {
|
||||||
|
|
||||||
|
private lateinit var view: View
|
||||||
|
private lateinit var description: TextView
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
description = mockk(relaxUnitFun = true)
|
||||||
|
view = mockk {
|
||||||
|
every { findViewById<TextView>(R.id.exceptions_description) } returns description
|
||||||
|
every {
|
||||||
|
context.getString(R.string.preferences_passwords_exceptions_description)
|
||||||
|
} returns "Logins and passwords will not be saved for these sites."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `sets description text`() {
|
||||||
|
LoginExceptionsHeaderViewHolder(view)
|
||||||
|
verify { description.text = "Logins and passwords will not be saved for these sites." }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* 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.loginexceptions.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.feature.logins.exceptions.LoginException
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.loginexceptions.LoginExceptionsInteractor
|
||||||
|
|
||||||
|
class LoginExceptionsListItemViewHolderTest {
|
||||||
|
|
||||||
|
private lateinit var view: View
|
||||||
|
private lateinit var url: TextView
|
||||||
|
private lateinit var deleteButton: ImageButton
|
||||||
|
private lateinit var interactor: LoginExceptionsInteractor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
url = mockk(relaxUnitFun = true)
|
||||||
|
deleteButton = mockk(relaxUnitFun = true)
|
||||||
|
view = mockk {
|
||||||
|
every { findViewById<TextView>(R.id.webAddressView) } returns url
|
||||||
|
every { findViewById<ImageButton>(R.id.delete_exception) } returns deleteButton
|
||||||
|
every { findViewById<ImageView>(R.id.favicon_image) } returns mockk()
|
||||||
|
}
|
||||||
|
interactor = mockk()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `sets url text`() {
|
||||||
|
LoginExceptionsListItemViewHolder(view, interactor).bind(mockk {
|
||||||
|
every { origin } returns "mozilla.org"
|
||||||
|
})
|
||||||
|
verify { url.text = "mozilla.org" }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `delete button calls interactor`() {
|
||||||
|
val slot = slot<View.OnClickListener>()
|
||||||
|
val loginException = mockk<LoginException> {
|
||||||
|
every { origin } returns "mozilla.org"
|
||||||
|
}
|
||||||
|
every { deleteButton.setOnClickListener(capture(slot)) } just Runs
|
||||||
|
LoginExceptionsListItemViewHolder(view, interactor).bind(loginException)
|
||||||
|
|
||||||
|
every { interactor.onDeleteOne(loginException) } just Runs
|
||||||
|
slot.captured.onClick(mockk())
|
||||||
|
verify { interactor.onDeleteOne(loginException) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue