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

Commit

Permalink
Closes #3977: Add basic navigational UI tests
Browse files Browse the repository at this point in the history
- Adds UI tests (and assets) for basic navigation

fix: review changes

fix: linter cleanup

fix: detekt cleanup
  • Loading branch information
AaronMT committed Jul 15, 2019
1 parent e91a2e6 commit e8ffe86
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 3 deletions.
7 changes: 7 additions & 0 deletions app/src/androidTest/assets/pages/generic1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<body>
<h1>
<p id="testContent">Page content: 1</p>
</h1>
</body>
</html>
7 changes: 7 additions & 0 deletions app/src/androidTest/assets/pages/generic2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<body>
<h1>
<p id="testContent">Page content: 2</p>
</h1>
</body>
</html>
7 changes: 7 additions & 0 deletions app/src/androidTest/assets/pages/generic3.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<body>
<h1>
<p id="testContent">Page content: 3</p>
</h1>
</body>
</html>
2 changes: 2 additions & 0 deletions app/src/androidTest/assets/pages/jquery-3.4.1.slim.min.js

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions app/src/androidTest/assets/pages/refresh.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

<html>
<script src="jquery-3.4.1.slim.min.js"></script>
<script>

function setCookie(newVal){
window.document.cookie = "pageStatus = " + newVal + ";";
}


function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

function valSwap(){
currentCookie = readCookie("pageStatus");
if(currentCookie == null) {
setCookie("DEFAULT");
}

if (currentCookie.localeCompare("REFRESHED") == 0) {
setCookie("DEFAULT");
return "My little test page - DEFAULT";
} else {
setCookie("REFRESHED");
return "My little test page - REFRESHED!";
}
}

var textToShow = valSwap();
window.addEventListener('DOMContentLoaded', (event) => {
document.querySelector('h1').innerHTML = textToShow;
});
</script>
<body>
<h1>My little test page - DEFAULT</h1>
</body>
</html>
121 changes: 121 additions & 0 deletions app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* 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.HomeActivityTestRule
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.ui.robots.navigationToolbar

/**
* Tests for verifying basic functionality of browser navigation
*
* Including:
* - Visiting a URL
* - Back and Forward navigation
* - Refresh
*/

class NavigationToolbarTest {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private lateinit var mockWebServer: MockWebServer

/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
@get:Rule
val activityTestRule = HomeActivityTestRule()

@Before
fun setUp() {
mockWebServer = MockWebServer().apply {
setDispatcher(AndroidAssetDispatcher())
start()
}
}

@After
fun tearDown() {
mockWebServer.shutdown()
}

@Test
fun goBackTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val nextWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)

navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openNavigationToolbar {
}.enterURLAndEnterToBrowser(nextWebPage.url) {
verifyPageContent(nextWebPage.content)
}

// Re-open the three-dot menu for verification
navigationToolbar {
}.openThreeDotMenu {
verifyThreeDotMenuExists()
}.goBack {
verifyPageContent(defaultWebPage.content)
}
}

@Test
fun goForwardTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val nextWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)

navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}.openNavigationToolbar {
}.enterURLAndEnterToBrowser(nextWebPage.url) {
verifyPageContent(nextWebPage.content)
mDevice.pressBack()
verifyPageContent(defaultWebPage.content)
}

// Re-open the three-dot menu for verification
navigationToolbar {
}.openThreeDotMenu {
verifyThreeDotMenuExists()
}.goForward {
verifyPageContent(nextWebPage.content)
}
}

@Test
fun refreshPageTest() {
val refreshWebPage = TestAssetHelper.getRefreshAsset(mockWebServer)

navigationToolbar {
}.enterURLAndEnterToBrowser(refreshWebPage.url) {
verifyPageContent("DEFAULT")
}

// Use refresh from the three-dot menu
navigationToolbar {
}.openThreeDotMenu {
}.refreshPage {
verifyPageContent("REFRESHED")
}
}

