Unverified Commit 4fec12b1 authored by Aaron Train's avatar Aaron Train Committed by GitHub
Browse files

Closes #7656: Add UI tests for Reader View (#7829)

parent 5bd5f815
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt</title>
<meta content="width=device-width, initial-scale=1"
name="viewport"/>
</head>
<body>
<h1>
Lorem ipsum dolor sit amet, consectetur adipiscing elit,<br>
sed do eiusmod tempor incididunt ut labore et dolore magna <br>
aliqua. Ut enim ad minim veniam, quis nostrud exercitation <br>
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis <br>
aute irure dolor in reprehenderit in voluptate velit esse cillum <br>
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat <br>
non proident, sunt in culpa qui officia deserunt mollit anim id est <br>
laborum.
</h1>
<p id="testContent">Page content: lorem ipsum</p>
<h1>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt</h1>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
sit amet.
</p>
</body>
</html>
......@@ -6,8 +6,11 @@ package org.mozilla.fenix.helpers
import android.graphics.Bitmap
import android.view.View
import android.view.ViewGroup
import org.hamcrest.CoreMatchers.not
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher
import org.mozilla.fenix.helpers.matchers.BitmapDrawableMatcher
import androidx.test.espresso.matcher.ViewMatchers.isChecked as espressoIsChecked
import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled
......@@ -34,3 +37,22 @@ private fun maybeInvertMatcher(matcher: Matcher<View>, useUnmodifiedMatcher: Boo
}
fun withBitmapDrawable(bitmap: Bitmap, name: String): Matcher<View>? = BitmapDrawableMatcher(bitmap, name)
fun nthChildOf(
parentMatcher: Matcher<View>,
childPosition: Int
): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("Position is $childPosition")
}
public override fun matchesSafely(view: View): Boolean {
if (view.parent !is ViewGroup) {
return parentMatcher.matches(view.parent)
}
val group = view.parent as ViewGroup
return parentMatcher.matches(view.parent) && group.getChildAt(childPosition) == view
}
}
}
/* 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.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.ui.robots.navigationToolbar
import org.mozilla.fenix.ui.robots.readerViewRobot
/**
* Tests for verifying basic functionality of content context menus
*
* - Verifies Reader View entry and detection when available UI and functionality
* - Verifies Reader View exit UI and functionality
* - Verifies Reader View appearance controls UI and functionality
*
*/
class ReaderViewTest {
private lateinit var mockWebServer: MockWebServer
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@get:Rule
val activityIntentTestRule = HomeActivityIntentTestRule()
@Before
fun setUp() {
mockWebServer = MockWebServer().apply {
setDispatcher(AndroidAssetDispatcher())
start()
}
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
/**
* Verify that Reader View capable pages
*
* - Show blue notification in the three dot menu
* - Show the toggle button in the three dot menu
*
*/
@Test
fun verifyReaderViewPageMenuDetection() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.closeBrowserMenuToBrowser { }
}
/**
* Verify that non Reader View capable pages
*
* - Do not show a blue notification in the three dot menu
* - Reader View toggle should not be visible in the three dot menu
*
*/
@Test
fun verifyNonReaderViewPageMenuNoDetection() {
var genericPage =
TestAssetHelper.getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(genericPage.url) {
verifyPageContent(genericPage.content)
}
readerViewRobot {
verifyReaderViewDetected(false)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(false)
verifyReaderViewAppearance(false)
}.closeBrowserMenuToBrowser { }
}
@Test
fun verifyReaderViewToggle() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(false)
}.close { }
readerViewRobot {
verifyReaderViewDetected(true)
}
}
@Test
fun verifyReaderViewAppearanceUI() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.openReaderViewAppearance {
verifyAppearanceFontGroup(true)
verifyAppearanceFontSansSerif(true)
verifyAppearanceFontSerif(true)
verifyAppearanceFontIncrease(true)
verifyAppearanceFontDecrease(true)
verifyAppearanceColorGroup(true)
verifyAppearanceColorDark(true)
verifyAppearanceColorLight(true)
verifyAppearanceColorSepia(true)
}
}
@Test
fun verifyReaderViewAppearanceFontToggle() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.openReaderViewAppearance {
verifyAppearanceFontGroup(true)
verifyAppearanceFontSansSerif(true)
verifyAppearanceFontSerif(true)
verifyAppearanceFontIncrease(true)
verifyAppearanceFontDecrease(true)
}.toggleSansSerif {
verifyAppearanceFontIsActive("SANSSERIF")
}.toggleSerif {
verifyAppearanceFontIsActive("SERIF")
}
}
@Test
fun verifyReaderViewAppearanceFontSizeToggle() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.openReaderViewAppearance {
verifyAppearanceFontIncrease(true)
verifyAppearanceFontDecrease(true)
verifyAppearanceFontSize(3)
}.toggleFontSizeIncrease {
verifyAppearanceFontSize(4)
}.toggleFontSizeIncrease {
verifyAppearanceFontSize(5)
}.toggleFontSizeIncrease {
verifyAppearanceFontSize(6)
}.toggleFontSizeDecrease {
verifyAppearanceFontSize(5)
}.toggleFontSizeDecrease {
verifyAppearanceFontSize(4)
}.toggleFontSizeDecrease {
verifyAppearanceFontSize(3)
}
}
@Test
fun verifyReaderViewAppearanceColorSchemeChange() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
verifyPageContent(readerViewPage.content)
}
readerViewRobot {
verifyReaderViewDetected(true)
}
navigationToolbar {
}.openThreeDotMenu {
verifyReaderViewToggle(true)
}.toggleReaderView {
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.openReaderViewAppearance {
verifyAppearanceColorDark(true)
verifyAppearanceColorLight(true)
verifyAppearanceColorSepia(true)
}.toggleColorSchemeChangeDark {
verifyAppearanceColorSchemeChange("DARK")
}.toggleColorSchemeChangeSepia {
verifyAppearanceColorSchemeChange("SEPIA")
}.toggleColorSchemeChangeLight {
verifyAppearanceColorSchemeChange("LIGHT")
}
}
}
/* 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 android.content.Context
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction
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.withId
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.nthChildOf
/**
* Implementation of Robot Pattern for Reader View UI.
*/
class ReaderViewRobot {
fun verifyReaderViewDetected(visible: Boolean = false): ViewInteraction =
assertReaderViewDetected(visible)
fun verifyAppearanceFontGroup(visible: Boolean = false): ViewInteraction =
assertAppearanceFontGroup(visible)
fun verifyAppearanceFontSansSerif(visible: Boolean = false): ViewInteraction =
assertAppearanceFontSansSerif(visible)
fun verifyAppearanceFontSerif(visible: Boolean = false): ViewInteraction =
assertAppearanceFontSerif(visible)
fun verifyAppearanceFontDecrease(visible: Boolean = false): ViewInteraction =
assertAppearanceFontDecrease(visible)
fun verifyAppearanceFontIncrease(visible: Boolean = false): ViewInteraction =
assertAppearanceFontIncrease(visible)
fun verifyAppearanceColorGroup(visible: Boolean = false): ViewInteraction =
assertAppearanceColorGroup(visible)
fun verifyAppearanceColorSepia(visible: Boolean = false): ViewInteraction =
assertAppearanceColorSepia(visible)
fun verifyAppearanceColorDark(visible: Boolean = false): ViewInteraction =
assertAppearanceColorDark(visible)
fun verifyAppearanceColorLight(visible: Boolean = false): ViewInteraction =
assertAppearanceColorLight(visible)
fun verifyAppearanceFontIsActive(fontType: String) {
val fontTypeKey: String = "mozac-readerview-fonttype"
val prefs = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences(
"mozac_feature_reader_view",
Context.MODE_PRIVATE
)
assertEquals(fontType, prefs.getString(fontTypeKey, ""))
}
fun verifyAppearanceFontSize(expectedFontSize: Int) {
val fontSizeKey: String = "mozac-readerview-fontsize"
val prefs = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences(
"mozac_feature_reader_view",
Context.MODE_PRIVATE
)
val fontSizeKeyValue = prefs.getInt(fontSizeKey, 3)
assertEquals(expectedFontSize, fontSizeKeyValue)
}
fun verifyAppearanceColorSchemeChange(expectedColorScheme: String) {
val colorSchemeKey: String = "mozac-readerview-colorscheme"
val prefs = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences(
"mozac_feature_reader_view",
Context.MODE_PRIVATE
)
assertEquals(expectedColorScheme, prefs.getString(colorSchemeKey, ""))
}
class Transition {
fun toggleSansSerif(interact: ReaderViewRobot.() -> Unit): Transition {
fun sansSerifButton() =
onView(
withId(R.id.mozac_feature_readerview_font_sans_serif)
)
sansSerifButton().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleSerif(interact: ReaderViewRobot.() -> Unit): Transition {
fun serifButton() =
onView(
withId(R.id.mozac_feature_readerview_font_serif)
)
serifButton().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleFontSizeDecrease(interact: ReaderViewRobot.() -> Unit): Transition {
fun fontSizeDecrease() =
onView(
withId(R.id.mozac_feature_readerview_font_size_decrease)
)
fontSizeDecrease().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleFontSizeIncrease(interact: ReaderViewRobot.() -> Unit): Transition {
fun fontSizeIncrease() =
onView(
withId(R.id.mozac_feature_readerview_font_size_increase)
)
fontSizeIncrease().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleColorSchemeChangeLight(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleLightColorSchemeButton() =
onView(
withId(R.id.mozac_feature_readerview_color_light)
)
toggleLightColorSchemeButton().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleColorSchemeChangeDark(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleDarkColorSchemeButton() =
onView(
withId(R.id.mozac_feature_readerview_color_dark)
)
toggleDarkColorSchemeButton().click()
ReaderViewRobot().interact()
return Transition()
}
fun toggleColorSchemeChangeSepia(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleSepiaColorSchemeButton() =
onView(
withId(R.id.mozac_feature_readerview_color_sepia)
)
toggleSepiaColorSchemeButton().click()
ReaderViewRobot().interact()
return Transition()
}
}
}
fun readerViewRobot(interact: ReaderViewRobot.() -> Unit): ReaderViewRobot.Transition {
ReaderViewRobot().interact()
return ReaderViewRobot.Transition()
}
/**
* Detects for the blue notification dot in the three dot menu
*/
private fun assertReaderViewDetected(visible: Boolean) =
onView(
nthChildOf(
withId(R.id.mozac_browser_toolbar_menu), 2
)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceFontGroup(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_font_group)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceFontSansSerif(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_font_sans_serif)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceFontSerif(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_font_serif)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceFontDecrease(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_font_size_decrease)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceFontIncrease(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_font_size_increase)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)
private fun assertAppearanceColorDark(visible: Boolean) =
onView(
withId(R.id.mozac_feature_readerview_color_dark)
).check(
matches(withEffectiveVisibility(visibleOrGone(visible)))
)