For #8651 - Add HistoryInteractor/Controller unit/ui tests
parent
fc0260d6ee
commit
9f3bbf1fb7
|
@ -80,6 +80,77 @@ class HistoryTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun copyHistoryItemURLTest() {
|
||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openThreeDotMenu {
|
||||
}.openLibrary {
|
||||
}.openHistory {
|
||||
}.openThreeDotMenu {
|
||||
}.clickCopy {
|
||||
verifyCopySnackBarText()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shareHistoryItemTest() {
|
||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openThreeDotMenu {
|
||||
}.openLibrary {
|
||||
}.openHistory {
|
||||
}.openThreeDotMenu {
|
||||
}.clickShare {
|
||||
verifyShareOverlay()
|
||||
verifyShareTabFavicon()
|
||||
verifyShareTabTitle()
|
||||
verifyShareTabUrl()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun openHistoryItemInNewTabTest() {
|
||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openThreeDotMenu {
|
||||
}.openLibrary {
|
||||
}.openHistory {
|
||||
}.openThreeDotMenu {
|
||||
}.clickOpenInNormalTab {
|
||||
verifyPageContent(firstWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun openHistoryItemInNewPrivateTabTest() {
|
||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openThreeDotMenu {
|
||||
}.openLibrary {
|
||||
}.openHistory {
|
||||
}.openThreeDotMenu {
|
||||
}.clickOpenInPrivateTab {
|
||||
verifyPageContent(firstWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteHistoryItemTest() {
|
||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
@ -90,8 +161,8 @@ class HistoryTest {
|
|||
}.openThreeDotMenu {
|
||||
}.openLibrary {
|
||||
}.openHistory {
|
||||
openOverflowMenu()
|
||||
clickThreeDotMenuDelete()
|
||||
}.openThreeDotMenu {
|
||||
}.clickDelete {
|
||||
verifyEmptyHistoryView()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ class HistoryRobot {
|
|||
|
||||
fun verifyTestPageUrl(expectedUrl: Uri) = assertPageUrl(expectedUrl)
|
||||
|
||||
fun verifyCopySnackBarText() = assertCopySnackBarText()
|
||||
|
||||
fun verifyDeleteConfirmationMessage() = assertDeleteConfirmationMessage()
|
||||
|
||||
fun verifyHomeScreen() = HomeScreenRobot().verifyHomeScreen()
|
||||
|
@ -66,11 +68,7 @@ class HistoryRobot {
|
|||
),
|
||||
waitingTime
|
||||
)
|
||||
overflowMenu().click()
|
||||
}
|
||||
|
||||
fun clickThreeDotMenuDelete() {
|
||||
threeDotMenuDeleteButton().click()
|
||||
threeDotMenu().click()
|
||||
}
|
||||
|
||||
fun clickDeleteHistoryButton() {
|
||||
|
@ -92,6 +90,15 @@ class HistoryRobot {
|
|||
HistoryRobot().interact()
|
||||
return Transition()
|
||||
}
|
||||
|
||||
fun openThreeDotMenu(interact: ThreeDotMenuHistoryItemRobot.() -> Unit):
|
||||
ThreeDotMenuHistoryItemRobot.Transition {
|
||||
|
||||
threeDotMenu().click()
|
||||
|
||||
ThreeDotMenuHistoryItemRobot().interact()
|
||||
return ThreeDotMenuHistoryItemRobot.Transition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,9 +113,9 @@ private fun testPageTitle() = onView(allOf(withId(R.id.title), withText("Test_Pa
|
|||
|
||||
private fun pageUrl() = onView(withId(R.id.url))
|
||||
|
||||
private fun overflowMenu() = onView(withId(R.id.overflow_menu))
|
||||
private fun threeDotMenu() = onView(withId(R.id.overflow_menu))
|
||||
|
||||
private fun threeDotMenuDeleteButton() = onView(withId(R.id.simple_text))
|
||||
private fun snackBarText() = onView(withId(R.id.snackbar_text))
|
||||
|
||||
private fun deleteAllHistoryButton() = onView(withId(R.id.delete_button))
|
||||
|
||||
|
@ -143,3 +150,5 @@ private fun assertDeleteConfirmationMessage() =
|
|||
onView(withText("This will delete all of your browsing data."))
|
||||
.inRoot(isDialog())
|
||||
.check(matches(isDisplayed()))
|
||||
|
||||
private fun assertCopySnackBarText() = snackBarText().check(matches(withText("URL copied")))
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/* 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.ui.robots
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.click
|
||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||
|
||||
/**
|
||||
* Implementation of Robot Pattern for the History three dot menu.
|
||||
*/
|
||||
class ThreeDotMenuHistoryItemRobot {
|
||||
|
||||
class Transition {
|
||||
|
||||
fun clickCopy(interact: HistoryRobot.() -> Unit): HistoryRobot.Transition {
|
||||
copyButton().click()
|
||||
HistoryRobot().interact()
|
||||
return HistoryRobot.Transition()
|
||||
}
|
||||
|
||||
fun clickShare(interact: LibrarySubMenusMultipleSelectionToolbarRobot.() -> Unit):
|
||||
LibrarySubMenusMultipleSelectionToolbarRobot.Transition {
|
||||
|
||||
shareButton().click()
|
||||
|
||||
mDevice.waitNotNull(
|
||||
Until.findObject(
|
||||
By.text("ALL ACTIONS")
|
||||
), TestAssetHelper.waitingTime
|
||||
)
|
||||
|
||||
LibrarySubMenusMultipleSelectionToolbarRobot().interact()
|
||||
return LibrarySubMenusMultipleSelectionToolbarRobot.Transition()
|
||||
}
|
||||
|
||||
fun clickOpenInNormalTab(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||
openInNewNormalTabButton().click()
|
||||
BrowserRobot().interact()
|
||||
return BrowserRobot.Transition()
|
||||
}
|
||||
|
||||
fun clickOpenInPrivateTab(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||
openInNewPrivateTabButton().click()
|
||||
BrowserRobot().interact()
|
||||
return BrowserRobot.Transition()
|
||||
}
|
||||
|
||||
fun clickDelete(interact: HistoryRobot.() -> Unit): HistoryRobot.Transition {
|
||||
deleteButton().click()
|
||||
HistoryRobot().interact()
|
||||
return HistoryRobot.Transition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyButton() = onView(withText(R.string.history_menu_copy_button))
|
||||
|
||||
private fun shareButton() = onView(withText(R.string.history_menu_share_button))
|
||||
|
||||
private fun openInNewNormalTabButton() =
|
||||
onView(withText(R.string.history_menu_open_in_new_tab_button))
|
||||
|
||||
private fun openInNewPrivateTabButton() =
|
||||
onView(withText(R.string.history_menu_open_in_private_tab_button))
|
||||
|
||||
private fun deleteButton() = onView(withText(R.string.history_delete_item))
|
|
@ -4,20 +4,58 @@
|
|||
|
||||
package org.mozilla.fenix.library.history
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.res.Resources
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDirections
|
||||
import assertk.assertAll
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.hasSize
|
||||
import assertk.assertions.isEqualTo
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import mozilla.components.concept.engine.prompt.ShareData
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.TestApplication
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
// Robolectric needed for `onShareItem()`
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = TestApplication::class)
|
||||
class HistoryControllerTest {
|
||||
|
||||
private val historyItem = HistoryItem(0, "title", "url", 0.toLong())
|
||||
private val store: HistoryFragmentStore = mockk(relaxed = true)
|
||||
private val state: HistoryFragmentState = mockk(relaxed = true)
|
||||
private val navController: NavController = mockk(relaxed = true)
|
||||
private val resources: Resources = mockk(relaxed = true)
|
||||
private val snackbar: FenixSnackbar = mockk(relaxed = true)
|
||||
private val clipboardManager: ClipboardManager = mockk(relaxed = true)
|
||||
private val openInBrowser: (HistoryItem, BrowsingMode?) -> Unit = mockk(relaxed = true)
|
||||
private val displayDeleteAll: () -> Unit = mockk(relaxed = true)
|
||||
private val invalidateOptionsMenu: () -> Unit = mockk(relaxed = true)
|
||||
private val deleteHistoryItems: (Set<HistoryItem>) -> Unit = mockk(relaxed = true)
|
||||
private val controller = DefaultHistoryController(
|
||||
store,
|
||||
navController,
|
||||
resources,
|
||||
snackbar,
|
||||
clipboardManager,
|
||||
openInBrowser,
|
||||
displayDeleteAll,
|
||||
invalidateOptionsMenu,
|
||||
deleteHistoryItems
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
@ -26,34 +64,35 @@ class HistoryControllerTest {
|
|||
|
||||
@Test
|
||||
fun onPressHistoryItemInNormalMode() {
|
||||
var historyItemReceived: HistoryItem? = null
|
||||
|
||||
every { state.mode } returns HistoryFragmentState.Mode.Normal
|
||||
|
||||
val controller = DefaultHistoryController(
|
||||
store,
|
||||
{ historyItemReceived = it },
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk()
|
||||
)
|
||||
|
||||
controller.handleOpen(historyItem)
|
||||
assertEquals(historyItem, historyItemReceived)
|
||||
|
||||
verify {
|
||||
openInBrowser(historyItem, null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onOpenItemInNormalMode() {
|
||||
controller.handleOpen(historyItem, BrowsingMode.Normal)
|
||||
|
||||
verify {
|
||||
openInBrowser(historyItem, BrowsingMode.Normal)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onOpenItemInPrivateMode() {
|
||||
controller.handleOpen(historyItem, BrowsingMode.Private)
|
||||
|
||||
verify {
|
||||
openInBrowser(historyItem, BrowsingMode.Private)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPressHistoryItemInEditMode() {
|
||||
every { state.mode } returns HistoryFragmentState.Mode.Editing(setOf())
|
||||
|
||||
val controller = DefaultHistoryController(
|
||||
store,
|
||||
{ },
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk()
|
||||
)
|
||||
|
||||
controller.handleSelect(historyItem)
|
||||
|
||||
verify {
|
||||
|
@ -65,14 +104,6 @@ class HistoryControllerTest {
|
|||
fun onPressSelectedHistoryItemInEditMode() {
|
||||
every { state.mode } returns HistoryFragmentState.Mode.Editing(setOf(historyItem))
|
||||
|
||||
val controller = DefaultHistoryController(
|
||||
store,
|
||||
{ },
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk()
|
||||
)
|
||||
|
||||
controller.handleDeselect(historyItem)
|
||||
|
||||
verify {
|
||||
|
@ -84,7 +115,6 @@ class HistoryControllerTest {
|
|||
fun onBackPressedInNormalMode() {
|
||||
every { state.mode } returns HistoryFragmentState.Mode.Normal
|
||||
|
||||
val controller = DefaultHistoryController(store, mockk(), mockk(), mockk(), mockk())
|
||||
assertFalse(controller.handleBackPressed())
|
||||
}
|
||||
|
||||
|
@ -92,9 +122,7 @@ class HistoryControllerTest {
|
|||
fun onBackPressedInEditMode() {
|
||||
every { state.mode } returns HistoryFragmentState.Mode.Editing(setOf())
|
||||
|
||||
val controller = DefaultHistoryController(store, mockk(), mockk(), mockk(), mockk())
|
||||
assertTrue(controller.handleBackPressed())
|
||||
|
||||
verify {
|
||||
store.dispatch(HistoryFragmentAction.ExitEditMode)
|
||||
}
|
||||
|
@ -102,45 +130,76 @@ class HistoryControllerTest {
|
|||
|
||||
@Test
|
||||
fun onModeSwitched() {
|
||||
var menuInvalidated = false
|
||||
val controller = DefaultHistoryController(
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk(),
|
||||
{ menuInvalidated = true },
|
||||
mockk()
|
||||
)
|
||||
controller.handleModeSwitched()
|
||||
assertEquals(true, menuInvalidated)
|
||||
|
||||
verify {
|
||||
invalidateOptionsMenu.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDeleteAll() {
|
||||
var deleteAllDialogShown = false
|
||||
val controller = DefaultHistoryController(
|
||||
mockk(),
|
||||
mockk(),
|
||||
{ deleteAllDialogShown = true },
|
||||
mockk(),
|
||||
mockk()
|
||||
)
|
||||
controller.handleDeleteAll()
|
||||
assertEquals(true, deleteAllDialogShown)
|
||||
|
||||
verify {
|
||||
displayDeleteAll.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDeleteSome() {
|
||||
var itemsToDelete: Set<HistoryItem>? = null
|
||||
val historyItem = HistoryItem(0, "title", "url", 0.toLong())
|
||||
val newHistoryItem = HistoryItem(1, "title", "url", 0.toLong())
|
||||
val controller = DefaultHistoryController(
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk(),
|
||||
mockk(),
|
||||
{ itemsToDelete = it }
|
||||
val itemsToDelete = setOf(historyItem)
|
||||
|
||||
controller.handleDeleteSome(itemsToDelete)
|
||||
|
||||
verify {
|
||||
deleteHistoryItems(itemsToDelete)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onCopyItem() {
|
||||
val clipdata = slot<ClipData>()
|
||||
|
||||
controller.handleCopyUrl(historyItem)
|
||||
|
||||
verify {
|
||||
clipboardManager.primaryClip = capture(clipdata)
|
||||
snackbar.show()
|
||||
}
|
||||
assertAll {
|
||||
assertEquals(clipdata.captured.itemCount, 1)
|
||||
assertThat(clipdata.captured.description.label).isEqualTo(historyItem.url)
|
||||
assertThat(clipdata.captured.getItemAt(0).text).isEqualTo(historyItem.url)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun onShareItem() {
|
||||
val directions = slot<NavDirections>()
|
||||
|
||||
controller.handleShare(historyItem)
|
||||
|
||||
// `verify` checks for referential equality.
|
||||
// This would fail as the NavDirections are created and used in place in the tested method.
|
||||
// Capture the NavDirections and `assert` for structural equality after.
|
||||
verify {
|
||||
navController.navigate(
|
||||
capture(directions)
|
||||
)
|
||||
controller.handleDeleteSome(setOf(historyItem, newHistoryItem))
|
||||
assertEquals(itemsToDelete, setOf(historyItem, newHistoryItem))
|
||||
}
|
||||
assertAll {
|
||||
// The below class is private, can't easily assert using `instanceOf`
|
||||
assertEquals(
|
||||
directions.captured::class.simpleName,
|
||||
"ActionHistoryFragmentToShareFragment"
|
||||
)
|
||||
assertThat(directions.captured.arguments["data"] as Array<ShareData>).hasSize(1)
|
||||
assertThat(((directions.captured.arguments["data"] as Array<ShareData>)[0]).title)
|
||||
.isEqualTo(historyItem.title)
|
||||
assertThat(((directions.captured.arguments["data"] as Array<ShareData>)[0]).url)
|
||||
.isEqualTo(historyItem.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/* 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
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isTrue
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verifyAll
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||
|
||||
class HistoryInteractorTest {
|
||||
private val historyItem = HistoryItem(0, "title", "url", 0.toLong())
|
||||
val controller: HistoryController = mockk(relaxed = true)
|
||||
val interactor = HistoryInteractor(controller)
|
||||
|
||||
@Test
|
||||
fun onOpen() {
|
||||
interactor.open(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleOpen(historyItem)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onSelect() {
|
||||
interactor.select(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleSelect(historyItem)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDeselect() {
|
||||
interactor.deselect(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleDeselect(historyItem)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onBackPressed() {
|
||||
every {
|
||||
controller.handleBackPressed()
|
||||
} returns true
|
||||
|
||||
val backpressHandled = interactor.onBackPressed()
|
||||
|
||||
verifyAll {
|
||||
controller.handleBackPressed()
|
||||
}
|
||||
assertThat(backpressHandled).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onModeSwitched() {
|
||||
interactor.onModeSwitched()
|
||||
|
||||
verifyAll {
|
||||
controller.handleModeSwitched()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onCopyPressed() {
|
||||
interactor.onCopyPressed(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleCopyUrl(historyItem)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onSharePressed() {
|
||||
interactor.onSharePressed(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleShare(historyItem)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onOpenInNormalTab() {
|
||||
interactor.onOpenInNormalTab(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleOpen(historyItem, BrowsingMode.Normal)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onOpenInPrivateTab() {
|
||||
interactor.onOpenInPrivateTab(historyItem)
|
||||
|
||||
verifyAll {
|
||||
controller.handleOpen(historyItem, BrowsingMode.Private)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDeleteAll() {
|
||||
interactor.onDeleteAll()
|
||||
|
||||
verifyAll {
|
||||
controller.handleDeleteAll()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDeleteSome() {
|
||||
val items = setOf(historyItem)
|
||||
|
||||
interactor.onDeleteSome(items)
|
||||
verifyAll {
|
||||
controller.handleDeleteSome(items)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue