1
0
Fork 0

Added BuildDate Assertion for About Preview Screen; Added verification for external links in About Preview Screen (#7413)

master
Kadeem M 2020-01-13 16:53:35 -05:00 committed by Richard Pappalardo
parent a952d0858c
commit fb2a68fdec
3 changed files with 168 additions and 3 deletions

View File

@ -55,4 +55,11 @@ object TestHelper {
false -> "com.android.packageinstaller" false -> "com.android.packageinstaller"
} }
} }
fun waitUntilObjectIsFound(resourceName: String) {
mDevice.waitNotNull(
Until.findObjects(By.res(resourceName)),
TestAssetHelper.waitingTime
)
}
} }

View File

@ -8,7 +8,6 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.MockWebServer
import org.junit.Rule import org.junit.Rule
import org.junit.Ignore
import org.junit.Before import org.junit.Before
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
@ -71,7 +70,6 @@ class SettingsAboutTest {
} }
@Test @Test
@Ignore("Temp disable flakey test - see: https://github.com/mozilla-mobile/fenix/issues/7388")
fun verifyAboutFirefoxPreview() { fun verifyAboutFirefoxPreview() {
homeScreen { homeScreen {
}.openThreeDotMenu { }.openThreeDotMenu {

View File

@ -6,8 +6,12 @@
package org.mozilla.fenix.ui.robots package org.mozilla.fenix.ui.robots
import android.os.Build
import android.widget.TextView
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewAssertion
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
@ -20,8 +24,15 @@ import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.Visibility
import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.containsString
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper
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
/** /**
* Implementation of Robot Pattern for the settings search sub menu. * Implementation of Robot Pattern for the settings search sub menu.
@ -79,32 +90,101 @@ private fun assertProductCompany() {
private fun assertCurrentTimestamp() { private fun assertCurrentTimestamp() {
onView(withId(R.id.build_date)) onView(withId(R.id.build_date))
.check(matches(withText(org.mozilla.fenix.BuildConfig.BUILD_DATE))) .check(BuildDateAssertion.isDisplayedDateAccurate())
} }
private fun assertWhatIsNewInFirefoxPreview() { private fun assertWhatIsNewInFirefoxPreview() {
onView(withText("Whats new in Firefox Preview")) onView(withText("Whats new in Firefox Preview"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.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()
} }
private fun assertSupport() { private fun assertSupport() {
onView(withText("Support")) onView(withText("Support"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.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()
} }
private fun assertPrivacyNotice() { private fun assertPrivacyNotice() {
onView(withText("Privacy notice")) onView(withText("Privacy notice"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.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()
} }
private fun assertKnowYourRights() { private fun assertKnowYourRights() {
TestHelper.scrollToElementByText("Know your rights")
onView(withText("Know your rights")) onView(withText("Know your rights"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.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()
} }
private fun assertLicensingInformation() { private fun assertLicensingInformation() {
TestHelper.scrollToElementByText("Libraries that we use")
onView(withText("Licensing information")) onView(withText("Licensing information"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.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()
} }
private fun assertLibrariesUsed() { private fun assertLibrariesUsed() {
@ -114,7 +194,87 @@ private fun assertLibrariesUsed() {
.perform(click()) .perform(click())
onView(withId(R.id.action_bar)).check(matches(hasDescendant(withText(containsString("Firefox Preview | OSS Libraries"))))) onView(withId(R.id.action_bar)).check(matches(hasDescendant(withText(containsString("Firefox Preview | OSS Libraries")))))
Espresso.pressBack()
} }
private fun goBackButton() = private fun goBackButton() =
onView(CoreMatchers.allOf(withContentDescription("Navigate up"))) onView(CoreMatchers.allOf(withContentDescription("Navigate up")))
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)
}
}
}