Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* 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
package mozilla.components.browser.state.action
import kotlin.test.assertNotNull
import mozilla.components.browser.state.reducer.BrowserStateReducer
import mozilla.components.browser.state.selector.normalTabs
import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createCustomTab
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.state.recover.RecoverableTab
import mozilla.components.browser.state.state.recover.TabState
import mozilla.components.support.test.mock
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
class TabListActionTest {
@Test
fun `AddTabAction - Adds provided SessionState`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
assertNull(state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab))
assertEquals(1, state.tabs.size)
assertEquals(tab.id, state.selectedTabId)
}
@Test
fun `AddTabAction - Add tab and update selection`() {
var state =
BrowserState(
tabs = listOf(existingTab),
selectedTabId = existingTab.id,
)
assertEquals(1, state.tabs.size)
assertEquals(existingTab.id, state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(newTab, select = true))
assertEquals(2, state.tabs.size)
assertEquals(newTab.id, state.selectedTabId)
}
@Test
fun `AddTabAction - Select first tab automatically`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
assertNull(existingTab.id, state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(newTab, select = false))
assertEquals(1, state.tabs.size)
assertEquals(newTab.id, state.selectedTabId)
}
@Test
fun `AddTabAction - Specify parent tab`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab3))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab4))
assertEquals(4, state.tabs.size)
assertNull(state.tabs[0].parentId)
assertNull(state.tabs[2].parentId)
assertEquals(tab1.id, state.tabs[1].parentId)
assertEquals(tab2.id, state.tabs[3].parentId)
}
@Test
fun `AddTabAction - Specify source`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
assertEquals(2, state.tabs.size)
assertEquals(SessionState.Source.Internal.None, state.tabs[0].source)
assertEquals(SessionState.Source.Internal.Menu, state.tabs[1].source)
}
@Test
fun `AddTabAction - Tabs with parent are added after (next to) parent`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(parent01))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child001))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(parent02))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child002))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child003))
assertEquals(parent01.id, state.tabs[0].id) // ├── parent 1
assertEquals(child002.id, state.tabs[1].id) // │ ├── child 2
assertEquals(child001.id, state.tabs[2].id) // │ └── child 1
assertEquals(tab1.id, state.tabs[3].id) // ├──tab 1
assertEquals(tab2.id, state.tabs[4].id) // ├──tab 2
assertEquals(parent02.id, state.tabs[5].id) // └── parent 2
assertEquals(child003.id, state.tabs[6].id) // └── child 3
}
@Test
fun `SelectTabAction - Selects SessionState by id`() {
var state =
BrowserState(
tabs =
listOf(
)
)
assertNull(state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.SelectTabAction("a"))
assertEquals("a", state.selectedTabId)
}
@Test
fun `RemoveTabAction - Removes SessionState`() {
var state =
BrowserState(
tabs =
listOf(
)
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("a"))
assertEquals(1, state.tabs.size)
}
@Test
fun `RemoveTabsAction - Removes SessionState`() {
var state =
BrowserState(
tabs =
listOf(
)
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabsAction(listOf("a", "b")))
assertEquals(1, state.tabs.size)
}
@Test
fun `RemoveTabAction - Noop for unknown id`() {
var state =
BrowserState(
tabs =
listOf(
)
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("c"))
assertEquals(2, state.tabs.size)
}
@Test
fun `RemoveTabAction - Selected tab id is set to null if selected and last tab is removed`() {
var state =
BrowserState(
selectedTabId = "a",
)
assertEquals("a", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("a"))
assertNull(state.selectedTabId)
}
@Test
fun `RemoveTabAction - Does not select custom tab`() {
var state =
BrowserState(
customTabs =
listOf(
createCustomTab(
id = "c",
source = SessionState.Source.External.CustomTab(mock()),
),
),
selectedTabId = "a",
)
assertEquals("a", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("a"))
assertNull(state.selectedTabId)
}
@Test
fun `RemoveTabAction - Will select next nearby tab after removing selected tab`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "c",
)
assertEquals("c", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("c"))
assertEquals("d", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("a"))
assertEquals("d", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("d"))
assertEquals("b", state.selectedTabId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("b"))
assertNull(state.selectedTabId)
}
@Test
fun `RemoveTabAction - Selects private tab after private tab was removed`() {
var state =
BrowserState(
tabs =
listOf(
),
customTabs =
listOf(
createCustomTab(
id = "b1",
source = SessionState.Source.External.CustomTab(mock()),
),
),
selectedTabId = "d",
)
// [a*, b, c, (d*), e*] -> [a*, b, c, (e*)]
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("d"))
assertEquals("e", state.selectedTabId)
// [a*, b, c, (e*)] -> [(a*), b, c]
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("e"))
assertEquals("a", state.selectedTabId)
}
@Test
fun `RemoveTabAction - Selects normal tab after normal tab was removed`() {
var state =
BrowserState(
tabs =
listOf(
),
customTabs =
listOf(
createCustomTab(
id = "b1",
source = SessionState.Source.External.CustomTab(mock()),
),
),
selectedTabId = "d",
)
// [a, b*, c*, (d), e] -> [a, b*, c* (e)]
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("d"))
assertEquals("e", state.selectedTabId)
// [a, b*, c*, (e)] -> [(a), b*, c*]
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("e"))
assertEquals("a", state.selectedTabId)
// After removing the last normal tab NO private tab should get selected
// [(a), b*, c*] -> [b*, c*]
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction("a"))
assertNull(state.selectedTabId)
}
@Test
fun `RemoveTabAction - Exclude excluded tab from selection`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "d",
)
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabAction(excludedFallbackTabIds = setOf("e"), tabId = "d"),
)
assertEquals("c", state.selectedTabId)
}
@Test
fun `RemoveTabsAction - Exclude excluded tabs from selection`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "d",
)
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabsAction(excludedFallbackTabIds = setOf("c", "e"), tabIds = listOf("d", "b")),
)
assertEquals("a", state.selectedTabId)
}
@Test
fun `GIVEN last normal tab WHEN removed THEN no new tab is selected`() {
val normalTab = createTab("normal", private = false)
val privateTab = createTab("private", private = true)
val initialState = BrowserState(tabs = listOf(normalTab, privateTab), selectedTabId = normalTab.id)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveTabAction(normalTab.id))
assertNull(state.selectedTabId)
assertEquals(1, state.tabs.size)
}
@Test
fun `GIVEN last private tab WHEN removed THEN no new tab is selected`() {
val normalTab = createTab("normal", private = false)
val privateTab = createTab("private", private = true)
val initialState = BrowserState(tabs = listOf(normalTab, privateTab), selectedTabId = privateTab.id)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveTabAction(privateTab.id))
assertNull(state.selectedTabId)
assertEquals(1, state.tabs.size)
}
@Test
fun `GIVEN normal tabs and one private tab WHEN all normal tabs are removed THEN no new tab is selected`() {
val tabs = List(5) { createTab("$it", private = false) } + createTab("private", private = true)
val initialState = BrowserState(tabs = tabs, selectedTabId = tabs.first().id)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllNormalTabsAction)
assertNull(state.selectedTabId)
assertEquals(1, state.tabs.size)
}
@Test
fun `GIVEN one normal tab and private tabs WHEN all private tabs are removed THEN no new tab is selected`() {
val tabs = List(5) { createTab("$it", private = true) } + createTab("normal", private = false)
val initialState = BrowserState(tabs = tabs, selectedTabId = tabs.first().id)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllPrivateTabsAction)
assertNull(state.selectedTabId)
assertEquals(1, state.tabs.size)
}
@Test
fun `RemoveTabAction - Parent will be selected if child is removed and flag is set to true (default)`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(parent))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child))
state = BrowserStateReducer.reduce(state, TabListAction.SelectTabAction(child.id))
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabAction(child.id, selectParentIfExists = true),
)
assertEquals(parent.id, state.selectedTabId)
}
@Test
fun `RemoveTabAction - Parent will not be selected if child is removed and flag is set to false`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(parent))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child2))
state = BrowserStateReducer.reduce(state, TabListAction.SelectTabAction(child1.id))
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabAction(child1.id, selectParentIfExists = false),
)
assertEquals(tab1.id, state.selectedTabId)
}
@Test
fun `RemoveTabAction - Providing selectParentIfExists when removing tab without parent has no effect`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab3))
state = BrowserStateReducer.reduce(state, TabListAction.SelectTabAction(tab3.id))
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabAction(tab3.id, selectParentIfExists = true),
)
assertEquals(tab2.id, state.selectedTabId)
}
@Test
fun `RemoveTabAction - Children are updated when parent is removed`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab0))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab1))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab2))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(tab3))
// tab0 <- tab1 <- tab2 <- tab3
assertEquals(tab0.id, state.tabs[0].id)
assertEquals(tab1.id, state.tabs[1].id)
assertEquals(tab2.id, state.tabs[2].id)
assertEquals(tab3.id, state.tabs[3].id)
assertNull(state.tabs[0].parentId)
assertEquals(tab0.id, state.tabs[1].parentId)
assertEquals(tab1.id, state.tabs[2].parentId)
assertEquals(tab2.id, state.tabs[3].parentId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction(tab2.id))
// tab0 <- tab1 <- tab3
assertEquals(tab0.id, state.tabs[0].id)
assertEquals(tab1.id, state.tabs[1].id)
assertEquals(tab3.id, state.tabs[2].id)
assertNull(state.tabs[0].parentId)
assertEquals(tab0.id, state.tabs[1].parentId)
assertEquals(tab1.id, state.tabs[2].parentId)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveTabAction(tab0.id))
// tab1 <- tab3
assertEquals(tab1.id, state.tabs[0].id)
assertEquals(tab3.id, state.tabs[1].id)
assertNull(state.tabs[0].parentId)
assertEquals(tab1.id, state.tabs[1].parentId)
}
@Test
fun `RestoreAction - Adds restored tabs and updates selected tab`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
state =
BrowserStateReducer.reduce(
state,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
state =
TabState(
id = "a",
private = false,
),
),
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = "d",
restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING,
),
)
assertEquals(4, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
assertEquals("d", state.tabs[3].id)
assertEquals("d", state.selectedTabId)
}
@Test
fun `RestoreAction - Adds restored tabs to the beginning of existing tabs without updating selection`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "a",
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = "d",
restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING,
),
)
assertEquals(4, state.tabs.size)
assertEquals("c", state.tabs[0].id)
assertEquals("d", state.tabs[1].id)
assertEquals("a", state.tabs[2].id)
assertEquals("b", state.tabs[3].id)
assertEquals("a", state.selectedTabId)
}
@Test
fun `RestoreAction - Adds restored tabs to the end of existing tabs without updating selection`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "a",
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = "d",
restoreLocation = TabListAction.RestoreAction.RestoreLocation.END,
),
)
assertEquals(4, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
assertEquals("d", state.tabs[3].id)
assertEquals("a", state.selectedTabId)
}
@Test
fun `RestoreAction - Adds restored tabs to beginning of existing tabs with updating selection`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = "d",
restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING,
),
)
assertEquals(4, state.tabs.size)
assertEquals("c", state.tabs[0].id)
assertEquals("d", state.tabs[1].id)
assertEquals("a", state.tabs[2].id)
assertEquals("b", state.tabs[3].id)
assertEquals("d", state.selectedTabId)
}
@Test
fun `RestoreAction - Adds restored tabs to end of existing tabs with updating selection`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = "d",
restoreLocation = TabListAction.RestoreAction.RestoreLocation.END,
),
)
assertEquals(4, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
assertEquals("d", state.tabs[3].id)
assertEquals("d", state.selectedTabId)
}
@Test
fun `RestoreAction - Does not update selection if none was provided`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.BEGINNING,
),
)
assertEquals(4, state.tabs.size)
assertEquals("c", state.tabs[0].id)
assertEquals("d", state.tabs[1].id)
assertEquals("a", state.tabs[2].id)
assertEquals("b", state.tabs[3].id)
assertNull(state.selectedTabId)
}
@Test
fun `RestoreAction - Add tab back to correct location (beginning)`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
)
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(3, state.tabs.size)
assertEquals("c", state.tabs[0].id)
assertEquals("a", state.tabs[1].id)
assertEquals("b", state.tabs[2].id)
}
@Test
fun `RestoreAction - Add tab back to correct location (middle)`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
)
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(3, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("c", state.tabs[1].id)
assertEquals("b", state.tabs[2].id)
}
@Test
fun `RestoreAction - Add tab back to correct location (end)`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
)
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(3, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
}
@Test
fun `RestoreAction - Add tab back to correct location with index beyond size of total tabs`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
)
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(3, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
}
@Test
fun `RestoreAction - Add tabs back to correct locations`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(4, state.tabs.size)
assertEquals("d", state.tabs[0].id)
assertEquals("a", state.tabs[1].id)
assertEquals("b", state.tabs[2].id)
assertEquals("c", state.tabs[3].id)
}
@Test
fun `RestoreAction - Add tabs with matching indices back to correct locations`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(4, state.tabs.size)
assertEquals("d", state.tabs[0].id)
assertEquals("c", state.tabs[1].id)
assertEquals("a", state.tabs[2].id)
assertEquals("b", state.tabs[3].id)
}
@Test
fun `RestoreAction - Add tabs with a -1 removal index`() {
val initialState =
BrowserState(
tabs =
listOf(
)
)
assertEquals(2, initialState.tabs.size)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.RestoreAction(
tabs =
listOf(
RecoverableTab(
engineSessionState = null,
),
RecoverableTab(
engineSessionState = null,
),
),
selectedTabId = null,
restoreLocation = TabListAction.RestoreAction.RestoreLocation.AT_INDEX,
),
)
assertEquals(4, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("b", state.tabs[1].id)
assertEquals("c", state.tabs[2].id)
assertEquals("d", state.tabs[3].id)
}
@Test
fun `RemoveAllTabsAction - Removes both private and non-private tabs (but not custom tabs)`() {
var state =
BrowserState(
tabs =
listOf(
),
customTabs =
listOf(
createCustomTab(
id = "a2",
source = SessionState.Source.External.CustomTab(mock()),
),
),
selectedTabId = "a",
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveAllTabsAction())
assertTrue(state.tabs.isEmpty())
assertNull(state.selectedTabId)
assertEquals(2, state.customTabs.size)
assertEquals("a2", state.customTabs.last().id)
}
@Test
fun `RemoveAllPrivateTabsAction - Removes only private tabs`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "a",
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveAllPrivateTabsAction)
assertEquals(1, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals("a", state.selectedTabId)
assertEquals(1, state.customTabs.size)
assertEquals("a1", state.customTabs.last().id)
}
@Test
fun `RemoveAllPrivateTabsAction - Updates selection if affected`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "b",
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveAllPrivateTabsAction)
assertEquals(1, state.tabs.size)
assertEquals("a", state.tabs[0].id)
assertEquals(null, state.selectedTabId)
assertEquals(1, state.customTabs.size)
assertEquals("a1", state.customTabs.last().id)
}
@Test
fun `RemoveAllNormalTabsAction - Removes only normal (non-private) tabs`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "b",
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveAllNormalTabsAction)
assertEquals(1, state.tabs.size)
assertEquals("b", state.tabs[0].id)
assertEquals("b", state.selectedTabId)
assertEquals(1, state.customTabs.size)
assertEquals("a1", state.customTabs.last().id)
}
@Test
fun `RemoveAllNormalTabsAction - Updates selection if affected`() {
var state =
BrowserState(
tabs =
listOf(
),
selectedTabId = "a",
)
state = BrowserStateReducer.reduce(state, TabListAction.RemoveAllNormalTabsAction)
assertEquals(1, state.tabs.size)
assertEquals("b", state.tabs[0].id)
// After removing the last normal tab NO private tab should get selected
assertNull(state.selectedTabId)
assertEquals(1, state.customTabs.size)
assertEquals("a1", state.customTabs.last().id)
}
@Test
fun `AddMultipleTabsAction - Adds multiple tabs and updates selection`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
assertNull(state.selectedTabId)
state =
BrowserStateReducer.reduce(
state,
TabListAction.AddMultipleTabsAction(
tabs =
listOf(
)
),
)
assertEquals(2, state.tabs.size)
assertNotNull(state.selectedTabId)
assertEquals("a", state.selectedTabId)
}
@Test
fun `AddMultipleTabsAction - Adds multiple tabs and does not update selection if one exists already`() {
val initialState =
BrowserState(
selectedTabId = "z",
)
assertEquals(1, initialState.tabs.size)
assertEquals("z", initialState.selectedTabId)
val state =
BrowserStateReducer.reduce(
initialState,
TabListAction.AddMultipleTabsAction(
tabs =
listOf(
)
),
)
assertEquals(3, state.tabs.size)
assertEquals("z", state.selectedTabId)
}
@Test
fun `AddMultipleTabsAction - Non private tab will be selected`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
assertNull(state.selectedTabId)
state =
BrowserStateReducer.reduce(
state,
TabListAction.AddMultipleTabsAction(
tabs =
listOf(
)
),
)
assertEquals(4, state.tabs.size)
assertNotNull(state.selectedTabId)
assertEquals("c", state.selectedTabId)
}
@Test
fun `AddMultipleTabsAction - No tab will be selected if only private tabs are added`() {
var state = BrowserState()
assertEquals(0, state.tabs.size)
assertNull(state.selectedTabId)
state =
BrowserStateReducer.reduce(
state,
TabListAction.AddMultipleTabsAction(
tabs =
listOf(
)
),
)
assertEquals(3, state.tabs.size)
assertNull(state.selectedTabId)
}
@Test
fun `RemoveAllNormalTabsAction with private tab selected`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "d",
)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllNormalTabsAction)
assertEquals(0, state.normalTabs.size)
assertEquals(2, state.privateTabs.size)
assertEquals("d", state.selectedTabId)
}
@Test
fun `RemoveAllNormalTabsAction with normal tab selected`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "b",
)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllNormalTabsAction)
assertEquals(0, state.normalTabs.size)
assertEquals(2, state.privateTabs.size)
assertNull(state.selectedTabId)
}
@Test
fun `RemoveAllPrivateTabsAction with private tab selected`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "d",
)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllPrivateTabsAction)
assertEquals(2, state.normalTabs.size)
assertEquals(0, state.privateTabs.size)
assertEquals(null, state.selectedTabId)
}
@Test
fun `RemoveAllPrivateTabsAction with private tab selected and no normal tabs`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "b",
)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllPrivateTabsAction)
assertEquals(0, state.normalTabs.size)
assertEquals(0, state.privateTabs.size)
assertNull(state.selectedTabId)
}
@Test
fun `RemoveAllPrivateTabsAction with normal tab selected`() {
val initialState =
BrowserState(
tabs =
listOf(
),
selectedTabId = "b",
)
val state = BrowserStateReducer.reduce(initialState, TabListAction.RemoveAllPrivateTabsAction)
assertEquals(2, state.normalTabs.size)
assertEquals(0, state.privateTabs.size)
assertEquals("b", state.selectedTabId)
}
private fun assertSameTabs(a: BrowserState, b: List<TabSessionState>, str: String? = null) {
val aMap = a.tabs.map { "<" + it.id + "," + it.content.url + ">\n" }
val bMap = b.map { "<" + it.id + "," + it.content.url + ">\n" }
assertEquals(str, aMap.toString(), bMap.toString())
}
private fun moveTabsAction(
state: BrowserState,
tabIds: List<String>,
targetTabId: String,
placeAfter: Boolean,
): BrowserState {
return BrowserStateReducer.reduce(
state,
TabListAction.MoveTabsAction(
tabIds,
targetTabId,
placeAfter,
),
)
}
@Test
fun `MoveTabsAction - Tabs move as expected`() {
val tabList =
listOf(
)
val initialState =
BrowserState(
tabs = tabList,
selectedTabId = "a",
)
var state: BrowserState = moveTabsAction(initialState, listOf("a"), "a", false)
assertSameTabs(state, tabList, "a to a-")
state = moveTabsAction(initialState, listOf("a"), "a", true)
assertSameTabs(state, tabList, "a to a+")
state = moveTabsAction(initialState, listOf("a"), "b", false)
assertSameTabs(state, tabList, "a to b-")
state = moveTabsAction(initialState, listOf("a", "b"), "a", false)
assertSameTabs(state, tabList, "a,b to a-")
state = moveTabsAction(initialState, listOf("a", "b"), "a", true)
assertSameTabs(state, tabList, "a,b to a+")
state = moveTabsAction(initialState, listOf("a", "b"), "b", false)
assertSameTabs(state, tabList, "a,b to b-")
state = moveTabsAction(initialState, listOf("a", "b"), "b", true)
assertSameTabs(state, tabList, "a,b to b+")
state = moveTabsAction(initialState, listOf("a", "b"), "c", false)
assertSameTabs(state, tabList, "a,b to c-")
state = moveTabsAction(initialState, listOf("c", "d"), "c", false)
assertSameTabs(state, tabList, "c,d to c-")
state = moveTabsAction(initialState, listOf("c", "d"), "d", true)
assertSameTabs(state, tabList, "c,d to d+")
val movedTabList =
listOf(
)
state = moveTabsAction(initialState, listOf("a"), "d", false)
assertSameTabs(state, movedTabList, "a to d-")
state = moveTabsAction(initialState, listOf("b", "c"), "a", true)
assertSameTabs(state, tabList, "b,c to a+")
state = moveTabsAction(initialState, listOf("a", "d"), "c", true)
assertSameTabs(state, movedTabList, "a,d to c+")
state = moveTabsAction(initialState, listOf("b", "c"), "d", false)
assertSameTabs(state, tabList, "b,c to d-")
assertEquals("a", state.selectedTabId)
}
@Test
fun `MoveTabsAction - Complex moves work`() {
val tabList =
listOf(
)
val initialState =
BrowserState(
tabs = tabList,
selectedTabId = "a",
)
var state = moveTabsAction(initialState, listOf("a", "b", "c", "d", "e", "f"), "a", false)
assertSameTabs(state, tabList, "all to a-")
val movedTabList =
listOf(
)
state = moveTabsAction(initialState, listOf("b", "e"), "d", false)
assertSameTabs(state, movedTabList, "b,e to d-")
state = moveTabsAction(initialState, listOf("c", "d"), "b", true)
assertSameTabs(state, tabList, "c,d to b+")
}
@Test
fun `WHEN an unselected child tab is closed THEN the tab that is selected remains selected`() {
var state = BrowserState()
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(parent))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(nonChildTab))
state = BrowserStateReducer.reduce(state, TabListAction.AddTabAction(child))
state = BrowserStateReducer.reduce(state, TabListAction.SelectTabAction(nonChildTab.id))
state =
BrowserStateReducer.reduce(
state,
TabListAction.RemoveTabAction(child.id, selectParentIfExists = true),
)
assertEquals(nonChildTab.id, state.selectedTabId)
assertEquals(nonChildTab.content.url, state.selectedTab?.content?.url)
}
}