SyncedTabsControllerTest.kt 4.81 KB
Newer Older
1
2
3
4
package org.mozilla.fenix.tabtray

import android.view.LayoutInflater
import android.view.View
5
6
7
8
9
10
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.recyclerview.widget.ConcatAdapter
import io.mockk.Called
import io.mockk.every
11
import io.mockk.mockk
12
import io.mockk.verify
13
import kotlinx.coroutines.ExperimentalCoroutinesApi
14
import kotlinx.coroutines.test.TestCoroutineDispatcher
15
16
17
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType
18
import mozilla.components.support.test.ext.joinBlocking
19
import mozilla.components.support.test.robolectric.testContext
20
import mozilla.components.support.test.rule.MainCoroutineRule
21
import org.junit.After
22
23
import org.junit.Assert.assertEquals
import org.junit.Before
24
import org.junit.Rule
25
26
27
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.R
28
import org.mozilla.fenix.components.metrics.MetricController
29
30
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.sync.SyncedTabsViewHolder
31
32
33
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentAction.EnterMultiSelectMode
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentAction.ExitMultiSelectMode
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode
34
35
36
37
38

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

39
40
41
42
    private val testDispatcher = TestCoroutineDispatcher()
    @get:Rule
    val coroutinesTestRule = MainCoroutineRule(testDispatcher)

43
44
    private lateinit var view: View
    private lateinit var controller: SyncedTabsController
45
46
47
48
    private lateinit var lifecycleOwner: LifecycleOwner
    private lateinit var lifecycle: LifecycleRegistry
    private lateinit var concatAdapter: ConcatAdapter
    private lateinit var store: TabTrayDialogFragmentStore
49
50
51

    @Before
    fun setup() = runBlockingTest {
52
53
54
55
56
57
        lifecycleOwner = mockk()
        lifecycle = LifecycleRegistry(lifecycleOwner)
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
        every { lifecycleOwner.lifecycle } returns lifecycle

        concatAdapter = mockk()
58
        every { concatAdapter.addAdapter(any()) } returns true
59
60
61
62
63
64
65
66
67
        every { concatAdapter.removeAdapter(any()) } returns true

        store = TabTrayDialogFragmentStore(
            initialState = TabTrayDialogFragmentState(
                mode = Mode.Normal,
                browserState = mockk(relaxed = true)
            )
        )

68
        view = LayoutInflater.from(testContext).inflate(R.layout.about_list_item, null)
69
        val metrics: MetricController = mockk()
70
        controller =
71
            SyncedTabsController(lifecycleOwner, view, store, concatAdapter, coroutineContext, metrics)
72
73
    }

74
75
76
77
78
    @After
    fun cleanUp() {
        testDispatcher.cleanupTestCoroutines()
    }

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    @Test
    fun `display synced tabs in reverse`() {
        val tabs = listOf(
            SyncedDeviceTabs(
                device = mockk(relaxed = true),
                tabs = listOf(
                    mockk(relaxed = true),
                    mockk(relaxed = true)
                )
            )
        )

        controller.displaySyncedTabs(tabs)

        val itemCount = controller.adapter.itemCount

        // title + device name + 2 tabs
        assertEquals(4, itemCount)
        assertEquals(
            SyncedTabsViewHolder.TitleViewHolder.LAYOUT_ID,
            controller.adapter.getItemViewType(itemCount - 1)
        )
        assertEquals(
            SyncedTabsViewHolder.DeviceViewHolder.LAYOUT_ID,
            controller.adapter.getItemViewType(itemCount - 2)
        )
        assertEquals(
            SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID,
            controller.adapter.getItemViewType(itemCount - 3)
        )
        assertEquals(
            SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID,
            controller.adapter.getItemViewType(itemCount - 4)
        )
    }

    @Test
    fun `show error when we go kaput`() {
        controller.onError(ErrorType.SYNC_NEEDS_REAUTHENTICATION)

        assertEquals(1, controller.adapter.itemCount)
        assertEquals(
            SyncedTabsViewHolder.ErrorViewHolder.LAYOUT_ID,
            controller.adapter.getItemViewType(0)
        )
    }
125
126
127
128
129
130
131
132

    @Test
    fun `do nothing on init, drop first event`() {
        verify { concatAdapter wasNot Called }
    }

    @Test
    fun `concatAdapter updated on mode changes`() = testDispatcher.runBlockingTest {
133
        store.dispatch(EnterMultiSelectMode).joinBlocking()
134
135
136
        verify { concatAdapter.removeAdapter(any()) }

        store.dispatch(ExitMultiSelectMode).joinBlocking()
137
        // When returning from Multiselect the adapter should be added at the end
138
        verify { concatAdapter.addAdapter(any()) }
139
    }
140
}