@Test
fun visitURLTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)

navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
verifyPageContent(defaultWebPage.content)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ 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.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import org.hamcrest.CoreMatchers.containsString
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.click

class BrowserRobot {

Expand All @@ -26,12 +30,30 @@ class BrowserRobot {
.check(matches(withText(containsString(redirectUrl))))
}

class Transition {
/* Asserts that the text within DOM element with ID="testContent" has the given text, i.e.
* document.querySelector('#testContent').innerText == expectedText
*/
fun verifyPageContent(expectedText: String) {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.wait(Until.findObject(By.res(expectedText)), TestAssetHelper.waitingTime)
}

class Transition {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

fun openNavigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {

navURLBar().click()

NavigationToolbarRobot().interact()
return NavigationToolbarRobot.Transition()
}
}
}

fun browserScreen(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
BrowserRobot().interact()
return BrowserRobot.Transition()
}

fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* 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.net.Uri
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click

/**
* Implementation of Robot Pattern for the URL toolbar.
*/
class NavigationToolbarRobot {
class Transition {

val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

fun enterURLAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
urlBar().perform(click())
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())

BrowserRobot().interact()
return BrowserRobot.Transition()
}

fun openThreeDotMenu(interact: ThreeDotMenuRobot.() -> Unit): ThreeDotMenuRobot.Transition {
mDevice.wait(Until.findObject(By.text("Menu")), waitingTime)
threeDotButton().click()

ThreeDotMenuRobot().interact()
return ThreeDotMenuRobot.Transition()
}
}
}

fun navigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {
NavigationToolbarRobot().interact()
return NavigationToolbarRobot.Transition()
}

private fun urlBar() = onView(ViewMatchers.withId(R.id.toolbar))
private fun awesomeBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_edit_url_view))
private fun threeDotButton() = onView(ViewMatchers.withContentDescription("Menu"))
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ package org.mozilla.fenix.ui.robots

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
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
Expand All @@ -23,10 +26,14 @@ class ThreeDotMenuRobot {
fun verifySettingsButton() = assertSettingsButton()
fun verifyLibraryButton() = assertLibraryButton()
fun verifyHelpButton() = assertHelpButton()
fun verifyThreeDotMenuExists() = threeDotMenuRecyclerViewExists()
fun verifyForwardButton() = assertForwardButton()
fun verifyBackButton() = assertBackButton()
fun verifyRefreshButton() = assertRefreshButton()

class Transition {

val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

fun openSettings(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
mDevice.waitForIdle()
Expand All @@ -51,9 +58,35 @@ class ThreeDotMenuRobot {
BrowserRobot().interact()
return BrowserRobot.Transition()
}

fun goForward(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
forwardButton().click()

BrowserRobot().interact()
return BrowserRobot.Transition()
}

fun goBack(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
backButton().click()

BrowserRobot().interact()
return BrowserRobot.Transition()
}

fun refreshPage(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
refreshButton().click()

BrowserRobot().interact()
return BrowserRobot.Transition()
}
}
}

private fun threeDotMenuRecyclerViewExists() {
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
}
private fun settingsButton() = onView(allOf(withText("Settings")))
private fun assertSettingsButton() = settingsButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
Expand All @@ -65,3 +98,15 @@ private fun assertLibraryButton() = libraryButton()
private fun helpButton() = onView(allOf(withText(R.string.browser_menu_help)))
private fun assertHelpButton() = helpButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))

private fun forwardButton() = onView(ViewMatchers.withContentDescription("Forward"))
private fun assertForwardButton() = forwardButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))

private fun backButton() = onView(ViewMatchers.withContentDescription("Back"))
private fun assertBackButton() = backButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))

private fun refreshButton() = onView(ViewMatchers.withContentDescription("Refresh"))
private fun assertRefreshButton() = refreshButton()
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))

0 comments on commit e8ffe86

Please sign in to comment.