1
0
Fork 0

Closes #8006: Add Close/Undo UI tests (#8007)

master
Aaron Train 2020-01-30 16:15:40 -05:00 committed by GitHub
parent f728cdaf05
commit 89cc5657ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 145 deletions

View File

@ -110,7 +110,6 @@ class HomeScreenTest {
verifyHomeWordmark() verifyHomeWordmark()
verifyAddTabButton() verifyAddTabButton()
verifyShareTabsButton(visible = false) verifyShareTabsButton(visible = false)
verifyCloseTabsButton(visible = false)
verifyPrivateSessionHeader() verifyPrivateSessionHeader()
verifyPrivateSessionMessage(visible = true) verifyPrivateSessionMessage(visible = true)
verifyHomeToolbar() verifyHomeToolbar()
@ -130,7 +129,6 @@ class HomeScreenTest {
verifyHomeWordmark() verifyHomeWordmark()
verifyAddTabButton() verifyAddTabButton()
verifyShareTabsButton(visible = true) verifyShareTabsButton(visible = true)
verifyCloseTabsButton(visible = true)
verifyPrivateSessionHeader() verifyPrivateSessionHeader()
verifyPrivateSessionMessage(visible = false) verifyPrivateSessionMessage(visible = false)
verifyHomeToolbar() verifyHomeToolbar()

View File

@ -28,8 +28,10 @@ import org.mozilla.fenix.ui.robots.navigationToolbar
* - Opening a private tab * - Opening a private tab
* - Verifying tab list * - Verifying tab list
* - Closing all tabs * - Closing all tabs
* - Close tab
* - Swipe to close tab
* - Undo close tab
* *
* TODO: Tab Collections
*/ */
class TabbedBrowsingTest { class TabbedBrowsingTest {
@ -76,7 +78,10 @@ class TabbedBrowsingTest {
homeScreen { homeScreen {
// Timing issue on slow devices on Firebase // Timing issue on slow devices on Firebase
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime) mDevice.waitNotNull(
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
TestAssetHelper.waitingTime
)
verifyExistingTabList() verifyExistingTabList()
}.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu {
@ -106,10 +111,13 @@ class TabbedBrowsingTest {
verifyTabCounter("1") verifyTabCounter("1")
}.openHomeScreen { }.openHomeScreen {
// Timing issue on slow devices on Firebase // Timing issue on slow devices on Firebase
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime) mDevice.waitNotNull(
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
TestAssetHelper.waitingTime
)
verifyExistingTabList() verifyExistingTabList()
verifyShareTabsButton(true) verifyShareTabsButton(true)
verifyCloseTabsButton(true) verifyCloseTabsButton("Test_Page_1")
}.togglePrivateBrowsingMode() }.togglePrivateBrowsingMode()
// Verify private tabs remain in private browsing mode // Verify private tabs remain in private browsing mode
@ -135,7 +143,10 @@ class TabbedBrowsingTest {
homeScreen { homeScreen {
// Timing issue on slow devices on Firebase // Timing issue on slow devices on Firebase
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime) mDevice.waitNotNull(
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
TestAssetHelper.waitingTime
)
verifyExistingTabList() verifyExistingTabList()
}.openTabsListThreeDotMenu { }.openTabsListThreeDotMenu {
verifyCloseAllTabsButton() verifyCloseAllTabsButton()
@ -147,5 +158,59 @@ class TabbedBrowsingTest {
verifyNoTabsOpenedHeader() verifyNoTabsOpenedHeader()
verifyNoTabsOpenedText() verifyNoTabsOpenedText()
} }
// Repeat for Private Tabs
homeScreen {
}.togglePrivateBrowsingMode()
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openHomeScreen { }
homeScreen {
// Timing issue on slow devices on Firebase
mDevice.waitNotNull(
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
TestAssetHelper.waitingTime
)
verifyExistingTabList()
verifyPrivateTabsCloseTabsButton()
}.closeAllPrivateTabs {
verifyPrivateSessionHeader()
verifyPrivateSessionMessage(true)
}
}
@Test
fun closeTabTest() {
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
genericURLS.forEachIndexed { index, element ->
navigationToolbar {
}.openNewTabAndEnterToBrowser(element.url) {
verifyPageContent(element.content)
}.openHomeScreen { }
homeScreen {
verifyExistingOpenTabs("Test_Page_${index + 1}")
verifyCloseTabsButton("Test_Page_${index + 1}")
closeTabViaXButton("Test_Page_${index + 1}")
verifySnackBarText("Tab closed")
snackBarButtonClick("UNDO")
verifyExistingOpenTabs("Test_Page_${index + 1}")
verifyCloseTabsButton("Test_Page_${index + 1}")
swipeTabRight("Test_Page_${index + 1}")
verifySnackBarText("Tab closed")
snackBarButtonClick("UNDO")
verifyExistingOpenTabs("Test_Page_${index + 1}")
verifyCloseTabsButton("Test_Page_${index + 1}")
swipeTabLeft("Test_Page_${index + 1}")
verifySnackBarText("Tab closed")
snackBarButtonClick("UNDO")
verifyExistingOpenTabs("Test_Page_${index + 1}")
verifyCloseTabsButton("Test_Page_${index + 1}")
}
}
} }
} }

View File

@ -1,122 +0,0 @@
/* 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
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.Before
import org.junit.After
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.navigationToolbar
/**
* Tests for verifying basic functionality of tabs
*
*/
class TabsTest {
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private lateinit var mockWebServer: MockWebServer
@get:Rule
val activityTestRule = HomeActivityTestRule()
@Before
fun setUp() {
mockWebServer = MockWebServer().apply {
setDispatcher(AndroidAssetDispatcher())
start()
}
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
@Ignore("This is a stub test, ignore for now")
@Test
fun tabsItemsTest() {
homeScreen { }.dismissOnboarding()
// Setup browser so that tabs are visible in UI
// Verify all tabs elements are visible:
// "open tabs header, + button, etc.
// Verify tabs 3-dot menu elements
}
@Ignore("This is a stub test, ignore for now")
@Test
fun noTabsInCacheTest() {
// Verify open tabs header and text exists (when no previous browsing)
// Verify + button redirects to navigation bar UI
// Verify "Collections" header exists
// Verify "No collections" text (when no previous browsing)
}
@Ignore("This is a stub test, ignore for now")
@Test
fun browsingWithTabsTest() {
// Setup:
// - Verify + button redirects to navigation bar UI
// - Enter mock website via navigation bar
// Verify "Open tabs" header exits
// Verify Collections header exits
// Verify that tabs counter is augmented by 1 count
// Click on tabs counter
// Verify that new page is listed in "Open tabs"
// Repeat for several sites
}
@Ignore("This is a stub test, ignore for now")
@Test
fun tabsThreeDotMenuTest() {
// short 3-dot menu setup:
// - create multiple tabs (using mock web server) for the following...
// Verify tabs 3-dot menu functions:
// 1. "Close all tabs"
// 2. "Share tabs" - opens share sub-menu
// 3. "Save to collection" - verify saved to collection
// NOTE: extended 3 dot menu test is verified in a separate class
}
@Ignore("This is a stub test, ignore for now")
@Test
fun collectionsTest() {
// Setup:
// - create multiple tabs (using mock web server) for the following...
// Verify collections header exits
// Verify multiple collections can be saved, named
// Verify "Select tabs to save"
// Verify collections dropdown toggle
// Verify send and share button works - opens share menu
// Verify collections 3-dot menu functions:
// 1. Delete collection
// 2. Rename collection
// 3. Open tabs
}
@Ignore("This is a sample test, ignore")
@Test
fun sampleTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}
}
}

