Commit 9ae1aa6f authored by Tiger Oakes's avatar Tiger Oakes Committed by Emily Kager
Browse files

Add tests for exceptions

parent 236b9818
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -14,19 +14,13 @@ import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder

sealed class AdapterItem {
    object DeleteButton : AdapterItem()
    object Header : AdapterItem()
    data class Item(val item: TrackingProtectionException) : AdapterItem()
}

/**
 * Adapter for a list of sites that are exempted from Tracking Protection,
 * along with controls to remove the exception.
 */
class ExceptionsAdapter(
    private val interactor: ExceptionsInteractor
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(DiffCallback) {
) : ListAdapter<ExceptionsAdapter.AdapterItem, RecyclerView.ViewHolder>(DiffCallback) {

    /**
     * Change the list of items that are displayed.
@@ -67,6 +61,12 @@ class ExceptionsAdapter(
        }
    }

    sealed class AdapterItem {
        object DeleteButton : AdapterItem()
        object Header : AdapterItem()
        data class Item(val item: TrackingProtectionException) : AdapterItem()
    }

    private object DiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
        override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
            areContentsTheSame(oldItem, newItem)
+2 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import org.mozilla.fenix.settings.SupportUtils
 * along with controls to remove the exception.
 */
class ExceptionsFragment : Fragment() {

    private lateinit var exceptionsStore: ExceptionsFragmentStore
    private lateinit var exceptionsView: ExceptionsView
    private lateinit var exceptionsInteractor: ExceptionsInteractor
@@ -48,7 +49,7 @@ class ExceptionsFragment : Fragment() {
        exceptionsStore = StoreProvider.get(this) {
            ExceptionsFragmentStore(
                ExceptionsFragmentState(
                    items = listOf()
                    items = emptyList()
                )
            )
        }
@@ -61,7 +62,6 @@ class ExceptionsFragment : Fragment() {

    @ExperimentalCoroutinesApi
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        consumeFrom(exceptionsStore) {
            exceptionsView.update(it)
        }
+17 −16
Original line number Diff line number Diff line
@@ -4,16 +4,16 @@

package org.mozilla.fenix.exceptions

import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.text.toSpannable
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.component_exceptions.view.*
import kotlinx.android.synthetic.main.component_exceptions.*
import mozilla.components.concept.engine.content.blocking.TrackingProtectionException
import org.mozilla.fenix.R

@@ -42,35 +42,36 @@ interface ExceptionsViewInteractor {
 * View that contains and configures the Exceptions List
 */
class ExceptionsView(
    override val containerView: ViewGroup,
    val interactor: ExceptionsInteractor
    container: ViewGroup,
    interactor: ExceptionsInteractor
) : LayoutContainer {

    val view: FrameLayout = LayoutInflater.from(containerView.context)
        .inflate(R.layout.component_exceptions, containerView, true)
    override val containerView: FrameLayout = LayoutInflater.from(container.context)
        .inflate(R.layout.component_exceptions, container, true)
        .findViewById(R.id.exceptions_wrapper)

    private val exceptionsAdapter = ExceptionsAdapter(interactor)

    init {
        view.exceptions_list.apply {
        exceptions_list.apply {
            adapter = exceptionsAdapter
            layoutManager = LinearLayoutManager(containerView.context)
            layoutManager = LinearLayoutManager(container.context)
        }
        val learnMoreText = view.exceptions_learn_more.text.toString()
        val textWithLink = SpannableString(learnMoreText).apply {

        with(exceptions_learn_more) {
            val learnMoreText = text
            text = learnMoreText.toSpannable().apply {
                setSpan(UnderlineSpan(), 0, learnMoreText.length, 0)
            }
        with(view.exceptions_learn_more) {

            movementMethod = LinkMovementMethod.getInstance()
            text = textWithLink
            setOnClickListener { interactor.onLearnMore() }
        }
    }

    fun update(state: ExceptionsFragmentState) {
        view.exceptions_empty_view.isVisible = state.items.isEmpty()
        view.exceptions_list.isVisible = state.items.isNotEmpty()
        exceptions_empty_view.isVisible = state.items.isEmpty()
        exceptions_list.isVisible = state.items.isNotEmpty()
        exceptionsAdapter.updateData(state.items)
    }
}
+42 −0
Original line number Diff line number Diff line
/* 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.exceptions

import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner

@ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class)
class ExceptionsAdapterTest {

    private lateinit var interactor: ExceptionsInteractor
    private lateinit var adapter: ExceptionsAdapter

    @Before
    fun setup() {
        interactor = mockk()
        adapter = ExceptionsAdapter(interactor)
    }

    @Test
    fun `binds header and delete button with other adapter items`() = runBlockingTest {
        adapter.updateData(listOf(mockk(), mockk()))

        assertEquals(4, adapter.itemCount)
        assertEquals(ExceptionsHeaderViewHolder.LAYOUT_ID, adapter.getItemViewType(0))
        assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(1))
        assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(2))
        assertEquals(ExceptionsDeleteButtonViewHolder.LAYOUT_ID, adapter.getItemViewType(3))
    }
}
+82 −0
Original line number Diff line number Diff line
/* 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.exceptions

import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isVisible
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkConstructor
import io.mockk.unmockkConstructor
import io.mockk.verify
import kotlinx.android.synthetic.main.component_exceptions.*
import mozilla.components.concept.engine.content.blocking.TrackingProtectionException
import mozilla.components.support.test.robolectric.testContext
import org.junit.After
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 ExceptionsViewTest {

    private lateinit var container: ViewGroup
    private lateinit var interactor: ExceptionsInteractor
    private lateinit var exceptionsView: ExceptionsView

    @Before
    fun setup() {
        mockkConstructor(ExceptionsAdapter::class)
        container = FrameLayout(testContext)
        interactor = mockk()

        exceptionsView = ExceptionsView(container, interactor)
        every { anyConstructed<ExceptionsAdapter>().updateData(any()) } just Runs
    }

    @After
    fun teardown() {
        unmockkConstructor(ExceptionsAdapter::class)
    }

    @Test
    fun `binds exception text`() {
        assertTrue(exceptionsView.exceptions_learn_more.movementMethod is LinkMovementMethod)
        assertTrue(exceptionsView.exceptions_learn_more.text is Spannable)
        assertEquals("Learn more", exceptionsView.exceptions_learn_more.text.toString())

        every { interactor.onLearnMore() } just Runs
        exceptionsView.exceptions_learn_more.performClick()
        verify { interactor.onLearnMore() }
    }

    @Test
    fun `binds empty list to adapter`() {
        exceptionsView.update(ExceptionsFragmentState(emptyList()))

        assertTrue(exceptionsView.exceptions_empty_view.isVisible)
        assertFalse(exceptionsView.exceptions_list.isVisible)
        verify { anyConstructed<ExceptionsAdapter>().updateData(emptyList()) }
    }

    @Test
    fun `binds list with items to adapter`() {
        val items = listOf<TrackingProtectionException>(mockk(), mockk())
        exceptionsView.update(ExceptionsFragmentState(items))

        assertFalse(exceptionsView.exceptions_empty_view.isVisible)
        assertTrue(exceptionsView.exceptions_list.isVisible)
        verify { anyConstructed<ExceptionsAdapter>().updateData(items) }
    }
}
Loading