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
2019-10-03 18:30:55 +02:00
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers
2019-12-27 16:55:35 +01:00
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.Visibility
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-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.Date
import java.util.Calendar
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 ( )
assertWhatIsNewInFirefoxPreview ( )
assertSupport ( )
assertPrivacyNotice ( )
assertKnowYourRights ( )
assertLicensingInformation ( )
assertLibrariesUsed ( )
}
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
onView ( withId ( R . id . about _text ) )
. check ( matches ( withText ( containsString ( buildNVersion ) ) ) )
. check ( matches ( withText ( containsString ( componentsVersion ) ) ) )
. check ( matches ( withText ( containsString ( geckoVersion ) ) ) )
}
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-01-13 22:53:35 +01:00
. check ( BuildDateAssertion . isDisplayedDateAccurate ( ) )
2019-12-27 16:55:35 +01:00
}
private fun assertWhatIsNewInFirefoxPreview ( ) {
onView ( withText ( " What’ s new in Firefox Preview " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
// This is used to wait for the webpage to fully load
TestHelper . waitUntilObjectIsFound ( " org.mozilla.fenix.debug:id/mozac_browser_toolbar_title_view " )
onView ( withId ( R . id . mozac _browser _toolbar _title _view ) ) . check (
matches (
withText (
containsString ( " What's new in Firefox Preview " )
)
)
)
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertSupport ( ) {
onView ( withText ( " Support " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
// This is used to wait for the webpage to fully load
TestHelper . waitUntilObjectIsFound ( " org.mozilla.fenix.debug:id/mozac_browser_toolbar_title_view " )
onView ( withId ( R . id . mozac _browser _toolbar _title _view ) ) . check (
matches (
withText (
containsString ( " Firefox Preview | Mozilla Support " )
)
)
)
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertPrivacyNotice ( ) {
onView ( withText ( " Privacy notice " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
// This is used to wait for the webpage to fully load
TestHelper . waitUntilObjectIsFound ( " org.mozilla.fenix.debug:id/mozac_browser_toolbar_title_view " )
onView ( withId ( R . id . mozac _browser _toolbar _title _view ) ) . check (
matches (
withText (
containsString ( " Firefox Privacy Notice " )
)
)
)
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertKnowYourRights ( ) {
2020-01-13 22:53:35 +01:00
TestHelper . scrollToElementByText ( " Know your rights " )
2019-12-27 16:55:35 +01:00
onView ( withText ( " Know your rights " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
// This is used to wait for the webpage to fully load
TestHelper . waitUntilObjectIsFound ( " org.mozilla.fenix.debug:id/mozac_browser_toolbar_title_view " )
onView ( withId ( R . id . mozac _browser _toolbar _title _view ) ) . check (
matches (
withText (
containsString ( " Firefox Preview - Your Rights | How to | Mozilla Support " )
)
)
)
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertLicensingInformation ( ) {
2020-01-13 22:53:35 +01:00
TestHelper . scrollToElementByText ( " Libraries that we use " )
2019-12-27 16:55:35 +01:00
onView ( withText ( " Licensing information " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
2020-01-13 22:53:35 +01:00
. perform ( click ( ) )
// This is used to wait for the webpage to fully load
TestHelper . waitUntilObjectIsFound ( " org.mozilla.fenix.debug:id/mozac_browser_toolbar_title_view " )
onView ( withId ( R . id . mozac _browser _toolbar _title _view ) ) . check (
matches (
withText (
containsString ( " Licenses " )
)
)
)
Espresso . pressBack ( )
2019-12-27 16:55:35 +01:00
}
private fun assertLibrariesUsed ( ) {
TestHelper . scrollToElementByText ( " Libraries that we use " )
onView ( withText ( " Libraries that we use " ) )
. check ( matches ( withEffectiveVisibility ( Visibility . VISIBLE ) ) )
. 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 )
if ( ! date . isWithinRangeOf ( hours ) ) throw AssertionError ( " The build date is not within Range. " )
} 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 )
}
}
}