1
0
Fork 0

Add automated UI test for main three dot menu (#2540)

master
Richard Pappalardo 2019-05-15 17:32:25 -07:00 committed by GitHub
parent b3a3c94169
commit ba3edbcf92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 337 additions and 14 deletions

View File

@ -0,0 +1,32 @@
/* 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.helpers
import android.view.View
import org.hamcrest.CoreMatchers.not
import org.hamcrest.Matcher
import androidx.test.espresso.matcher.ViewMatchers.isChecked as espressoIsChecked
import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled
import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected
/**
* The [espressoIsEnabled] function that can also handle disabled state through the boolean argument.
*/
fun isEnabled(isEnabled: Boolean): Matcher<View> = maybeInvertMatcher(espressoIsEnabled(), isEnabled)
/**
* The [espressoIsChecked] function that can also handle unchecked state through the boolean argument.
*/
fun isChecked(isChecked: Boolean): Matcher<View> = maybeInvertMatcher(espressoIsChecked(), isChecked)
/**
* The [espressoIsSelected] function that can also handle not selected state through the boolean argument.
*/
fun isSelected(isSelected: Boolean): Matcher<View> = maybeInvertMatcher(espressoIsSelected(), isSelected)
private fun maybeInvertMatcher(matcher: Matcher<View>, useUnmodifiedMatcher: Boolean): Matcher<View> = when {
useUnmodifiedMatcher -> matcher
else -> not(matcher)
}

View File

@ -0,0 +1,23 @@
/* 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.helpers
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions.matches
fun ViewInteraction.click(): ViewInteraction = this.perform(ViewActions.click())!!
fun ViewInteraction.assertIsEnabled(isEnabled: Boolean): ViewInteraction {
return this.check(matches(isEnabled(isEnabled)))!!
}
fun ViewInteraction.assertIsChecked(isChecked: Boolean): ViewInteraction {
return this.check(matches(isChecked(isChecked)))!!
}
fun ViewInteraction.assertIsSelected(isSelected: Boolean): ViewInteraction {
return this.check(matches(isSelected(isSelected)))!!
}

View File

@ -0,0 +1,46 @@
/* 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 org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.ui.robots.homeScreen
/**
* Tests for verifying the main three dot menu options
*
* Including:
* - Verify all menu items present
* - Open library button opens library menu
* - Open settings button opens settings menu
* - Open Help button opens support page in browser
*
*/
class ThreeDotMenuTest {
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
@get:Rule
val activityTestRule = HomeActivityTestRule()
@Test
fun threeDotMenuItemsTest() {
homeScreen {
}.openThreeDotMenu {
verifySettingsButton()
verifyLibraryButton()
verifyHelpButton()
}.openSettings {
verifySettingsView()
}.goBack {
}.openThreeDotMenu {
}.openLibrary {
verifyLibraryView()
}.goBack {
}.openThreeDotMenu {
}.openHelp {
verifyHelpUrl()
}
}
}

View File

@ -0,0 +1,32 @@
/* 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/. */
@file:Suppress("TooManyFunctions")
package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers.containsString
import org.mozilla.fenix.R
class BrowserRobot {
fun verifyHelpUrl() {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val redirectUrl = "https://support.mozilla.org/"
mDevice.waitForIdle()
onView(withId(R.id.mozac_browser_toolbar_url_view))
.check(matches(withText(containsString(redirectUrl))))
}
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
}

View File

@ -7,33 +7,58 @@
package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.hamcrest.Matchers.allOf
import org.mozilla.fenix.R
/**
* Implementation of Robot Pattern for the home screen menu.
*/
class HomeScreenRobot {
fun verifyHomeScreen() = homeScreen()
fun verifyHomePrivateBrowsingButton() = homePrivateBrowsingButton()
fun verifyHomeMenu() = homeMenu()
fun verifyHomeWordmark() = homeWordmark()
fun verifyHomeToolbar() = homeToolbar()
fun verifyHomeComponent() = homeComponent()
fun verifyHomeScreen() = assertHomeScreen()
fun verifyHomePrivateBrowsingButton() = assertHomePrivateBrowsingButton()
fun verifyHomeMenu() = assertHomeMenu()
fun verifyHomeWordmark() = assertHomeWordmark()
fun verifyHomeToolbar() = assertHomeToolbar()
fun verifyHomeComponent() = assertHomeComponent()
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun openThreeDotMenu(interact: ThreeDotMenuRobot.() -> Unit): ThreeDotMenuRobot.Transition {
mDevice.waitForIdle()
threeDotButton().perform(click())
ThreeDotMenuRobot().interact()
return ThreeDotMenuRobot.Transition()
}
}
}
fun homeScreen(interact: HomeScreenRobot.() -> Unit) {
fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
private fun homeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun homePrivateBrowsingButton() = onView(ViewMatchers.withResourceName("privateBrowsingButton"))
private fun assertHomeMenu() = onView(ViewMatchers.withResourceName("menuButton"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun homeMenu() = onView(ViewMatchers.withResourceName("menuButton"))
private fun assertHomePrivateBrowsingButton() = onView(ViewMatchers.withResourceName("privateBrowsingButton"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun homeWordmark() = onView(ViewMatchers.withResourceName("wordmark"))
private fun assertHomeWordmark() = onView(ViewMatchers.withResourceName("wordmark"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun homeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun homeComponent() = onView(ViewMatchers.withResourceName("home_component"))
private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("home_component"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun threeDotButton() = onView(allOf(ViewMatchers.withId(R.id.menuButton)))

View File

@ -0,0 +1,46 @@
/* 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/. */
@file:Suppress("TooManyFunctions")
package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.uiautomator.UiDevice
import androidx.test.platform.app.InstrumentationRegistry
import org.hamcrest.CoreMatchers.allOf
import org.mozilla.fenix.R
/**
* Implementation of Robot Pattern for the your library menu.
*/
class LibraryRobot {
fun verifyLibraryView() = assertLibraryView()
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle()
goBackButton().perform(click())
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
}
}
private fun assertLibraryView() {
// verify that we are in the correct library view
onView(allOf(withId(R.id.libraryItemTitle)))
onView(allOf(withText("Bookmarks")))
}
private fun goBackButton() = onView(allOf(withContentDescription("Navigate up")))

View File

@ -0,0 +1,52 @@
/* 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/. */
@file:Suppress("TooManyFunctions")
package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import org.hamcrest.CoreMatchers
/**
* Implementation of Robot Pattern for the settings menu.
*/
class SettingsRobot {
fun verifySettingsView() = assertSettingsView()
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle()
goBackButton().perform(ViewActions.click())
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
}
}
private fun assertSettingsView() {
// verify that we are in the correct library view
assertBasicsHeading()
assertAdvancedHeading()
}
private fun assertBasicsHeading() = onView(ViewMatchers.withText("Basics"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAdvancedHeading() = onView(ViewMatchers.withText("Advanced"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun goBackButton() = onView(CoreMatchers.allOf(withContentDescription("Navigate up")))

View File

@ -0,0 +1,67 @@
/* 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/. */
@file:Suppress("TooManyFunctions")
package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.hamcrest.Matchers.allOf
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.click
/**
* Implementation of Robot Pattern for the three dot (main) menu.
*/
class ThreeDotMenuRobot {
fun verifySettingsButton() = assertSettingsButton()
fun verifyLibraryButton() = assertLibraryButton()
fun verifyHelpButton() = assertHelpButton()
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun openSettings(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
mDevice.waitForIdle()
settingsButton().click()
SettingsRobot().interact()
return SettingsRobot.Transition()
}
fun openLibrary(interact: LibraryRobot.() -> Unit): LibraryRobot.Transition {
mDevice.waitForIdle()
libraryButton().click()
LibraryRobot().interact()
return LibraryRobot.Transition()
}
fun openHelp(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
helpButton().click()
BrowserRobot().interact()
return BrowserRobot.Transition()
}
}
}
private fun settingsButton() = onView(allOf(withText("Settings")))
private fun assertSettingsButton() = settingsButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
private fun libraryButton() = onView(allOf(withText(R.string.browser_menu_your_library)))
private fun assertLibraryButton() = libraryButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
private fun helpButton() = onView(allOf(withText(R.string.browser_menu_help)))
private fun assertHelpButton() = helpButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))