2019-10-03 18:30:55 +02:00
/ * 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
2020-01-13 22:53:35 +01:00
import android.os.Build
import android.widget.TextView
2019-12-27 16:55:35 +01:00
import androidx.core.content.pm.PackageInfoCompat
2020-01-13 22:53:35 +01:00
import androidx.test.espresso.Espresso
2019-12-27 16:55:35 +01:00
import androidx.test.espresso.Espresso.onView
2020-01-13 22:53:35 +01:00
import androidx.test.espresso.ViewAssertion
2020-04-24 18:41:53 +02:00
import androidx.test.espresso.action.ViewActions
2019-12-27 16:55:35 +01:00
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
2020-04-24 18:41:53 +02:00
import androidx.test.espresso.matcher.ViewMatchers
2019-12-27 16:55:35 +01:00
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
2020-04-24 18:41:53 +02:00
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
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
2019-12-27 16:55:35 +01:00
import org.hamcrest.CoreMatchers.containsString
2020-01-13 22:53:35 +01:00
import org.mozilla.fenix.BuildConfig
2019-12-27 16:55:35 +01:00
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestHelper
2020-04-24 18:41:53 +02:00
import org.mozilla.fenix.helpers.isVisibleForUser
import org.mozilla.fenix.settings.SupportUtils
2020-01-13 22:53:35 +01:00
import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.time.format.DateTimeFormatterBuilder
import java.time.temporal.ChronoField
import java.util.Calendar
2020-07-09 19:50:51 +02:00
import java.util.Date
2019-10-03 18:30:55 +02:00
/ * *
* Implementation of Robot Pattern for the settings search sub menu .
* /
class SettingsSubMenuAboutRobot {
2019-12-27 16:55:35 +01:00
fun verifyAboutFirefoxPreview ( ) = assertFirefoxPreviewPage ( )
2019-10-03 18:30:55 +02:00
class Transition {
val mDevice = UiDevice . getInstance ( InstrumentationRegistry . getInstrumentation ( ) )
fun goBack ( interact : SettingsRobot . ( ) -> Unit ) : SettingsRobot . Transition {
2019-12-27 16:55:35 +01:00
goBackButton ( ) . perform ( click ( ) )
2019-10-03 18:30:55 +02:00
SettingsRobot ( ) . interact ( )
return SettingsRobot . Transition ( )
}
}
}
2019-12-27 16:55:35 +01:00
private fun assertFirefoxPreviewPage ( ) {
assertVersionNumber ( )
assertProductCompany ( )
assertCurrentTimestamp ( )
2020-04-24 18:41:53 +02:00
verifyListElements ( )
}
private fun navigateBackToAboutPage ( itemToInteract : ( ) -> Unit ) {
2020-07-28 17:33:57 +02:00
browserScreen {
} . openTabDrawer {
closeTab ( )
}
2020-04-24 18:41:53 +02:00
homeScreen {
} . openThreeDotMenu {
} . openSettings {
} . openAboutFirefoxPreview {
itemToInteract ( )
}
}
private fun verifyListElements ( ) {
2019-12-27 16:55:35 +01:00
assertWhatIsNewInFirefoxPreview ( )
2020-04-24 18:41:53 +02:00
navigateBackToAboutPage ( :: assertSupport )
navigateBackToAboutPage ( :: assertPrivacyNotice )
navigateBackToAboutPage ( :: assertKnowYourRights )
navigateBackToAboutPage ( :: assertLicensingInformation )
navigateBackToAboutPage ( :: assertLibrariesUsed )
2019-12-27 16:55:35 +01:00
}
private fun assertVersionNumber ( ) {
val context = InstrumentationRegistry . getInstrumentation ( ) . targetContext
val packageInfo = context . packageManager . getPackageInfo ( context . packageName , 0 )
val versionCode = PackageInfoCompat . getLongVersionCode ( packageInfo ) . toString ( )
val buildNVersion = " ${packageInfo.versionName} (Build # $versionCode ) \n "
val componentsVersion =
" ${mozilla.components.Build.version} , ${mozilla.components.Build.gitHash} "
val geckoVersion =
org . mozilla . geckoview . BuildConfig . MOZ _APP _VERSION + " - " + org . mozilla . geckoview . BuildConfig . MOZ _APP _BUILDID
2020-03-03 01:02:00 +01:00
val asVersion = mozilla . components . Build . applicationServicesVersion
2019-12-27 16:55:35 +01:00
onView ( withId ( R . id . about _text ) )
. check ( matches ( withText ( containsString ( buildNVersion ) ) ) )
. check ( matches ( withText ( containsString ( componentsVersion ) ) ) )
. check ( matches ( withText ( containsString ( geckoVersion ) ) ) )
2020-03-03 01:02:00 +01:00
. check ( matches ( withText ( containsString ( asVersion ) ) ) )
2019-12-27 16:55:35 +01:00
}
private fun assertProductCompany ( ) {
onView ( withId ( R . id . about _content ) )
. check ( matches ( withText ( containsString ( " Firefox Preview is produced by Mozilla. " ) ) ) )
}
private fun assertCurrentTimestamp ( ) {
onView ( withId ( R . id . build _date ) )
2020-05-26 02:07:17 +02:00
// Currently UI tests run against debug builds, which display a hard-coded string 'debug build'
// instead of the date. See https://github.com/mozilla-mobile/fenix/pull/10812#issuecomment-633746833
. check ( matches ( withText ( containsString ( " debug build " ) ) ) )
// This assertion should be valid for non-debug build types.
// .check(BuildDateAssertion.isDisplayedDateAccurate())
2019-12-27 16:55:35 +01:00
}
private fun assertWhatIsNewInFirefoxPreview ( ) {
2020-07-03 18:31:47 +02:00
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " What’ s new in Firefox Preview " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " What’ s new in Firefox Preview " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
2020-07-03 18:31:47 +02:00
// Commenting out since the Text to verify in the web site seems to be different now
/ *
2020-04-24 18:41:53 +02:00
TestHelper . verifyUrl (
2020-07-03 18:31:47 +02:00
SupportUtils . SumoTopic . WHATS_NEW . topicStr ,
" org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view " ,
R . id . mozac _browser _toolbar _url _view
) * /
2020-04-24 18:41:53 +02:00
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertSupport ( ) {
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " Support " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " Support " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
2020-04-24 18:41:53 +02:00
TestHelper . verifyUrl (
" support.mozilla.org " ,
" org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view " ,
R . id . mozac _browser _toolbar _url _view
2020-01-13 22:53:35 +01:00
)
2020-04-24 18:41:53 +02:00
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertPrivacyNotice ( ) {
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " Privacy notice " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " Privacy notice " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
2020-04-24 18:41:53 +02:00
TestHelper . verifyUrl (
" /privacy/firefox " ,
" org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view " ,
R . id . mozac _browser _toolbar _url _view
2020-01-13 22:53:35 +01:00
)
2020-04-24 18:41:53 +02:00
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertKnowYourRights ( ) {
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " Know your rights " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " Know your rights " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
2020-04-24 18:41:53 +02:00
TestHelper . verifyUrl (
SupportUtils . SumoTopic . YOUR_RIGHTS . topicStr ,
" org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view " ,
R . id . mozac _browser _toolbar _url _view
2020-01-13 22:53:35 +01:00
)
2020-04-24 18:41:53 +02:00
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertLicensingInformation ( ) {
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " Licensing information " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " Licensing information " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
2020-04-24 18:41:53 +02:00
TestHelper . verifyUrl (
" about:license " ,
" org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view " ,
R . id . mozac _browser _toolbar _url _view
2020-01-13 22:53:35 +01:00
)
2020-04-24 18:41:53 +02:00
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertLibrariesUsed ( ) {
2020-04-24 18:41:53 +02:00
if ( ! onView ( withText ( " Libraries that we use " ) ) . isVisibleForUser ( ) ) {
onView ( withId ( R . id . about _layout ) ) . perform ( ViewActions . swipeUp ( ) )
}
2019-12-27 16:55:35 +01:00
onView ( withText ( " Libraries that we use " ) )
2020-04-24 18:41:53 +02:00
. check ( matches ( withEffectiveVisibility ( ViewMatchers . Visibility . VISIBLE ) ) )
2019-12-27 16:55:35 +01:00
. perform ( click ( ) )
onView ( withId ( R . id . action _bar ) ) . check ( matches ( hasDescendant ( withText ( containsString ( " Firefox Preview | OSS Libraries " ) ) ) ) )
2020-01-13 22:53:35 +01:00
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
2019-10-03 18:30:55 +02:00
private fun goBackButton ( ) =
2019-12-27 16:55:35 +01:00
onView ( CoreMatchers . allOf ( withContentDescription ( " Navigate up " ) ) )
2020-01-13 22:53:35 +01:00
class BuildDateAssertion {
// When the app is built on firebase, there are times where the BuildDate is off by a few seconds or a few minutes.
// To compensate for that slight discrepancy, this assertion was added to see if the Build Date shown
// is within a reasonable amount of time from when the app was built.
companion object {
// this pattern represents the following date format: "Monday 12/30 @ 6:49 PM"
private const val DATE _PATTERN = " EEEE M/d @ h:m a "
//
private const val NUM _OF _HOURS = 1
fun isDisplayedDateAccurate ( ) : ViewAssertion {
return ViewAssertion { view , noViewFoundException ->
if ( noViewFoundException != null ) throw noViewFoundException
val textFromView = ( view as TextView ) . text
?: throw AssertionError ( " This view is not of type TextView " )
verifyDateIsWithinRange ( textFromView . toString ( ) , NUM _OF _HOURS )
}
}
private fun verifyDateIsWithinRange ( dateText : String , hours : Int ) {
// This assertion checks whether has defined a range of tim
if ( Build . VERSION . SDK _INT <= Build . VERSION_CODES . N _MR1 ) {
val simpleDateFormat = SimpleDateFormat ( DATE _PATTERN )
val date = simpleDateFormat . parse ( dateText )
2020-07-09 19:50:51 +02:00
if ( date == null || ! date . isWithinRangeOf ( hours ) ) {
throw AssertionError ( " The build date is not within Range. " )
}
2020-01-13 22:53:35 +01:00
} else {
val textviewDate = getLocalDateTimeFromString ( dateText )
val buildConfigDate = getLocalDateTimeFromString ( BuildConfig . BUILD _DATE )
if ( ! buildConfigDate . isEqual ( textviewDate ) &&
! textviewDate . isWithinRangeOf ( hours , buildConfigDate )
) {
throw AssertionError ( " $textviewDate is not equal to the date within the build config: $buildConfigDate , and are not within a reasonable amount of time from each other. " )
}
}
}
private fun Date . isWithinRangeOf ( hours : Int ) : Boolean {
// To determine the date range, the maxDate is retrieved by adding the variable hours to the calendar.
// Since the calendar will represent the maxDate at this time, to retrieve the minDate the variable hours is multipled by negative 2 and added to the calendar
// This will result in the maxDate being equal to the original Date + hours, and minDate being equal to original Date - hours
val calendar = Calendar . getInstance ( )
val currentYear = calendar . get ( Calendar . YEAR )
calendar . time = this
calendar . set ( Calendar . YEAR , currentYear )
val updatedDate = calendar . time
calendar . add ( Calendar . HOUR _OF _DAY , hours )
val maxDate = calendar . time
calendar . add (
Calendar . HOUR _OF _DAY ,
hours * - 2
) // Gets the minDate by subtracting from maxDate
val minDate = calendar . time
return updatedDate . after ( minDate ) && updatedDate . before ( maxDate )
}
private fun LocalDateTime . isWithinRangeOf (
hours : Int ,
baselineDate : LocalDateTime
) : Boolean {
val upperBound = baselineDate . plusHours ( hours . toLong ( ) )
val lowerBound = baselineDate . minusHours ( hours . toLong ( ) )
val currentDate = this
return currentDate . isAfter ( lowerBound ) && currentDate . isBefore ( upperBound )
}
private fun getLocalDateTimeFromString ( buildDate : String ) : LocalDateTime {
val dateFormatter = DateTimeFormatterBuilder ( ) . appendPattern ( DATE _PATTERN )
. parseDefaulting ( ChronoField . YEAR , LocalDateTime . now ( ) . year . toLong ( ) )
. toFormatter ( )
return LocalDateTime . parse ( buildDate , dateFormatter )
}
}
}