You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
9.5 KiB
Kotlin
229 lines
9.5 KiB
Kotlin
/* 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.library.history.state
|
|
|
|
import kotlinx.coroutines.runBlocking
|
|
import kotlinx.coroutines.test.advanceUntilIdle
|
|
import mozilla.components.browser.state.action.BrowserAction
|
|
import mozilla.components.browser.state.action.EngineAction
|
|
import mozilla.components.browser.state.action.HistoryMetadataAction
|
|
import mozilla.components.browser.state.action.RecentlyClosedAction
|
|
import mozilla.components.browser.state.state.BrowserState
|
|
import mozilla.components.browser.state.store.BrowserStore
|
|
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
|
import mozilla.components.support.test.ext.joinBlocking
|
|
import mozilla.components.support.test.libstate.ext.waitUntilIdle
|
|
import mozilla.components.support.test.middleware.CaptureActionsMiddleware
|
|
import mozilla.components.support.test.mock
|
|
import mozilla.components.support.test.rule.MainCoroutineRule
|
|
import mozilla.components.support.test.rule.runTestOnMain
|
|
import org.junit.Assert.assertEquals
|
|
import org.junit.Assert.assertFalse
|
|
import org.junit.Assert.assertTrue
|
|
import org.junit.Before
|
|
import org.junit.Ignore
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.mockito.Mockito.anyLong
|
|
import org.mockito.Mockito.verify
|
|
import org.mozilla.fenix.components.AppStore
|
|
import org.mozilla.fenix.components.appstate.AppAction
|
|
import org.mozilla.fenix.components.history.DefaultPagedHistoryProvider
|
|
import org.mozilla.fenix.library.history.History
|
|
import org.mozilla.fenix.library.history.HistoryFragmentAction
|
|
import org.mozilla.fenix.library.history.HistoryFragmentState
|
|
import org.mozilla.fenix.library.history.HistoryFragmentStore
|
|
import org.mozilla.fenix.library.history.HistoryItemTimeGroup
|
|
import org.mozilla.fenix.library.history.RemoveTimeFrame
|
|
import org.mozilla.fenix.library.history.toPendingDeletionHistory
|
|
|
|
class HistoryStorageMiddlewareTest {
|
|
@get:Rule
|
|
val coroutinesTestRule = MainCoroutineRule()
|
|
|
|
private val appStore = mock<AppStore>()
|
|
private lateinit var captureBrowserActions: CaptureActionsMiddleware<BrowserState, BrowserAction>
|
|
private lateinit var browserStore: BrowserStore
|
|
private val provider = mock<DefaultPagedHistoryProvider>()
|
|
private lateinit var storage: PlacesHistoryStorage
|
|
|
|
@Before
|
|
fun setup() {
|
|
storage = mock()
|
|
captureBrowserActions = CaptureActionsMiddleware()
|
|
browserStore = BrowserStore(middleware = listOf(captureBrowserActions))
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN items are deleted THEN action to add to pending deletion is dispatched and snackbar is shown`() = runTestOnMain {
|
|
var snackbarCalled = false
|
|
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = { _, _, _ -> snackbarCalled = true },
|
|
onTimeFrameDeleted = { },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
|
|
assertTrue(snackbarCalled)
|
|
verify(appStore).dispatch(AppAction.AddPendingDeletionSet(history.toPendingDeletionHistory()))
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN items are deleted THEN undo dispatches action to remove them from pending deletion state`() = runTestOnMain {
|
|
var snackbarCalled = false
|
|
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = { _, undo, _ ->
|
|
runBlocking { undo(history) }
|
|
snackbarCalled = true
|
|
},
|
|
onTimeFrameDeleted = { },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
|
|
assertTrue(snackbarCalled)
|
|
verify(appStore).dispatch(AppAction.AddPendingDeletionSet(history.toPendingDeletionHistory()))
|
|
verify(appStore).dispatch(AppAction.UndoPendingDeletionSet(history.toPendingDeletionHistory()))
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN regular items are deleted and not undone THEN items are removed from storage`() = runTestOnMain {
|
|
var snackbarCalled = false
|
|
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = { _, _, delete ->
|
|
runBlocking { delete(history) }
|
|
snackbarCalled = true
|
|
},
|
|
onTimeFrameDeleted = { },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
|
|
assertTrue(snackbarCalled)
|
|
verify(storage).deleteVisitsFor(history.first().url)
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN group items are deleted and not undone THEN items are removed from provider and browser store updated`() = runTestOnMain {
|
|
var snackbarCalled = false
|
|
val history = setOf(History.Group(0, "title", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0), listOf()))
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = { _, _, delete ->
|
|
runBlocking { delete(history) }
|
|
snackbarCalled = true
|
|
},
|
|
onTimeFrameDeleted = { },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
browserStore.waitUntilIdle()
|
|
|
|
assertTrue(snackbarCalled)
|
|
captureBrowserActions.assertFirstAction(HistoryMetadataAction.DisbandSearchGroupAction::class)
|
|
verify(provider).deleteMetadataSearchGroup(history.first())
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN a null time frame is deleted THEN browser store is informed, storage deletes everything, and callback is invoked`() = runTestOnMain {
|
|
var callbackInvoked = false
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = mock(),
|
|
onTimeFrameDeleted = { callbackInvoked = true },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteTimeRange(null)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
browserStore.waitUntilIdle()
|
|
|
|
assertTrue(callbackInvoked)
|
|
assertEquals(HistoryFragmentState.Mode.Normal, store.state.mode)
|
|
captureBrowserActions.assertFirstAction(RecentlyClosedAction.RemoveAllClosedTabAction::class)
|
|
captureBrowserActions.assertLastAction(EngineAction.PurgeHistoryAction::class) {}
|
|
verify(storage).deleteEverything()
|
|
}
|
|
|
|
@Ignore("Intermittent failure; see Bug 1848436.")
|
|
@Test
|
|
fun `WHEN a specified time frame is deleted THEN browser store is informed, storage deletes time frame, and callback is invoked`() = runTestOnMain {
|
|
var callbackInvoked = false
|
|
val middleware = HistoryStorageMiddleware(
|
|
appStore = appStore,
|
|
browserStore = browserStore,
|
|
historyProvider = provider,
|
|
historyStorage = storage,
|
|
undoDeleteSnackbar = mock(),
|
|
onTimeFrameDeleted = { callbackInvoked = true },
|
|
scope = this,
|
|
)
|
|
val store = HistoryFragmentStore(
|
|
initialState = HistoryFragmentState.initial,
|
|
middleware = listOf(middleware),
|
|
)
|
|
|
|
store.dispatch(HistoryFragmentAction.DeleteTimeRange(RemoveTimeFrame.LastHour)).joinBlocking()
|
|
store.waitUntilIdle()
|
|
browserStore.waitUntilIdle()
|
|
this.advanceUntilIdle()
|
|
|
|
assertTrue(callbackInvoked)
|
|
assertFalse(store.state.isDeletingItems)
|
|
captureBrowserActions.assertFirstAction(RecentlyClosedAction.RemoveAllClosedTabAction::class)
|
|
captureBrowserActions.assertLastAction(EngineAction.PurgeHistoryAction::class) {}
|
|
verify(storage).deleteVisitsBetween(anyLong(), anyLong())
|
|
}
|
|
}
|