View File

@ -14,23 +14,25 @@ import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.Until
import androidx.test.uiautomator.By import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.containsString import org.hamcrest.Matchers.containsString
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.ext.waitNotNull
/** /**
@ -80,8 +82,11 @@ class HomeScreenRobot {
// Private mode elements // Private mode elements
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader() fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible) fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton()
fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible) fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible)
fun verifyCloseTabsButton(visible: Boolean = true) = assertCloseTabsButton(visible) fun verifyCloseTabsButton(title: String) =
assertCloseTabsButton(title)
fun verifyExistingTabList() = assertExistingTabList() fun verifyExistingTabList() = assertExistingTabList()
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title) fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
@ -91,29 +96,35 @@ class HomeScreenRobot {
collectionThreeDotButton().click() collectionThreeDotButton().click()
mDevice.waitNotNull(Until.findObject(By.text("Delete collection")), waitingTime) mDevice.waitNotNull(Until.findObject(By.text("Delete collection")), waitingTime)
} }
fun selectRenameCollection() { fun selectRenameCollection() {
onView(allOf(ViewMatchers.withText("Rename collection"))).click() onView(allOf(ViewMatchers.withText("Rename collection"))).click()
mDevice.waitNotNull(Until.findObject(By.res("name_collection_edittext"))) mDevice.waitNotNull(Until.findObject(By.res("name_collection_edittext")))
} }
fun selectDeleteCollection() { fun selectDeleteCollection() {
onView(allOf(ViewMatchers.withText("Delete collection"))).click() onView(allOf(ViewMatchers.withText("Delete collection"))).click()
mDevice.waitNotNull(Until.findObject(By.res("message")), waitingTime) mDevice.waitNotNull(Until.findObject(By.res("message")), waitingTime)
} }
fun confirmDeleteCollection() { fun confirmDeleteCollection() {
onView(allOf(ViewMatchers.withText("DELETE"))).click() onView(allOf(ViewMatchers.withText("DELETE"))).click()
mDevice.waitNotNull(Until.findObject(By.res("collections_header")), waitingTime) mDevice.waitNotNull(Until.findObject(By.res("collections_header")), waitingTime)
} }
fun typeCollectionName(name: String) { fun typeCollectionName(name: String) {
mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime) mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime)
collectionNameTextField().perform(ViewActions.replaceText(name)) collectionNameTextField().perform(ViewActions.replaceText(name))
collectionNameTextField().perform(ViewActions.pressImeActionButton()) collectionNameTextField().perform(ViewActions.pressImeActionButton())
} }
fun scrollToElementByText(text: String): UiScrollable { fun scrollToElementByText(text: String): UiScrollable {
val appView = UiScrollable(UiSelector().scrollable(true)) val appView = UiScrollable(UiSelector().scrollable(true))
appView.scrollTextIntoView(text) appView.scrollTextIntoView(text)
return appView return appView
} }
fun swipeUpToDismissFirstRun() { fun swipeUpToDismissFirstRun() {
scrollToElementByText("Start browsing") scrollToElementByText("Start browsing")
} }
@ -124,12 +135,31 @@ class HomeScreenRobot {
fun togglePrivateBrowsingModeOnOff() { fun togglePrivateBrowsingModeOnOff() {
onView(ViewMatchers.withResourceName("privateBrowsingButton")) onView(ViewMatchers.withResourceName("privateBrowsingButton"))
.perform(click()) .perform(click())
} }
fun swipeToBottom() = onView(ViewMatchers.withId(R.id.home_component)).perform(ViewActions.swipeUp()) fun swipeToBottom() = onView(withId(R.id.home_component)).perform(ViewActions.swipeUp())
fun swipeToTop() = onView(ViewMatchers.withId(R.id.home_component)).perform(ViewActions.swipeDown()) fun swipeToTop() = onView(withId(R.id.home_component)).perform(ViewActions.swipeDown())
fun swipeTabRight(title: String) =
onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeRight())
fun swipeTabLeft(title: String) =
onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeLeft())
fun closeTabViaXButton(title: String) = closeTabViaX(title)
fun verifySnackBarText(expectedText: String) {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
}
fun snackBarButtonClick(expectedText: String) {
onView(CoreMatchers.allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))
).perform(ViewActions.click())
}
class Transition { class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@ -167,6 +197,15 @@ class HomeScreenRobot {
ThreeDotMenuMainRobot().interact() ThreeDotMenuMainRobot().interact()
return ThreeDotMenuMainRobot.Transition() return ThreeDotMenuMainRobot.Transition()
} }
fun closeAllPrivateTabs(interact: HomeScreenRobot.() -> Unit): Transition {
onView(withId(R.id.close_tabs_button))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.perform(click())
HomeScreenRobot().interact()
return Transition()
}
} }
} }
@ -322,8 +361,13 @@ private fun assertYourPrivacyHeader() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertYourPrivacyText() = private fun assertYourPrivacyText() =
onView(CoreMatchers.allOf(withText( onView(
"Weve designed Firefox Preview to give you control over what you share online and what you share with us."))) CoreMatchers.allOf(
withText(
"Weve designed Firefox Preview to give you control over what you share online and what you share with us."
)
)
)
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertPrivacyNoticeButton() = private fun assertPrivacyNoticeButton() =
@ -337,7 +381,7 @@ private fun assertStartBrowsingButton() =
// Private mode elements // Private mode elements
private fun assertPrivateSessionHeader() = private fun assertPrivateSessionHeader() =
onView(CoreMatchers.allOf(withText("Private tabs"))) onView(CoreMatchers.allOf(withText("Private tabs")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " + const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
"when you quit the app or close all private tabs. While this doesnt make you anonymous to websites or " + "when you quit the app or close all private tabs. While this doesnt make you anonymous to websites or " +
@ -354,11 +398,12 @@ private fun assertShareTabsButton(visible: Boolean) =
onView(CoreMatchers.allOf(withId(R.id.share_tabs_button), isDisplayed())) onView(CoreMatchers.allOf(withId(R.id.share_tabs_button), isDisplayed()))
.check(matches(withEffectiveVisibility(visibleOrGone(visible)))) .check(matches(withEffectiveVisibility(visibleOrGone(visible))))
private fun assertCloseTabsButton(visible: Boolean) = private fun assertCloseTabsButton(title: String) =
onView(CoreMatchers.allOf(withId(R.id.close_tab_button), isDisplayed())) onView(allOf(withId(R.id.close_tab_button), withContentDescription("Close tab $title")))
.check(matches(withEffectiveVisibility(visibleOrGone(visible)))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE private fun visibleOrGone(visibility: Boolean) =
if (visibility) Visibility.VISIBLE else Visibility.GONE
private fun assertExistingTabList() = private fun assertExistingTabList() =
onView(CoreMatchers.allOf(withId(R.id.item_tab))) onView(CoreMatchers.allOf(withId(R.id.item_tab)))
@ -375,4 +420,17 @@ private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_bu
private fun collectionThreeDotButton() = onView(allOf(withId(R.id.collection_overflow_button))) private fun collectionThreeDotButton() = onView(allOf(withId(R.id.collection_overflow_button)))
private fun collectionNameTextField() = onView(allOf(ViewMatchers.withResourceName("name_collection_edittext"))) private fun collectionNameTextField() =
onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))
private fun closeTabViaX(title: String) {
val closeButton = onView(
allOf(
withId(R.id.close_tab_button),
withContentDescription("Close tab $title")
)
)
closeButton.perform(click())
}
private fun assertPrivateTabsCloseTabsButton() = onView(allOf(withId(R.id.close_tabs_button)))