1
0
Fork 0

For #8651 - Add HistoryInteractor/Controller unit/ui tests

master
Mugurell 2020-03-18 18:12:04 +02:00 committed by Emily Kager
parent fc0260d6ee
commit 9f3bbf1fb7
5 changed files with 409 additions and 72 deletions

View File

@ -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()
}
}

View File

@ -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")))

View File

@ -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))

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}