Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Add automated UI test for main three dot menu (#2540)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpappalax committed May 16, 2019
1 parent b3a3c94 commit ba3edbc
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 14 deletions.
32 changes: 32 additions & 0 deletions app/src/androidTest/java/org/mozilla/fenix/helpers/Matchers.kt
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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)))!!
}
46 changes: 46 additions & 0 deletions app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuTest.kt
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
Original file line number Diff line number Diff line change
@@ -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())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Original file line number Diff line number Diff line change
@@ -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")))
Original file line number Diff line number Diff line change
@@ -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")))
Original file line number Diff line number Diff line change
@@ -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)))

0 comments on commit ba3edbc

Please sign in to comment.