Merge branch 'master' of https://github.com/mozilla-mobile/fenix
|
@ -12,11 +12,11 @@ jobs:
|
||||||
when:
|
when:
|
||||||
- {hour: 6, minute: 0}
|
- {hour: 6, minute: 0}
|
||||||
- {hour: 18, minute: 0}
|
- {hour: 18, minute: 0}
|
||||||
- name: fennec-nightly
|
- name: fennec-beta
|
||||||
job:
|
job:
|
||||||
type: decision-task
|
type: decision-task
|
||||||
treeherder-symbol: N-fennec
|
treeherder-symbol: fennec-beta
|
||||||
target-tasks-method: fennec-nightly
|
target-tasks-method: fennec-beta
|
||||||
when: [] # Force hook only
|
when: [] # Force hook only
|
||||||
- name: raptor
|
- name: raptor
|
||||||
job:
|
job:
|
||||||
|
|
|
@ -84,6 +84,7 @@ gen-external-apklibs
|
||||||
.adjust_token
|
.adjust_token
|
||||||
.sentry_token
|
.sentry_token
|
||||||
.digital_asset_links_token
|
.digital_asset_links_token
|
||||||
|
.mls_token
|
||||||
|
|
||||||
|
|
||||||
# Python Byte-compiled / optimized / DLL files
|
# Python Byte-compiled / optimized / DLL files
|
||||||
|
|
|
@ -8,7 +8,7 @@ tasks:
|
||||||
- $let:
|
- $let:
|
||||||
taskgraph:
|
taskgraph:
|
||||||
branch: taskgraph
|
branch: taskgraph
|
||||||
revision: bb532a33ad32213f3a396346b26abd28fb87a975
|
revision: 7a51e874018f13aa236f5dc64ae7bbcaf942fcf3
|
||||||
trustDomain: mobile
|
trustDomain: mobile
|
||||||
in:
|
in:
|
||||||
$let:
|
$let:
|
||||||
|
@ -63,11 +63,8 @@ tasks:
|
||||||
$if: 'tasks_for == "github-release"'
|
$if: 'tasks_for == "github-release"'
|
||||||
then: '${event.release.target_commitish}'
|
then: '${event.release.target_commitish}'
|
||||||
else:
|
else:
|
||||||
$if: 'tasks_for == "cron"'
|
$if: 'tasks_for in ["action", "cron"]'
|
||||||
then: '${push.branch}'
|
then: '${push.branch}'
|
||||||
else:
|
|
||||||
$if: 'tasks_for == "action"'
|
|
||||||
then: ${parameters.head_ref}
|
|
||||||
head_sha:
|
head_sha:
|
||||||
$if: 'tasks_for == "github-push"'
|
$if: 'tasks_for == "github-push"'
|
||||||
then: '${event.after}'
|
then: '${event.after}'
|
||||||
|
@ -78,11 +75,9 @@ tasks:
|
||||||
$if: 'tasks_for == "github-release"'
|
$if: 'tasks_for == "github-release"'
|
||||||
then: '${event.release.tag_name}'
|
then: '${event.release.tag_name}'
|
||||||
else:
|
else:
|
||||||
$if: 'tasks_for == "cron"'
|
$if: 'tasks_for in ["action", "cron"]'
|
||||||
then: '${push.revision}'
|
then: '${push.revision}'
|
||||||
else:
|
|
||||||
$if: 'tasks_for == "action"'
|
|
||||||
then: ${parameters.head_rev}
|
|
||||||
|
|
||||||
head_tag:
|
head_tag:
|
||||||
$if: 'tasks_for == "github-release"'
|
$if: 'tasks_for == "github-release"'
|
||||||
|
|
|
@ -5,6 +5,7 @@ plugins {
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
apply from: "$project.rootDir/automation/gradle/versionCode.gradle"
|
apply from: "$project.rootDir/automation/gradle/versionCode.gradle"
|
||||||
apply plugin: 'androidx.navigation.safeargs.kotlin'
|
apply plugin: 'androidx.navigation.safeargs.kotlin'
|
||||||
|
@ -150,6 +151,7 @@ android {
|
||||||
testOptions {
|
testOptions {
|
||||||
execution 'ANDROIDX_TEST_ORCHESTRATOR'
|
execution 'ANDROIDX_TEST_ORCHESTRATOR'
|
||||||
unitTests.includeAndroidResources = true
|
unitTests.includeAndroidResources = true
|
||||||
|
animationsDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "engine"
|
flavorDimensions "engine"
|
||||||
|
@ -355,6 +357,21 @@ android.applicationVariants.all { variant ->
|
||||||
buildConfigField 'String', 'DIGITAL_ASSET_LINKS_TOKEN', 'null'
|
buildConfigField 'String', 'DIGITAL_ASSET_LINKS_TOKEN', 'null'
|
||||||
println("X_X")
|
println("X_X")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// MLS: Read token from local file if it exists
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
print("MLS token: ")
|
||||||
|
|
||||||
|
try {
|
||||||
|
def token = new File("${rootDir}/.mls_token").text.trim()
|
||||||
|
buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
|
||||||
|
println "(Added from .mls_token file)"
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
buildConfigField 'String', 'MLS_TOKEN', '""'
|
||||||
|
println("X_X")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
|
@ -374,9 +391,11 @@ dependencies {
|
||||||
implementation Deps.androidx_coordinatorlayout
|
implementation Deps.androidx_coordinatorlayout
|
||||||
|
|
||||||
implementation Deps.sentry
|
implementation Deps.sentry
|
||||||
implementation Deps.leanplum
|
|
||||||
implementation Deps.osslicenses_library
|
implementation Deps.osslicenses_library
|
||||||
|
|
||||||
|
implementation Deps.leanplum_core
|
||||||
|
implementation Deps.leanplum_fcm
|
||||||
|
|
||||||
implementation Deps.mozilla_concept_engine
|
implementation Deps.mozilla_concept_engine
|
||||||
implementation Deps.mozilla_concept_push
|
implementation Deps.mozilla_concept_push
|
||||||
implementation Deps.mozilla_concept_storage
|
implementation Deps.mozilla_concept_storage
|
||||||
|
@ -394,6 +413,9 @@ dependencies {
|
||||||
implementation Deps.mozilla_browser_storage_sync
|
implementation Deps.mozilla_browser_storage_sync
|
||||||
implementation Deps.mozilla_browser_toolbar
|
implementation Deps.mozilla_browser_toolbar
|
||||||
|
|
||||||
|
implementation Deps.mozilla_support_extensions
|
||||||
|
implementation Deps.mozilla_feature_addons
|
||||||
|
|
||||||
implementation Deps.mozilla_feature_accounts
|
implementation Deps.mozilla_feature_accounts
|
||||||
implementation Deps.mozilla_feature_app_links
|
implementation Deps.mozilla_feature_app_links
|
||||||
implementation Deps.mozilla_feature_awesomebar
|
implementation Deps.mozilla_feature_awesomebar
|
||||||
|
@ -415,6 +437,7 @@ dependencies {
|
||||||
implementation Deps.mozilla_feature_readerview
|
implementation Deps.mozilla_feature_readerview
|
||||||
implementation Deps.mozilla_feature_tab_collections
|
implementation Deps.mozilla_feature_tab_collections
|
||||||
implementation Deps.mozilla_feature_top_sites
|
implementation Deps.mozilla_feature_top_sites
|
||||||
|
implementation Deps.mozilla_feature_share
|
||||||
implementation Deps.mozilla_feature_accounts_push
|
implementation Deps.mozilla_feature_accounts_push
|
||||||
implementation Deps.mozilla_feature_webcompat
|
implementation Deps.mozilla_feature_webcompat
|
||||||
implementation Deps.mozilla_feature_webnotifications
|
implementation Deps.mozilla_feature_webnotifications
|
||||||
|
@ -423,6 +446,8 @@ dependencies {
|
||||||
implementation Deps.mozilla_service_firefox_accounts
|
implementation Deps.mozilla_service_firefox_accounts
|
||||||
implementation Deps.mozilla_service_glean
|
implementation Deps.mozilla_service_glean
|
||||||
implementation Deps.mozilla_service_experiments
|
implementation Deps.mozilla_service_experiments
|
||||||
|
implementation Deps.mozilla_service_location
|
||||||
|
|
||||||
|
|
||||||
implementation Deps.mozilla_support_base
|
implementation Deps.mozilla_support_base
|
||||||
implementation Deps.mozilla_support_ktx
|
implementation Deps.mozilla_support_ktx
|
||||||
|
@ -494,6 +519,8 @@ dependencies {
|
||||||
exclude group: 'com.android.support', module: 'support-annotations'
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
androidTestImplementation Deps.androidx_junit
|
||||||
|
androidTestImplementation Deps.androidx_work_testing
|
||||||
androidTestImplementation Deps.mockwebserver
|
androidTestImplementation Deps.mockwebserver
|
||||||
testImplementation Deps.mozilla_support_test
|
testImplementation Deps.mozilla_support_test
|
||||||
testImplementation Deps.androidx_junit
|
testImplementation Deps.androidx_junit
|
||||||
|
|
183
app/metrics.yaml
|
@ -82,7 +82,7 @@ events:
|
||||||
A string containing the name of the item the user tapped. These items include:
|
A string containing the name of the item the user tapped. These items include:
|
||||||
Settings, Library, Help, Desktop Site toggle on/off, Find in Page, New Tab,
|
Settings, Library, Help, Desktop Site toggle on/off, Find in Page, New Tab,
|
||||||
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit,
|
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit,
|
||||||
Reader Mode On, Reader Mode Off, Open In App, Add to Firefox Home
|
Reader Mode On, Reader Mode Off, Open In App, Add To Top Sites, Add-ons Manager
|
||||||
bugs:
|
bugs:
|
||||||
- https://github.com/mozilla-mobile/fenix/issues/1024
|
- https://github.com/mozilla-mobile/fenix/issues/1024
|
||||||
data_reviews:
|
data_reviews:
|
||||||
|
@ -98,10 +98,13 @@ events:
|
||||||
A counter of URIs visited by the user in the current session, including page reloads. This does not include background page requests and URIs from embedded pages or private browsing.
|
A counter of URIs visited by the user in the current session, including page reloads. This does not include background page requests and URIs from embedded pages or private browsing.
|
||||||
send_in_pings:
|
send_in_pings:
|
||||||
- baseline
|
- baseline
|
||||||
|
- metrics
|
||||||
bugs:
|
bugs:
|
||||||
- https://github.com/mozilla-mobile/fenix/issues/1301
|
- https://github.com/mozilla-mobile/fenix/issues/1301
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/4456
|
||||||
data_reviews:
|
data_reviews:
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1785
|
- https://github.com/mozilla-mobile/fenix/pull/1785
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8314
|
||||||
notification_emails:
|
notification_emails:
|
||||||
- fenix-core@mozilla.com
|
- fenix-core@mozilla.com
|
||||||
expires: "2020-09-01"
|
expires: "2020-09-01"
|
||||||
|
@ -362,20 +365,6 @@ metrics:
|
||||||
notification_emails:
|
notification_emails:
|
||||||
- fenix-core@mozilla.com
|
- fenix-core@mozilla.com
|
||||||
expires: "2020-09-01"
|
expires: "2020-09-01"
|
||||||
total_uri_count:
|
|
||||||
type: string
|
|
||||||
lifetime: application
|
|
||||||
description: >
|
|
||||||
A counter of URIs visited by the user in the current session, including page reloads. This does not include background page requests and URIs from embedded pages or private browsing.
|
|
||||||
send_in_pings:
|
|
||||||
- metrics
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issues/4456
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/6003
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-09-01"
|
|
||||||
toolbar_position:
|
toolbar_position:
|
||||||
type: string
|
type: string
|
||||||
lifetime: application
|
lifetime: application
|
||||||
|
@ -1703,3 +1692,167 @@ top_sites:
|
||||||
notification_emails:
|
notification_emails:
|
||||||
- fenix-core@mozilla.com
|
- fenix-core@mozilla.com
|
||||||
expires: "2020-09-01"
|
expires: "2020-09-01"
|
||||||
|
|
||||||
|
about_page:
|
||||||
|
support_tapped:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user tapped on "Support" item from About page
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/6834
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8047
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
privacy_notice_tapped:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user tapped on "Privacy notice" item from About page
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/6834
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8047
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
rights_tapped:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user tapped on "Know your rights" item from About page
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/6834
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8047
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
licensing_tapped:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user tapped on "Licensing information" item from About page
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/6834
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8047
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
libraries_tapped:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user tapped on "Libraries that we use" item from About page
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/6834
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8047
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
|
||||||
|
app_theme:
|
||||||
|
dark_theme_selected:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user selected Dark Theme
|
||||||
|
extra_keys:
|
||||||
|
source:
|
||||||
|
description: "The source from where dark theme was selected. The source can be 'SETTINGS' or 'ONBOARDING'"
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7289
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/7968
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
|
||||||
|
pocket:
|
||||||
|
pocket_top_site_clicked:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user clicked on the trending Pocket top site
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/8126
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8098
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
pocket_top_site_removed:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
A user removed the trending Pocket top site
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/8126
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8098
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
|
||||||
|
installation:
|
||||||
|
campaign:
|
||||||
|
type: string
|
||||||
|
send_in_pings:
|
||||||
|
- installation
|
||||||
|
description: >
|
||||||
|
The name of the campaign that is responsible for this installation.
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7295
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
network:
|
||||||
|
type: string
|
||||||
|
send_in_pings:
|
||||||
|
- installation
|
||||||
|
description: >
|
||||||
|
The name of the Network that sourced this installation.
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7295
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
adgroup:
|
||||||
|
type: string
|
||||||
|
send_in_pings:
|
||||||
|
- installation
|
||||||
|
description: >
|
||||||
|
The name of the AdGroup that was used to source this installation.
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586480836
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
creative:
|
||||||
|
send_in_pings:
|
||||||
|
- installation
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
The identifier of the creative material that the user interacted with.
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7295
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
timestamp:
|
||||||
|
send_in_pings:
|
||||||
|
- installation
|
||||||
|
type: datetime
|
||||||
|
description: >
|
||||||
|
The date and time of the installation.
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7295
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
expires: "2020-09-01"
|
||||||
|
|
|
@ -18,3 +18,14 @@ activation:
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209
|
- https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209
|
||||||
notification_emails:
|
notification_emails:
|
||||||
- fenix-core@mozilla.com
|
- fenix-core@mozilla.com
|
||||||
|
|
||||||
|
installation:
|
||||||
|
description: >
|
||||||
|
This ping is intended to capture the source of the installation
|
||||||
|
include_client_id: false
|
||||||
|
bugs:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/issues/7295
|
||||||
|
data_reviews:
|
||||||
|
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
|
||||||
|
notification_emails:
|
||||||
|
- fenix-core@mozilla.com
|
||||||
|
|
|
@ -1,16 +1,36 @@
|
||||||
<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>
|
<body>
|
||||||
|
|
||||||
<h1>
|
<p id="testContent">Page content: lorem ipsum</p>
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit,<br>
|
|
||||||
sed do eiusmod tempor incididunt ut labore et dolore magna <br>
|
<h1>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt</h1>
|
||||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation <br>
|
|
||||||
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis <br>
|
<p>
|
||||||
aute irure dolor in reprehenderit in voluptate velit esse cillum <br>
|
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
||||||
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat <br>
|
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
|
||||||
non proident, sunt in culpa qui officia deserunt mollit anim id est <br>
|
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
|
||||||
laborum.
|
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
||||||
</h1>
|
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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body aria-label="body">
|
||||||
|
|
||||||
|
<form method="GET" action="passwordsubmit.html">
|
||||||
|
<p>Username: <input id="username" type="text" value="test@example.com"></p>
|
||||||
|
<p>Password: <input id="password" type="password" value="verysecret"></p>
|
||||||
|
<p><input type="submit" id="submit" value="Login" aria-label="submit"/></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("password").value = Math.random().toString();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
</head>
|
||||||
|
<body aria-label="body">
|
||||||
|
<p>Password submitted. Nope just a test.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* 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.glean
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.service.glean.Glean
|
||||||
|
import mozilla.components.service.glean.config.Configuration
|
||||||
|
import mozilla.components.service.glean.testing.GleanTestLocalServer
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||||
|
import org.mozilla.fenix.helpers.MockWebServerHelper
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class BaselinePingTest {
|
||||||
|
private val server = MockWebServerHelper.createAlwaysOkMockWebServer()
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val activityRule: ActivityTestRule<HomeActivity> = HomeActivityTestRule()
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val gleanRule = GleanTestLocalServer(ApplicationProvider.getApplicationContext(), server.port)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun setupOnce() {
|
||||||
|
// Fenix does not initialize the Glean SDK in tests/debug builds, but this test
|
||||||
|
// requires Glean to be initialized so we need to do it manually. Additionally,
|
||||||
|
// we need to do this on the main thread, as the Glean SDK requires it.
|
||||||
|
GlobalScope.launch(Dispatchers.Main.immediate) {
|
||||||
|
Glean.initialize(
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
true,
|
||||||
|
Configuration()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun waitForPingContent(
|
||||||
|
pingName: String,
|
||||||
|
maxAttempts: Int = 3
|
||||||
|
): JSONObject? {
|
||||||
|
var attempts = 0
|
||||||
|
do {
|
||||||
|
attempts += 1
|
||||||
|
val request = server.takeRequest(20L, TimeUnit.SECONDS)
|
||||||
|
val docType = request.path.split("/")[3]
|
||||||
|
if (pingName == docType) {
|
||||||
|
return JSONObject(request.body.readUtf8())
|
||||||
|
}
|
||||||
|
} while (attempts < maxAttempts)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun validateBaselinePing() {
|
||||||
|
// Wait for the app to be idle/ready.
|
||||||
|
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||||
|
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
device.waitForIdle()
|
||||||
|
|
||||||
|
// Wait for 1 second: this should guarantee we have some valid duration in the
|
||||||
|
// ping.
|
||||||
|
Thread.sleep(1000)
|
||||||
|
|
||||||
|
// Move it to background.
|
||||||
|
device.pressHome()
|
||||||
|
|
||||||
|
// Validate the received data.
|
||||||
|
val baselinePing = waitForPingContent("baseline")!!
|
||||||
|
assertEquals("baseline", baselinePing.getJSONObject("ping_info")["ping_type"])
|
||||||
|
|
||||||
|
val metrics = baselinePing.getJSONObject("metrics")
|
||||||
|
|
||||||
|
// Make sure we have a 'duration' field with a reasonable value: it should be >= 1, since
|
||||||
|
// we slept for 1000ms.
|
||||||
|
val timespans = metrics.getJSONObject("timespan")
|
||||||
|
assertTrue(timespans.getJSONObject("glean.baseline.duration").getLong("value") >= 1L)
|
||||||
|
|
||||||
|
// Make sure there's no errors.
|
||||||
|
val errors = metrics.optJSONObject("labeled_counter")?.keys()
|
||||||
|
errors?.forEach {
|
||||||
|
assertFalse(it.startsWith("glean.error."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,14 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.helpers
|
package org.mozilla.fenix.helpers
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import org.hamcrest.CoreMatchers.not
|
import org.hamcrest.CoreMatchers.not
|
||||||
|
import org.hamcrest.Description
|
||||||
import org.hamcrest.Matcher
|
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.isChecked as espressoIsChecked
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled
|
import androidx.test.espresso.matcher.ViewMatchers.isEnabled as espressoIsEnabled
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected
|
import androidx.test.espresso.matcher.ViewMatchers.isSelected as espressoIsSelected
|
||||||
|
@ -30,3 +35,24 @@ private fun maybeInvertMatcher(matcher: Matcher<View>, useUnmodifiedMatcher: Boo
|
||||||
useUnmodifiedMatcher -> matcher
|
useUnmodifiedMatcher -> matcher
|
||||||
else -> not(matcher)
|
else -> not(matcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,20 @@ object MockWebServerHelper {
|
||||||
}
|
}
|
||||||
return uris
|
return uris
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mock webserver that accepts all requests and replies with "OK".
|
||||||
|
* @return a [MockWebServer] instance
|
||||||
|
*/
|
||||||
|
fun createAlwaysOkMockWebServer(): MockWebServer {
|
||||||
|
return MockWebServer().apply {
|
||||||
|
setDispatcher(object : Dispatcher() {
|
||||||
|
override fun dispatch(request: RecordedRequest): MockResponse {
|
||||||
|
return MockResponse().setBody("OK")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,4 +83,10 @@ object TestAssetHelper {
|
||||||
|
|
||||||
return TestAsset(url, "")
|
return TestAsset(url, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSaveLoginAsset(server: MockWebServer): TestAsset {
|
||||||
|
val url = server.url("pages/password.html").toString().toUri()!!
|
||||||
|
|
||||||
|
return TestAsset(url, "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package org.mozilla.fenix.helpers.assertions
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.test.espresso.ViewAssertion
|
||||||
|
import mozilla.components.browser.awesomebar.BrowserAwesomeBar
|
||||||
|
|
||||||
|
class AwesomeBarAssertion {
|
||||||
|
companion object {
|
||||||
|
fun suggestionsAreGreaterThan(minimumSuggestions: Int): ViewAssertion {
|
||||||
|
return ViewAssertion { view, noViewFoundException ->
|
||||||
|
if (noViewFoundException != null) throw noViewFoundException
|
||||||
|
|
||||||
|
val suggestionsCount = getSuggestionCountFromView(view)
|
||||||
|
|
||||||
|
if (suggestionsCount <= minimumSuggestions)
|
||||||
|
throw AssertionError("The suggestion count is less than or equal to the minimum suggestions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun suggestionsAreEqualTo(expectedItemCount: Int): ViewAssertion {
|
||||||
|
return ViewAssertion { view, noViewFoundException ->
|
||||||
|
if (noViewFoundException != null) throw noViewFoundException
|
||||||
|
|
||||||
|
val suggestionsCount = getSuggestionCountFromView(view)
|
||||||
|
|
||||||
|
if (suggestionsCount != expectedItemCount)
|
||||||
|
throw AssertionError("The expected item count is $expectedItemCount, and the suggestions count within the AwesomeBar is $suggestionsCount")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSuggestionCountFromView(view: View): Int {
|
||||||
|
return (view as BrowserAwesomeBar).adapter?.itemCount
|
||||||
|
?: throw AssertionError("This view is not of type BrowserAwesomeBar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.mozilla.fenix.helpers.matchers
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.test.espresso.matcher.BoundedMatcher
|
||||||
|
import org.hamcrest.Description
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.graphics.drawable.StateListDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
|
||||||
|
class BitmapDrawableMatcher(private val bitmap: Bitmap, private val name: String) :
|
||||||
|
BoundedMatcher<View, ImageView>(ImageView::class.java) {
|
||||||
|
|
||||||
|
override fun describeTo(description: Description?) {
|
||||||
|
description?.appendText("has image drawable resource $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun matchesSafely(item: ImageView): Boolean {
|
||||||
|
return sameBitmap(item.drawable, bitmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sameBitmap(drawable: Drawable?, otherBitmap: Bitmap): Boolean {
|
||||||
|
var currentDrawable = drawable ?: return false
|
||||||
|
|
||||||
|
if (currentDrawable is StateListDrawable) {
|
||||||
|
currentDrawable = currentDrawable.current
|
||||||
|
}
|
||||||
|
if (currentDrawable is BitmapDrawable) {
|
||||||
|
val bitmap = currentDrawable.bitmap
|
||||||
|
return bitmap.sameAs(otherBitmap)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.mozilla.fenix.helpers.matchers
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.test.espresso.matcher.BoundedMatcher
|
||||||
|
import org.hamcrest.Description
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
|
||||||
|
fun hasItem(matcher: Matcher<View?>): Matcher<View?>? {
|
||||||
|
return object : BoundedMatcher<View?, RecyclerView>(RecyclerView::class.java) {
|
||||||
|
override fun describeTo(description: Description) {
|
||||||
|
description.appendText("has item: ")
|
||||||
|
matcher.describeTo(description)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||||
|
val adapter = view.adapter
|
||||||
|
for (position in 0 until adapter!!.itemCount) {
|
||||||
|
val type = adapter.getItemViewType(position)
|
||||||
|
val holder = adapter.createViewHolder(view, type)
|
||||||
|
adapter.onBindViewHolder(holder, position)
|
||||||
|
if (matcher.matches(holder.itemView)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -206,7 +206,7 @@ fun settingsAccountPreferences() = onView(withText(R.string.preferences_sync)).c
|
||||||
|
|
||||||
fun settingsSearch() = onView(withText(R.string.preferences_search)).click()
|
fun settingsSearch() = onView(withText(R.string.preferences_search)).click()
|
||||||
|
|
||||||
fun settingsTheme() = onView(withText(R.string.preferences_theme)).click()
|
fun settingsTheme() = onView(withText(R.string.preferences_customize)).click()
|
||||||
|
|
||||||
fun settingsAccessibility() = onView(withText(R.string.preferences_accessibility)).click()
|
fun settingsAccessibility() = onView(withText(R.string.preferences_accessibility)).click()
|
||||||
|
|
||||||
|
|
|
@ -9,35 +9,54 @@ import android.widget.EditText
|
||||||
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions.click
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.action.ViewActions.replaceText
|
|
||||||
import androidx.test.espresso.action.ViewActions.pressImeActionButton
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
|
||||||
import org.mozilla.fenix.ui.robots.accountSettings
|
|
||||||
import org.mozilla.fenix.ui.robots.settingsSubMenuLoginsAndPassword
|
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import androidx.test.uiautomator.UiSelector
|
import androidx.test.uiautomator.UiSelector
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.Until
|
import androidx.test.uiautomator.Until
|
||||||
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.hamcrest.Matchers.allOf
|
import org.hamcrest.Matchers.allOf
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
|
import org.mozilla.fenix.helpers.ext.toUri
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
|
import org.mozilla.fenix.ui.robots.homeScreen
|
||||||
|
import org.mozilla.fenix.ui.robots.accountSettings
|
||||||
|
import org.mozilla.fenix.ui.robots.settingsSubMenuLoginsAndPassword
|
||||||
|
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
|
import org.mozilla.fenix.ui.robots.browserScreen
|
||||||
|
|
||||||
@Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
|
@Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
|
||||||
class SyncIntegrationTest {
|
class SyncIntegrationTest {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
private lateinit var mockWebServer: MockWebServer
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val activityTestRule = HomeActivityTestRule()
|
val activityTestRule = HomeActivityTestRule()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
mockWebServer = MockWebServer().apply {
|
||||||
|
setDispatcher(AndroidAssetDispatcher())
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
mockWebServer.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
// History item Desktop -> Fenix
|
// History item Desktop -> Fenix
|
||||||
@Test
|
@Test
|
||||||
fun checkHistoryFromDesktopTest() {
|
fun checkHistoryFromDesktopTest() {
|
||||||
|
@ -82,6 +101,7 @@ class SyncIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Login item Desktop -> Fenix
|
||||||
@Test
|
@Test
|
||||||
fun checkLoginsFromDesktopTest() {
|
fun checkLoginsFromDesktopTest() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
|
@ -113,30 +133,46 @@ class SyncIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These tests will be running in the future
|
// Bookmark item Fenix -> Desktop
|
||||||
// once the test above runs successfully and
|
@Test
|
||||||
// the environment is stable
|
fun checkBookmarkFromDeviceTest() {
|
||||||
|
val defaultWebPage = "example.com".toUri()!!
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage) {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
verifyAddBookmarkButton()
|
||||||
|
clickAddBookmarkButton()
|
||||||
|
}
|
||||||
|
browserScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openTurnOnSyncMenu {
|
||||||
|
useEmailInsteadButton()
|
||||||
|
typeEmail()
|
||||||
|
tapOnContinueButton()
|
||||||
|
typePassword()
|
||||||
|
sleep(TestAssetHelper.waitingTimeShort)
|
||||||
|
tapOnSignIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// History item Fenix -> Desktop
|
// History item Fenix -> Desktop
|
||||||
@Test
|
@Test
|
||||||
fun checkBookmarkFromDeviceTest() {
|
|
||||||
tapInToolBar()
|
|
||||||
typeInToolBar()
|
|
||||||
seeBookmark()
|
|
||||||
mDevice.pressBack()
|
|
||||||
signInFxSync()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bookmark item Fenix -> Desktop
|
|
||||||
@Test
|
|
||||||
fun checkHistoryFromDeviceTest() {
|
fun checkHistoryFromDeviceTest() {
|
||||||
tapInToolBar()
|
val defaultWebPage = "example.com".toUri()!!
|
||||||
typeInToolBar()
|
navigationToolbar {
|
||||||
sleep(TestAssetHelper.waitingTime)
|
}.enterURLAndEnterToBrowser(defaultWebPage) {
|
||||||
mDevice.pressBack()
|
}.openThreeDotMenu {
|
||||||
signInFxSync()
|
}.openSettings {
|
||||||
|
}.openTurnOnSyncMenu {
|
||||||
|
useEmailInsteadButton()
|
||||||
|
typeEmail()
|
||||||
|
tapOnContinueButton()
|
||||||
|
typePassword()
|
||||||
|
sleep(TestAssetHelper.waitingTimeShort)
|
||||||
|
tapOnSignIn()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Useful functions for the tests
|
// Useful functions for the tests
|
||||||
fun typeEmail() {
|
fun typeEmail() {
|
||||||
|
@ -170,11 +206,6 @@ class SyncIntegrationTest {
|
||||||
mDevice.pressEnter()
|
mDevice.pressEnter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun typeInToolBar() {
|
|
||||||
awesomeBar().perform(replaceText("example.com"),
|
|
||||||
pressImeActionButton())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun historyAfterSyncIsShown() {
|
fun historyAfterSyncIsShown() {
|
||||||
val historyEntry = mDevice.findObject(By.text("http://www.example.com/"))
|
val historyEntry = mDevice.findObject(By.text("http://www.example.com/"))
|
||||||
historyEntry.isEnabled()
|
historyEntry.isEnabled()
|
||||||
|
@ -185,12 +216,6 @@ class SyncIntegrationTest {
|
||||||
bookmarkEntry.isEnabled()
|
bookmarkEntry.isEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun seeBookmark() {
|
|
||||||
mDevice.waitNotNull(Until.findObjects(By.text("Bookmark")), TestAssetHelper.waitingTime)
|
|
||||||
val bookmarkButton = mDevice.findObject(By.text("Bookmark"))
|
|
||||||
bookmarkButton.click()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun tapReturnToPreviousApp() {
|
fun tapReturnToPreviousApp() {
|
||||||
mDevice.waitNotNull(Until.findObjects(By.text("Settings")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(Until.findObjects(By.text("Settings")), TestAssetHelper.waitingTime)
|
||||||
mDevice.pressBack()
|
mDevice.pressBack()
|
||||||
|
@ -218,7 +243,5 @@ class SyncIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun settingsAccount() = onView(allOf(withText("Turn on Sync"))).perform(click())
|
fun settingsAccount() = onView(allOf(withText("Turn on Sync"))).perform(click())
|
||||||
fun tapInToolBar() = onView(withId(R.id.toolbar_wrapper))
|
|
||||||
fun awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
|
|
||||||
fun useEmailInsteadButton() = onView(withId(R.id.signInEmailButton)).perform(click())
|
fun useEmailInsteadButton() = onView(withId(R.id.signInEmailButton)).perform(click())
|
||||||
fun enterAccountSettings() = onView(withId(R.id.email)).perform(click())
|
fun enterAccountSettings() = onView(withId(R.id.email)).perform(click())
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of phases mapped to their corresponding profiles. The object
|
||||||
|
* here must be in strict JSON format, as it will get parsed by the Python
|
||||||
|
* testrunner (no single quotes, extra comma's, etc).
|
||||||
|
*/
|
||||||
|
EnableEngines(["bookmarks"]);
|
||||||
|
|
||||||
|
var phases = { "phase1": "profile1" };
|
||||||
|
|
||||||
|
|
||||||
|
// expected bookmark state
|
||||||
|
var bookmarksExpected = {
|
||||||
|
"mobile": [{
|
||||||
|
uri: "http://www.example.com/",
|
||||||
|
title: "Example Domain"}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// sync and verify bookmarks
|
||||||
|
Phase("phase1", [
|
||||||
|
[Sync],
|
||||||
|
[Bookmarks.verify, bookmarksExpected],
|
||||||
|
]);
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of phases mapped to their corresponding profiles. The object
|
||||||
|
* here must be in strict JSON format, as it will get parsed by the Python
|
||||||
|
* testrunner (no single quotes, extra comma's, etc).
|
||||||
|
*/
|
||||||
|
EnableEngines(["history"]);
|
||||||
|
|
||||||
|
var phases = { "phase1": "profile1" };
|
||||||
|
|
||||||
|
|
||||||
|
// expected history state
|
||||||
|
var historyExpected = [
|
||||||
|
{ uri: "http://www.example.com/",
|
||||||
|
visits: [
|
||||||
|
{ type: 1 },
|
||||||
|
{ type: 2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// sync and verify history
|
||||||
|
Phase("phase1", [
|
||||||
|
[Sync],
|
||||||
|
[History.verify, historyExpected]
|
||||||
|
]);
|
|
@ -10,12 +10,14 @@ def test_sync_history_from_desktop(tps, gradlewbuild):
|
||||||
tps.run('test_history.js')
|
tps.run('test_history.js')
|
||||||
gradlewbuild.test('checkHistoryFromDesktopTest')
|
gradlewbuild.test('checkHistoryFromDesktopTest')
|
||||||
|
|
||||||
def test_sync_bookmark_from_device(tps, gradlewbuild):
|
def test_sync_bookmark_from_desktop(tps, gradlewbuild):
|
||||||
os.chdir('app/src/androidTest/java/org/mozilla/fenix/syncintegration/')
|
|
||||||
tps.run('test_bookmark.js')
|
tps.run('test_bookmark.js')
|
||||||
gradlewbuild.test('checkBookmarkFromDesktopTest')
|
gradlewbuild.test('checkBookmarkFromDesktopTest')
|
||||||
|
|
||||||
def test_sync_logins_from_device(tps, gradlewbuild):
|
def test_sync_logins_from_device(tps, gradlewbuild):
|
||||||
os.chdir('app/src/androidTest/java/org/mozilla/fenix/syncintegration/')
|
|
||||||
tps.run('test_logins.js')
|
tps.run('test_logins.js')
|
||||||
gradlewbuild.test('checkLoginsFromDesktopTest')
|
gradlewbuild.test('checkLoginsFromDesktopTest')
|
||||||
|
|
||||||
|
def test_sync_bookmark_from_device(tps, gradlewbuild):
|
||||||
|
gradlewbuild.test('checkBookmarkFromDeviceTest')
|
||||||
|
tps.run('test_bookmark_desktop.js')
|
||||||
|
|
|
@ -11,6 +11,7 @@ import mozilla.appservices.places.BookmarkRoot
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.ext.bookmarkStorage
|
import org.mozilla.fenix.ext.bookmarkStorage
|
||||||
|
@ -103,6 +104,7 @@ class BookmarksTest {
|
||||||
verifyKeyboardVisible()
|
verifyKeyboardVisible()
|
||||||
addNewFolderName(bookmarksFolderName)
|
addNewFolderName(bookmarksFolderName)
|
||||||
saveNewFolder()
|
saveNewFolder()
|
||||||
|
getInstrumentation().waitForIdleSync()
|
||||||
verifyFolderTitle(bookmarksFolderName)
|
verifyFolderTitle(bookmarksFolderName)
|
||||||
verifyKeyboardHidden()
|
verifyKeyboardHidden()
|
||||||
}
|
}
|
||||||
|
@ -268,6 +270,7 @@ class BookmarksTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Temp disable: Nexus 6 failures - issue: https://github.com/mozilla-mobile/fenix/issues/7417")
|
||||||
@Test
|
@Test
|
||||||
fun deleteMultipleSelectionTest() {
|
fun deleteMultipleSelectionTest() {
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
@ -314,6 +317,7 @@ class BookmarksTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Temp disable: Nexus 6 failures - issue: https://github.com/mozilla-mobile/fenix/issues/7417")
|
||||||
@Test
|
@Test
|
||||||
fun multipleBookmarkDeletions() {
|
fun multipleBookmarkDeletions() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
|
|
|
@ -53,6 +53,7 @@ class ContextMenusTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("Disabling because of intermittent failures https://github.com/mozilla-mobile/fenix/issues/8663")
|
||||||
fun verifyContextOpenLinkNewTab() {
|
fun verifyContextOpenLinkNewTab() {
|
||||||
val pageLinks =
|
val pageLinks =
|
||||||
TestAssetHelper.getGenericAsset(mockWebServer, 4)
|
TestAssetHelper.getGenericAsset(mockWebServer, 4)
|
||||||
|
@ -112,7 +113,7 @@ class ContextMenusTest {
|
||||||
clickContextCopyLink()
|
clickContextCopyLink()
|
||||||
verifySnackBarText("Link copied to clipboard")
|
verifySnackBarText("Link copied to clipboard")
|
||||||
}.openNavigationToolbar {
|
}.openNavigationToolbar {
|
||||||
}.visitLinkFromClipboard(genericURL.url) {
|
}.visitLinkFromClipboard {
|
||||||
verifyUrl(genericURL.url.toString())
|
verifyUrl(genericURL.url.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +170,7 @@ class ContextMenusTest {
|
||||||
clickContextCopyImageLocation()
|
clickContextCopyImageLocation()
|
||||||
verifySnackBarText("Link copied to clipboard")
|
verifySnackBarText("Link copied to clipboard")
|
||||||
}.openNavigationToolbar {
|
}.openNavigationToolbar {
|
||||||
}.visitLinkFromClipboard(imageResource.url) {
|
}.visitLinkFromClipboard {
|
||||||
verifyUrl(imageResource.url.toString())
|
verifyUrl(imageResource.url.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,6 @@ class HomeScreenTest {
|
||||||
verifyHomeWordmark()
|
verifyHomeWordmark()
|
||||||
verifyAddTabButton()
|
verifyAddTabButton()
|
||||||
verifyShareTabsButton(visible = false)
|
verifyShareTabsButton(visible = false)
|
||||||
verifyCloseTabsButton(visible = false)
|
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateSessionHeader()
|
||||||
verifyPrivateSessionMessage(visible = true)
|
verifyPrivateSessionMessage(visible = true)
|
||||||
verifyHomeToolbar()
|
verifyHomeToolbar()
|
||||||
|
@ -130,7 +129,6 @@ class HomeScreenTest {
|
||||||
verifyHomeWordmark()
|
verifyHomeWordmark()
|
||||||
verifyAddTabButton()
|
verifyAddTabButton()
|
||||||
verifyShareTabsButton(visible = true)
|
verifyShareTabsButton(visible = true)
|
||||||
verifyCloseTabsButton(visible = true)
|
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateSessionHeader()
|
||||||
verifyPrivateSessionMessage(visible = false)
|
verifyPrivateSessionMessage(visible = false)
|
||||||
verifyHomeToolbar()
|
verifyHomeToolbar()
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
/* 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,11 +52,11 @@ class SearchTest {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
}.openSearch {
|
}.openSearch {
|
||||||
verifySearchWithText()
|
verifySearchWithText()
|
||||||
clickDuckDuckGoEngineButton()
|
clickSearchEngineButton("DuckDuckGo")
|
||||||
typeSearch("mozilla")
|
typeSearch("mozilla")
|
||||||
verifyDuckDuckGoResults()
|
verifySearchEngineResults("DuckDuckGo")
|
||||||
clickDuckDuckGoResult()
|
clickSearchEngineResult("DuckDuckGo")
|
||||||
verifyDuckDuckGoURL()
|
verifySearchEngineURL("DuckDuckGo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,17 @@ import androidx.test.uiautomator.UiDevice
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.Ignore
|
||||||
|
import org.mozilla.fenix.FenixApplication
|
||||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||||
|
import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset
|
||||||
|
import org.mozilla.fenix.helpers.TestAssetHelper.getLoremIpsumAsset
|
||||||
|
import org.mozilla.fenix.ui.robots.checkTextSizeOnWebsite
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
import org.mozilla.fenix.ui.robots.homeScreen
|
||||||
|
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for verifying the main three dot menu options
|
* Tests for verifying the main three dot menu options
|
||||||
|
@ -29,7 +34,7 @@ class SettingsBasicsTest {
|
||||||
private lateinit var mockWebServer: MockWebServer
|
private lateinit var mockWebServer: MockWebServer
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val activityTestRule = HomeActivityTestRule()
|
val activityIntentTestRule = HomeActivityIntentTestRule()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
@ -45,7 +50,8 @@ class SettingsBasicsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUiTheme(): Boolean {
|
private fun getUiTheme(): Boolean {
|
||||||
val mode = activityTestRule.activity.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK)
|
val mode =
|
||||||
|
activityIntentTestRule.activity.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK)
|
||||||
|
|
||||||
return when (mode) {
|
return when (mode) {
|
||||||
Configuration.UI_MODE_NIGHT_YES -> true // dark theme is set
|
Configuration.UI_MODE_NIGHT_YES -> true // dark theme is set
|
||||||
|
@ -68,15 +74,16 @@ class SettingsBasicsTest {
|
||||||
verifySearchEngineList()
|
verifySearchEngineList()
|
||||||
verifyShowSearchSuggestions()
|
verifyShowSearchSuggestions()
|
||||||
verifyShowSearchShortcuts()
|
verifyShowSearchShortcuts()
|
||||||
|
|
||||||
verifyShowClipboardSuggestions()
|
verifyShowClipboardSuggestions()
|
||||||
verifySearchBrowsingHistory()
|
verifySearchBrowsingHistory()
|
||||||
verifySearchBookmarks()
|
verifySearchBookmarks()
|
||||||
}.goBack {
|
}.goBack {
|
||||||
}.openThemeSubMenu {
|
}.openCustomizeSubMenu {
|
||||||
verifyThemes()
|
verifyThemes()
|
||||||
}.goBack {
|
}.goBack {
|
||||||
}.openAccessibilitySubMenu {
|
}.openAccessibilitySubMenu {
|
||||||
verifyAutomaticFontSizing()
|
verifyAutomaticFontSizingMenuItems()
|
||||||
}.goBack {
|
}.goBack {
|
||||||
// drill down to submenu
|
// drill down to submenu
|
||||||
}.openDefaultBrowserSubMenu {
|
}.openDefaultBrowserSubMenu {
|
||||||
|
@ -86,53 +93,79 @@ class SettingsBasicsTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
@Test
|
||||||
fun selectNewDefaultSearchEngine() {
|
fun selectNewDefaultSearchEngine() {
|
||||||
// Open 3dot (main) menu
|
// Goes through the settings and changes the default search engine, then verifies it has changed.
|
||||||
// Select settings
|
homeScreen {
|
||||||
// Select "Search engine"
|
}.openThreeDotMenu {
|
||||||
// Choose: DuckDuckGo
|
}.openSettings {
|
||||||
// Back arrow to Home
|
}.openSearchSubMenu {
|
||||||
// Verify DuckDuckGo icon in Navigation bar
|
changeDefaultSearchEngine("DuckDuckGo")
|
||||||
|
}.goBack {
|
||||||
|
}.goBack {
|
||||||
|
verifyDefaultSearchEngine("DuckDuckGo")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
@Ignore("This test works locally, fails on firebase. https://github.com/mozilla-mobile/fenix/issues/8174")
|
||||||
@Test
|
@Test
|
||||||
fun toggleSearchSuggestions() {
|
fun toggleSearchSuggestions() {
|
||||||
// Enter: "mozilla" in navigation bar
|
// Goes through the settings and changes the search suggestion toggle, then verifies it changes.
|
||||||
// Verify more than one suggesion provided
|
homeScreen {
|
||||||
// Open 3dot (main) menu
|
}.openNavigationToolbar {
|
||||||
// Select settings
|
verifySearchSuggestionsAreMoreThan(1, "mozilla")
|
||||||
// Select "Search engine"
|
}.goBack {
|
||||||
// Toggle 'Show search suggestions' to 'off'
|
}.openThreeDotMenu {
|
||||||
// Back arrow twice to home screen
|
}.openSettings {
|
||||||
// Enter: "mozilla" in navigation bar
|
}.openSearchSubMenu {
|
||||||
// Verify no suggestions provided
|
disableShowSearchSuggestions()
|
||||||
|
}.goBack {
|
||||||
|
}.goBack {
|
||||||
|
}.openNavigationToolbar {
|
||||||
|
verifySearchSuggestionsAreEqualTo(0, "mozilla")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleShowVisitedSitesAndBookmarks() {
|
fun toggleShowVisitedSitesAndBookmarks() {
|
||||||
// Visit 3 static sites
|
// Bookmarks a few websites, toggles the history and bookmarks setting to off, then verifies if the visited and bookmarked websites do not show in the suggestions.
|
||||||
// Bookmark 2 of them
|
val page1 = getGenericAsset(mockWebServer, 1)
|
||||||
// Open 3dot (main) menu
|
val page2 = getGenericAsset(mockWebServer, 2)
|
||||||
// Enter navigation bar and verify visited sites appear
|
val page3 = getGenericAsset(mockWebServer, 3)
|
||||||
// Verify bookmarks exist
|
|
||||||
// Open 3dot (main) menu
|
homeScreen {
|
||||||
// Select settings
|
}.openNavigationToolbar {
|
||||||
// Select "Search engine"
|
}.enterURLAndEnterToBrowser(page1.url) {
|
||||||
// Toggle off "Show visited sites and bookmarks"
|
verifyPageContent(page1.content)
|
||||||
// Back arrow twice to home screen
|
}.openThreeDotMenu {
|
||||||
// Verify history and bookmarks are gone
|
clickAddBookmarkButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(page2.url) {
|
||||||
|
verifyPageContent(page2.content)
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
clickAddBookmarkButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(page3.url) {
|
||||||
|
verifyPageContent(page3.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
verifyNoHistoryBookmarks()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun changeThemeSetting() {
|
fun changeThemeSetting() {
|
||||||
|
// Goes through the settings and changes the default search engine, then verifies it changes.
|
||||||
homeScreen {
|
homeScreen {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openSettings {
|
}.openSettings {
|
||||||
}.openThemeSubMenu {
|
}.openCustomizeSubMenu {
|
||||||
verifyThemes()
|
verifyThemes()
|
||||||
selectDarkMode()
|
selectDarkMode()
|
||||||
verifyDarkThemeApplied(getUiTheme())
|
verifyDarkThemeApplied(getUiTheme())
|
||||||
|
@ -141,40 +174,48 @@ class SettingsBasicsTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
@Test
|
||||||
fun changeAccessibiltySettings() {
|
fun changeAccessibiltySettings() {
|
||||||
// Open 3dot (main) menu
|
// Goes through the settings and changes the default text on a webpage, then verifies if the text has changed.
|
||||||
// Select settings
|
val fenixApp = activityIntentTestRule.activity.applicationContext as FenixApplication
|
||||||
// Select Accessibility
|
val webpage = getLoremIpsumAsset(mockWebServer).url
|
||||||
// Verify header: "Automatic Font Sizing"
|
|
||||||
// Verify description: "Font size will match your Android settings. Disable to manage font size here"
|
// This value will represent the text size percentage the webpage will scale to. The default value is 100%.
|
||||||
// Verify toggle is set to 'on' by default
|
val textSizePercentage = 180
|
||||||
// Toggle font size to off
|
|
||||||
// Verify that new sub-menu items appear....
|
homeScreen {
|
||||||
// Verify header: "Font Size"
|
}.openThreeDotMenu {
|
||||||
// Verify description: "Make text on websites larger or smaller"
|
}.openSettings {
|
||||||
// Verify slider bar exists
|
}.openAccessibilitySubMenu {
|
||||||
// Verify slider bar default value set to 100%
|
clickFontSizingSwitch()
|
||||||
// Verify sample text "The quick brown fox..." appears 4 times
|
verifyNewMenuItems()
|
||||||
// Move slider bar to 180%
|
changeTextSizeSlider(textSizePercentage)
|
||||||
// Verify that text grows to 180%
|
verifyTextSizePercentage(textSizePercentage)
|
||||||
// Back error twice to home screen
|
}.goBack {
|
||||||
// Open static website in navigation bar
|
}.goBack {
|
||||||
// Verify that text is now at 180%
|
}.openNavigationToolbar {
|
||||||
// Select settings
|
}.enterURLAndEnterToBrowser(webpage) {
|
||||||
// Select Accessibility
|
checkTextSizeOnWebsite(textSizePercentage, fenixApp.components)
|
||||||
// Toggle font size back to 'off'
|
}.openHomeScreen {
|
||||||
// Verify that "Font Size" header, description, slider bar and sample text all disappear
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openAccessibilitySubMenu {
|
||||||
|
clickFontSizingSwitch()
|
||||||
|
verifyNewMenuItemsAreGone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
@Test
|
||||||
fun changeDefaultBrowserSetting() {
|
fun changeDefaultBrowserSetting() {
|
||||||
// Open 3dot (main) menu
|
// Opens settings and toggles the default browser setting to on. The device settings open and allows the user to set a default browser.
|
||||||
// Select settings
|
homeScreen {
|
||||||
// Verify that "Set as default browser toggle is set to 'off' (default)
|
}.openThreeDotMenu {
|
||||||
// Turn default browser toggle 'on'
|
}.openSettings {
|
||||||
// Verify that Andrdoid "Default Apps" menu appears
|
}.openDefaultBrowserSubMenu {
|
||||||
|
verifyDefaultBrowserIsDisabled()
|
||||||
|
clickDefaultBrowserSwitch()
|
||||||
|
verifyAndroidDefaultAppsMenuAppears()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||||
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
import org.mozilla.fenix.helpers.TestHelper
|
import org.mozilla.fenix.helpers.TestHelper
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
import org.mozilla.fenix.ui.robots.homeScreen
|
||||||
|
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for verifying the main three dot menu options
|
* Tests for verifying the main three dot menu options
|
||||||
|
@ -133,6 +135,65 @@ class SettingsPrivacyTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveLoginFromPromptTest() {
|
||||||
|
val saveLoginTest =
|
||||||
|
TestAssetHelper.getSaveLoginAsset(mockWebServer)
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(saveLoginTest.url) {
|
||||||
|
verifySaveLoginPromptIsShown()
|
||||||
|
// Click save to save the login
|
||||||
|
saveLoginFromPrompt("Save")
|
||||||
|
}.openHomeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
TestHelper.scrollToElementByText("Logins and passwords")
|
||||||
|
}.openLoginsAndPasswordSubMenu {
|
||||||
|
verifyDefaultView()
|
||||||
|
verifyDefaultValueSyncLogins()
|
||||||
|
}.openSavedLogins {
|
||||||
|
verifySavedLoginsView()
|
||||||
|
tapSetupLater()
|
||||||
|
// Verify that the login appears correctly
|
||||||
|
verifySavedLoginFromPrompt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun doNotSaveLoginFromPromptTest() {
|
||||||
|
val saveLoginTest = TestAssetHelper.getSaveLoginAsset(mockWebServer)
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(saveLoginTest.url) {
|
||||||
|
verifySaveLoginPromptIsShown()
|
||||||
|
// Don't save the login
|
||||||
|
saveLoginFromPrompt("Don’t save")
|
||||||
|
}.openHomeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openLoginsAndPasswordSubMenu {
|
||||||
|
verifyDefaultView()
|
||||||
|
verifyDefaultValueSyncLogins()
|
||||||
|
}.openSavedLogins {
|
||||||
|
verifySavedLoginsView()
|
||||||
|
tapSetupLater()
|
||||||
|
// Verify that the login list is empty
|
||||||
|
verifyNotSavedLoginFromPromt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveLoginsAndPasswordsOptions() {
|
||||||
|
homeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openLoginsAndPasswordSubMenu {
|
||||||
|
}.saveLoginsAndPasswordsOptions {
|
||||||
|
verifySaveLoginsOptionsView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
@Ignore("This is a stub test, ignore for now")
|
||||||
@Test
|
@Test
|
||||||
fun toggleTrackingProtection() {
|
fun toggleTrackingProtection() {
|
||||||
|
|
|
@ -28,8 +28,10 @@ import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
* - Opening a private tab
|
* - Opening a private tab
|
||||||
* - Verifying tab list
|
* - Verifying tab list
|
||||||
* - Closing all tabs
|
* - Closing all tabs
|
||||||
|
* - Close tab
|
||||||
|
* - Swipe to close tab
|
||||||
|
* - Undo close tab
|
||||||
*
|
*
|
||||||
* TODO: Tab Collections
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TabbedBrowsingTest {
|
class TabbedBrowsingTest {
|
||||||
|
@ -76,7 +78,10 @@ class TabbedBrowsingTest {
|
||||||
|
|
||||||
homeScreen {
|
homeScreen {
|
||||||
// Timing issue on slow devices on Firebase
|
// Timing issue on slow devices on Firebase
|
||||||
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(
|
||||||
|
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
|
|
||||||
}.openTabsListThreeDotMenu {
|
}.openTabsListThreeDotMenu {
|
||||||
|
@ -106,10 +111,13 @@ class TabbedBrowsingTest {
|
||||||
verifyTabCounter("1")
|
verifyTabCounter("1")
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
// Timing issue on slow devices on Firebase
|
// Timing issue on slow devices on Firebase
|
||||||
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(
|
||||||
|
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyShareTabsButton(true)
|
verifyShareTabsButton(true)
|
||||||
verifyCloseTabsButton(true)
|
verifyCloseTabsButton("Test_Page_1")
|
||||||
}.togglePrivateBrowsingMode()
|
}.togglePrivateBrowsingMode()
|
||||||
|
|
||||||
// Verify private tabs remain in private browsing mode
|
// Verify private tabs remain in private browsing mode
|
||||||
|
@ -135,7 +143,10 @@ class TabbedBrowsingTest {
|
||||||
|
|
||||||
homeScreen {
|
homeScreen {
|
||||||
// Timing issue on slow devices on Firebase
|
// Timing issue on slow devices on Firebase
|
||||||
mDevice.waitNotNull(Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(
|
||||||
|
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
}.openTabsListThreeDotMenu {
|
}.openTabsListThreeDotMenu {
|
||||||
verifyCloseAllTabsButton()
|
verifyCloseAllTabsButton()
|
||||||
|
@ -147,5 +158,59 @@ class TabbedBrowsingTest {
|
||||||
verifyNoTabsOpenedHeader()
|
verifyNoTabsOpenedHeader()
|
||||||
verifyNoTabsOpenedText()
|
verifyNoTabsOpenedText()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeat for Private Tabs
|
||||||
|
homeScreen {
|
||||||
|
}.togglePrivateBrowsingMode()
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
}.openHomeScreen { }
|
||||||
|
|
||||||
|
homeScreen {
|
||||||
|
// Timing issue on slow devices on Firebase
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
|
verifyExistingTabList()
|
||||||
|
verifyPrivateTabsCloseTabsButton()
|
||||||
|
}.closeAllPrivateTabs {
|
||||||
|
verifyPrivateSessionHeader()
|
||||||
|
verifyPrivateSessionMessage(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun closeTabTest() {
|
||||||
|
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
||||||
|
|
||||||
|
genericURLS.forEachIndexed { index, element ->
|
||||||
|
navigationToolbar {
|
||||||
|
}.openNewTabAndEnterToBrowser(element.url) {
|
||||||
|
verifyPageContent(element.content)
|
||||||
|
}.openHomeScreen { }
|
||||||
|
|
||||||
|
homeScreen {
|
||||||
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
closeTabViaXButton("Test_Page_${index + 1}")
|
||||||
|
verifySnackBarText("Tab closed")
|
||||||
|
snackBarButtonClick("UNDO")
|
||||||
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
swipeTabRight("Test_Page_${index + 1}")
|
||||||
|
verifySnackBarText("Tab closed")
|
||||||
|
snackBarButtonClick("UNDO")
|
||||||
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
swipeTabLeft("Test_Page_${index + 1}")
|
||||||
|
verifySnackBarText("Tab closed")
|
||||||
|
snackBarButtonClick("UNDO")
|
||||||
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
/* 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.Ignore
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.After
|
|
||||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
|
||||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for verifying basic functionality of tabs
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TabsTest {
|
|
||||||
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
|
|
||||||
|
|
||||||
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
|
||||||
private lateinit var mockWebServer: MockWebServer
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val activityTestRule = HomeActivityTestRule()
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
mockWebServer = MockWebServer().apply {
|
|
||||||
setDispatcher(AndroidAssetDispatcher())
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun tearDown() {
|
|
||||||
mockWebServer.shutdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
|
||||||
fun tabsItemsTest() {
|
|
||||||
homeScreen { }.dismissOnboarding()
|
|
||||||
|
|
||||||
// Setup browser so that tabs are visible in UI
|
|
||||||
// Verify all tabs elements are visible:
|
|
||||||
// "open tabs header, + button, etc.
|
|
||||||
// Verify tabs 3-dot menu elements
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
|
||||||
fun noTabsInCacheTest() {
|
|
||||||
// Verify open tabs header and text exists (when no previous browsing)
|
|
||||||
// Verify + button redirects to navigation bar UI
|
|
||||||
// Verify "Collections" header exists
|
|
||||||
// Verify "No collections" text (when no previous browsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
|
||||||
fun browsingWithTabsTest() {
|
|
||||||
// Setup:
|
|
||||||
// - Verify + button redirects to navigation bar UI
|
|
||||||
// - Enter mock website via navigation bar
|
|
||||||
// Verify "Open tabs" header exits
|
|
||||||
// Verify Collections header exits
|
|
||||||
// Verify that tabs counter is augmented by 1 count
|
|
||||||
// Click on tabs counter
|
|
||||||
// Verify that new page is listed in "Open tabs"
|
|
||||||
// Repeat for several sites
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
|
||||||
fun tabsThreeDotMenuTest() {
|
|
||||||
// short 3-dot menu setup:
|
|
||||||
// - create multiple tabs (using mock web server) for the following...
|
|
||||||
// Verify tabs 3-dot menu functions:
|
|
||||||
// 1. "Close all tabs"
|
|
||||||
// 2. "Share tabs" - opens share sub-menu
|
|
||||||
// 3. "Save to collection" - verify saved to collection
|
|
||||||
|
|
||||||
// NOTE: extended 3 dot menu test is verified in a separate class
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a stub test, ignore for now")
|
|
||||||
@Test
|
|
||||||
fun collectionsTest() {
|
|
||||||
// Setup:
|
|
||||||
// - create multiple tabs (using mock web server) for the following...
|
|
||||||
// Verify collections header exits
|
|
||||||
// Verify multiple collections can be saved, named
|
|
||||||
// Verify "Select tabs to save"
|
|
||||||
// Verify collections dropdown toggle
|
|
||||||
// Verify send and share button works - opens share menu
|
|
||||||
|
|
||||||
// Verify collections 3-dot menu functions:
|
|
||||||
// 1. Delete collection
|
|
||||||
// 2. Rename collection
|
|
||||||
// 3. Open tabs
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This is a sample test, ignore")
|
|
||||||
@Test
|
|
||||||
fun sampleTest() {
|
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/* 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.homeScreen
|
||||||
|
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests Top Sites functionality
|
||||||
|
*
|
||||||
|
* - Verifies 'Add to Firefox Home' UI functionality
|
||||||
|
* - Verifies 'Top Sites' context menu UI functionality
|
||||||
|
* - Verifies 'Top Site' usage UI functionality
|
||||||
|
* - Verifies existence of default top sites available on the home-screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TopSitesTest {
|
||||||
|
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
private lateinit var mockWebServer: MockWebServer
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val activityIntentTestRule = HomeActivityIntentTestRule()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
mockWebServer = MockWebServer().apply {
|
||||||
|
setDispatcher(AndroidAssetDispatcher())
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
mockWebServer.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyAddToFirefoxHome() {
|
||||||
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
val defaultWebPageTitle = "Test_Page_1"
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
verifyAddFirefoxHome()
|
||||||
|
}.addToFirefoxHome {
|
||||||
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyExistingTabList()
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyOpenTopSiteNormalTab() {
|
||||||
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
val defaultWebPageTitle = "Test_Page_1"
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
verifyAddFirefoxHome()
|
||||||
|
}.addToFirefoxHome {
|
||||||
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyExistingTabList()
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
}.openTopSiteTabWithTitle(title = defaultWebPageTitle) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
verifyUrl(defaultWebPage.url.toString())
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||||
|
verifyTopSiteContextMenuItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismiss context menu popup
|
||||||
|
mDevice.pressBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyOpenTopSitePrivateTab() {
|
||||||
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
val defaultWebPageTitle = "Test_Page_1"
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
verifyAddFirefoxHome()
|
||||||
|
}.addToFirefoxHome {
|
||||||
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyExistingTabList()
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||||
|
verifyTopSiteContextMenuItems()
|
||||||
|
}.openTopSiteInPrivateTab {
|
||||||
|
verifyCurrentPrivateSession(activityIntentTestRule.activity.applicationContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyRemoveTopSite() {
|
||||||
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
val defaultWebPageTitle = "Test_Page_1"
|
||||||
|
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyPageContent(defaultWebPage.content)
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
verifyAddFirefoxHome()
|
||||||
|
}.addToFirefoxHome {
|
||||||
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyExistingTabList()
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||||
|
verifyTopSiteContextMenuItems()
|
||||||
|
}.removeTopSite {
|
||||||
|
verifyNotExistingTopSitesList(defaultWebPageTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyDefaultTopSitesLocale_EN() {
|
||||||
|
// en-US defaults
|
||||||
|
val defaultTopSites = arrayOf(
|
||||||
|
"Top Articles",
|
||||||
|
"Wikipedia",
|
||||||
|
"YouTube"
|
||||||
|
)
|
||||||
|
|
||||||
|
homeScreen { }.dismissOnboarding()
|
||||||
|
|
||||||
|
homeScreen {
|
||||||
|
verifyExistingTopSitesList()
|
||||||
|
defaultTopSites.forEach { item ->
|
||||||
|
verifyExistingTopSitesTabs(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
@ -15,6 +16,7 @@ import androidx.test.espresso.intent.Intents
|
||||||
import androidx.test.espresso.intent.matcher.BundleMatchers
|
import androidx.test.espresso.intent.matcher.BundleMatchers
|
||||||
import androidx.test.espresso.intent.matcher.IntentMatchers
|
import androidx.test.espresso.intent.matcher.IntentMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
@ -25,11 +27,13 @@ import androidx.test.uiautomator.Until
|
||||||
import org.hamcrest.CoreMatchers
|
import org.hamcrest.CoreMatchers
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
import org.hamcrest.CoreMatchers.containsString
|
import org.hamcrest.CoreMatchers.containsString
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.helpers.Constants.LongClickDuration
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
import org.mozilla.fenix.helpers.Constants.LongClickDuration
|
|
||||||
|
|
||||||
class BrowserRobot {
|
class BrowserRobot {
|
||||||
|
|
||||||
|
@ -38,14 +42,19 @@ class BrowserRobot {
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyUrl(redirectUrl: String) {
|
fun verifyCurrentPrivateSession(context: Context) {
|
||||||
|
val session = context.components.core.sessionManager.selectedSession
|
||||||
|
assertTrue("Current session is private", session?.private!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyUrl(url: String) {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view")),
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_url_view")),
|
||||||
TestAssetHelper.waitingTime
|
TestAssetHelper.waitingTime
|
||||||
)
|
)
|
||||||
onView(withId(R.id.mozac_browser_toolbar_url_view))
|
onView(withId(R.id.mozac_browser_toolbar_url_view))
|
||||||
.check(matches(withText(containsString(redirectUrl))))
|
.check(matches(withText(containsString(url))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyHelpUrl() {
|
fun verifyHelpUrl() {
|
||||||
|
@ -76,6 +85,10 @@ class BrowserRobot {
|
||||||
fun verifySnackBarText(expectedText: String) {
|
fun verifySnackBarText(expectedText: String) {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
||||||
|
|
||||||
|
onView(withText(expectedText)).check(
|
||||||
|
matches(isCompletelyDisplayed())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyLinkContextMenuItems(containsURL: Uri) {
|
fun verifyLinkContextMenuItems(containsURL: Uri) {
|
||||||
|
@ -256,6 +269,18 @@ class BrowserRobot {
|
||||||
).perform(ViewActions.click())
|
).perform(ViewActions.click())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun verifySaveLoginPromptIsShown() {
|
||||||
|
mDevice.waitNotNull(Until.findObjects(By.text("test@example.com")), TestAssetHelper.waitingTime)
|
||||||
|
val submitButton = mDevice.findObject(By.res("submit"))
|
||||||
|
submitButton.clickAndWait(Until.newWindow(), TestAssetHelper.waitingTime)
|
||||||
|
// Click save to save the login
|
||||||
|
mDevice.waitNotNull(Until.findObjects(By.text("Save")))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveLoginFromPrompt(optionToSaveLogin: String) {
|
||||||
|
mDevice.findObject(By.text(optionToSaveLogin)).click()
|
||||||
|
}
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
private fun threeDotButton() = onView(
|
private fun threeDotButton() = onView(
|
||||||
|
@ -312,4 +337,4 @@ fun dismissTrackingOnboarding() {
|
||||||
|
|
||||||
fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
|
fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
|
||||||
|
|
||||||
private fun tabsCounter() = onView(withId(R.id.counter_box))
|
private fun tabsCounter() = onView(withId(R.id.mozac_browser_toolbar_browser_actions))
|
||||||
|
|
|
@ -7,31 +7,39 @@
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import android.graphics.Bitmap
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
import androidx.test.espresso.action.ViewActions.click
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
|
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.Until
|
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import androidx.test.uiautomator.UiScrollable
|
import androidx.test.uiautomator.UiScrollable
|
||||||
import androidx.test.uiautomator.UiSelector
|
import androidx.test.uiautomator.UiSelector
|
||||||
import org.hamcrest.CoreMatchers
|
import androidx.test.uiautomator.Until
|
||||||
import org.hamcrest.Matchers.allOf
|
import org.hamcrest.CoreMatchers.containsString
|
||||||
import org.hamcrest.Matchers.containsString
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
|
import org.hamcrest.CoreMatchers.not
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
||||||
|
import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
|
import org.mozilla.fenix.components.Search
|
||||||
|
import org.mozilla.fenix.helpers.withBitmapDrawable
|
||||||
|
import org.mozilla.fenix.helpers.matchers.hasItem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the home screen menu.
|
* Implementation of Robot Pattern for the home screen menu.
|
||||||
|
@ -51,6 +59,7 @@ class HomeScreenRobot {
|
||||||
fun verifyHomeWordmark() = assertHomeWordmark()
|
fun verifyHomeWordmark() = assertHomeWordmark()
|
||||||
fun verifyHomeToolbar() = assertHomeToolbar()
|
fun verifyHomeToolbar() = assertHomeToolbar()
|
||||||
fun verifyHomeComponent() = assertHomeComponent()
|
fun verifyHomeComponent() = assertHomeComponent()
|
||||||
|
fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine)
|
||||||
|
|
||||||
// First Run elements
|
// First Run elements
|
||||||
fun verifyWelcomeHeader() = assertWelcomeHeader()
|
fun verifyWelcomeHeader() = assertWelcomeHeader()
|
||||||
|
@ -79,41 +88,55 @@ class HomeScreenRobot {
|
||||||
|
|
||||||
// Private mode elements
|
// Private mode elements
|
||||||
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
|
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
|
||||||
|
|
||||||
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
|
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
|
||||||
|
fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton()
|
||||||
|
|
||||||
fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible)
|
fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible)
|
||||||
fun verifyCloseTabsButton(visible: Boolean = true) = assertCloseTabsButton(visible)
|
fun verifyCloseTabsButton(title: String) =
|
||||||
|
assertCloseTabsButton(title)
|
||||||
|
|
||||||
fun verifyExistingTabList() = assertExistingTabList()
|
fun verifyExistingTabList() = assertExistingTabList()
|
||||||
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
|
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
|
||||||
|
|
||||||
|
fun verifyExistingTopSitesList() = assertExistingTopSitesList()
|
||||||
|
fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
|
||||||
|
fun verifyExistingTopSitesTabs(title: String) = assertExistingTopSitesTabs(title)
|
||||||
|
fun verifyTopSiteContextMenuItems() = assertTopSiteContextMenuItems()
|
||||||
|
|
||||||
// Collections element
|
// Collections element
|
||||||
fun clickCollectionThreeDotButton() {
|
fun clickCollectionThreeDotButton() {
|
||||||
collectionThreeDotButton().click()
|
collectionThreeDotButton().click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.text("Delete collection")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.text("Delete collection")), waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectRenameCollection() {
|
fun selectRenameCollection() {
|
||||||
onView(allOf(ViewMatchers.withText("Rename collection"))).click()
|
onView(allOf(ViewMatchers.withText("Rename collection"))).click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.res("name_collection_edittext")))
|
mDevice.waitNotNull(Until.findObject(By.res("name_collection_edittext")))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectDeleteCollection() {
|
fun selectDeleteCollection() {
|
||||||
onView(allOf(ViewMatchers.withText("Delete collection"))).click()
|
onView(allOf(ViewMatchers.withText("Delete collection"))).click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.res("message")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.res("message")), waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun confirmDeleteCollection() {
|
fun confirmDeleteCollection() {
|
||||||
onView(allOf(ViewMatchers.withText("DELETE"))).click()
|
onView(allOf(ViewMatchers.withText("DELETE"))).click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.res("collections_header")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.res("collections_header")), waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun typeCollectionName(name: String) {
|
fun typeCollectionName(name: String) {
|
||||||
mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime)
|
mDevice.wait(Until.findObject(By.res("name_collection_edittext")), waitingTime)
|
||||||
|
|
||||||
collectionNameTextField().perform(ViewActions.replaceText(name))
|
collectionNameTextField().perform(ViewActions.replaceText(name))
|
||||||
collectionNameTextField().perform(ViewActions.pressImeActionButton())
|
collectionNameTextField().perform(ViewActions.pressImeActionButton())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollToElementByText(text: String): UiScrollable {
|
fun scrollToElementByText(text: String): UiScrollable {
|
||||||
val appView = UiScrollable(UiSelector().scrollable(true))
|
val appView = UiScrollable(UiSelector().scrollable(true))
|
||||||
appView.scrollTextIntoView(text)
|
appView.scrollTextIntoView(text)
|
||||||
return appView
|
return appView
|
||||||
}
|
}
|
||||||
|
|
||||||
fun swipeUpToDismissFirstRun() {
|
fun swipeUpToDismissFirstRun() {
|
||||||
scrollToElementByText("Start browsing")
|
scrollToElementByText("Start browsing")
|
||||||
}
|
}
|
||||||
|
@ -124,12 +147,31 @@ class HomeScreenRobot {
|
||||||
|
|
||||||
fun togglePrivateBrowsingModeOnOff() {
|
fun togglePrivateBrowsingModeOnOff() {
|
||||||
onView(ViewMatchers.withResourceName("privateBrowsingButton"))
|
onView(ViewMatchers.withResourceName("privateBrowsingButton"))
|
||||||
.perform(click())
|
.perform(click())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun swipeToBottom() = onView(ViewMatchers.withId(R.id.home_component)).perform(ViewActions.swipeUp())
|
fun swipeToBottom() = onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeUp())
|
||||||
|
|
||||||
fun swipeToTop() = onView(ViewMatchers.withId(R.id.home_component)).perform(ViewActions.swipeDown())
|
fun swipeToTop() = onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown())
|
||||||
|
|
||||||
|
fun swipeTabRight(title: String) =
|
||||||
|
onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeRight())
|
||||||
|
|
||||||
|
fun swipeTabLeft(title: String) =
|
||||||
|
onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeLeft())
|
||||||
|
|
||||||
|
fun closeTabViaXButton(title: String) = closeTabViaX(title)
|
||||||
|
|
||||||
|
fun verifySnackBarText(expectedText: String) {
|
||||||
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
mDevice.waitNotNull(Until.findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun snackBarButtonClick(expectedText: String) {
|
||||||
|
onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
|
||||||
|
matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))
|
||||||
|
).perform(ViewActions.click())
|
||||||
|
}
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
@ -167,6 +209,58 @@ class HomeScreenRobot {
|
||||||
ThreeDotMenuMainRobot().interact()
|
ThreeDotMenuMainRobot().interact()
|
||||||
return ThreeDotMenuMainRobot.Transition()
|
return ThreeDotMenuMainRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun closeAllPrivateTabs(interact: HomeScreenRobot.() -> Unit): Transition {
|
||||||
|
onView(withId(R.id.close_tabs_button))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
.perform(click())
|
||||||
|
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openNavigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {
|
||||||
|
|
||||||
|
assertNavigationToolbar().perform(click())
|
||||||
|
NavigationToolbarRobot().interact()
|
||||||
|
return NavigationToolbarRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openContextMenuOnTopSitesWithTitle(title: String, interact: HomeScreenRobot.() -> Unit): Transition {
|
||||||
|
onView(withId(R.id.top_sites_list)).perform(
|
||||||
|
actionOnItem<RecyclerView.ViewHolder>(hasDescendant(withText(title)), ViewActions.longClick())
|
||||||
|
)
|
||||||
|
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openTopSiteTabWithTitle(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
|
onView(withId(R.id.top_sites_list)).perform(
|
||||||
|
actionOnItem<RecyclerView.ViewHolder>(hasDescendant(withText(title)), click())
|
||||||
|
)
|
||||||
|
|
||||||
|
BrowserRobot().interact()
|
||||||
|
return BrowserRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeTopSite(interact: HomeScreenRobot.() -> Unit): Transition {
|
||||||
|
onView(withText("Remove"))
|
||||||
|
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
|
||||||
|
.perform(click())
|
||||||
|
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openTopSiteInPrivateTab(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
|
onView(withText("Open in private tab"))
|
||||||
|
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
|
||||||
|
.perform(click())
|
||||||
|
|
||||||
|
BrowserRobot().interact()
|
||||||
|
return BrowserRobot.Transition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,14 +270,15 @@ fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition
|
||||||
}
|
}
|
||||||
|
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
private fun navigationToolbar() =
|
private fun navigationToolbar() =
|
||||||
onView(CoreMatchers.allOf(withText("Search or enter address")))
|
onView(allOf(withText("Search or enter address")))
|
||||||
|
|
||||||
private fun closeTabButton() = onView(withId(R.id.close_tab_button))
|
private fun closeTabButton() = onView(withId(R.id.close_tab_button))
|
||||||
|
|
||||||
private fun assertNavigationToolbar() =
|
private fun assertNavigationToolbar() =
|
||||||
onView(CoreMatchers.allOf(withText("Search or enter address")))
|
onView(allOf(withText("Search or enter address")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
|
private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
|
||||||
|
@ -203,50 +298,63 @@ private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertOpenTabsHeader() =
|
private fun assertOpenTabsHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Open tabs")))
|
onView(allOf(withText("Open tabs")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertAddTabButton() =
|
private fun assertAddTabButton() =
|
||||||
onView(CoreMatchers.allOf(withId(R.id.add_tab_button), isDisplayed()))
|
onView(allOf(withId(R.id.add_tab_button), isDisplayed()))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoTabsOpenedHeader() =
|
private fun assertNoTabsOpenedHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("No open tabs")))
|
onView(allOf(withText("No open tabs")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoTabsOpenedText() {
|
private fun assertNoTabsOpenedText() {
|
||||||
onView(CoreMatchers.allOf(withText("Your open tabs will be shown here.")))
|
onView(allOf(withText("Your open tabs will be shown here.")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertCollectionsHeader() =
|
private fun assertCollectionsHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Collections")))
|
onView(allOf(withText("Collections")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoCollectionsHeader() =
|
private fun assertNoCollectionsHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("No collections")))
|
onView(allOf(withText("No collections")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoCollectionsText() =
|
private fun assertNoCollectionsText() =
|
||||||
onView(
|
onView(
|
||||||
CoreMatchers.allOf(
|
allOf(
|
||||||
withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
|
withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("home_component"))
|
private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
|
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
|
||||||
|
|
||||||
|
private fun verifySearchEngineIcon(searchEngineIcon: Bitmap, searchEngineName: String) {
|
||||||
|
onView(withId(R.id.search_engine_icon))
|
||||||
|
.check(matches(withBitmapDrawable(searchEngineIcon, searchEngineName)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSearchEngine(searchEngineName: String) =
|
||||||
|
Search(appContext).searchEngineManager.getDefaultSearchEngine(appContext, searchEngineName)
|
||||||
|
|
||||||
|
private fun verifySearchEngineIcon(searchEngineName: String) {
|
||||||
|
val ddgSearchEngine = getSearchEngine(searchEngineName)
|
||||||
|
verifySearchEngineIcon(ddgSearchEngine.icon, ddgSearchEngine.name)
|
||||||
|
}
|
||||||
|
|
||||||
// First Run elements
|
// First Run elements
|
||||||
private fun assertWelcomeHeader() =
|
private fun assertWelcomeHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Welcome to Firefox Preview!")))
|
onView(allOf(withText("Welcome to Firefox Preview!")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertGetTheMostHeader() =
|
private fun assertGetTheMostHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Get the most out of Firefox Preview.")))
|
onView(allOf(withText("Get the most out of Firefox Preview.")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertAccountsSignInButton() =
|
private fun assertAccountsSignInButton() =
|
||||||
|
@ -254,15 +362,15 @@ private fun assertAccountsSignInButton() =
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertGetToKnowHeader() =
|
private fun assertGetToKnowHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Get to know Firefox Preview")))
|
onView(allOf(withText("Get to know Firefox Preview")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertChooseThemeHeader() =
|
private fun assertChooseThemeHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Choose your theme")))
|
onView(allOf(withText("Choose your theme")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertChooseThemeText() =
|
private fun assertChooseThemeText() =
|
||||||
onView(CoreMatchers.allOf(withText("Try dark theme: easier on your battery and your eyes.")))
|
onView(allOf(withText("Try dark theme: easier on your battery and your eyes.")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertLightThemeToggle() =
|
private fun assertLightThemeToggle() =
|
||||||
|
@ -270,7 +378,7 @@ private fun assertLightThemeToggle() =
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertLightThemeDescription() =
|
private fun assertLightThemeDescription() =
|
||||||
onView(CoreMatchers.allOf(withText("Light theme")))
|
onView(allOf(withText("Light theme")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertDarkThemeToggle() =
|
private fun assertDarkThemeToggle() =
|
||||||
|
@ -278,7 +386,7 @@ private fun assertDarkThemeToggle() =
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertDarkThemeDescription() =
|
private fun assertDarkThemeDescription() =
|
||||||
onView(CoreMatchers.allOf(withText("Dark theme")))
|
onView(allOf(withText("Dark theme")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertAutomaticThemeToggle() =
|
private fun assertAutomaticThemeToggle() =
|
||||||
|
@ -286,21 +394,21 @@ private fun assertAutomaticThemeToggle() =
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertAutomaticThemeDescription() =
|
private fun assertAutomaticThemeDescription() =
|
||||||
onView(CoreMatchers.allOf(withText("Automatic")))
|
onView(allOf(withText("Automatic")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertProtectYourselfHeader() =
|
private fun assertProtectYourselfHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Protect yourself")))
|
onView(allOf(withText("Protect yourself")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertTrackingProtectionToggle() = onView(
|
private fun assertTrackingProtectionToggle() = onView(
|
||||||
CoreMatchers.allOf(ViewMatchers.withResourceName("tracking_protection_toggle"))
|
allOf(ViewMatchers.withResourceName("tracking_protection_toggle"))
|
||||||
)
|
)
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertProtectYourselfText() {
|
private fun assertProtectYourselfText() {
|
||||||
onView(
|
onView(
|
||||||
CoreMatchers.allOf(
|
allOf(
|
||||||
withText(
|
withText(
|
||||||
"Firefox Preview blocks ad trackers that follow you around the web."
|
"Firefox Preview blocks ad trackers that follow you around the web."
|
||||||
)
|
)
|
||||||
|
@ -310,34 +418,39 @@ private fun assertProtectYourselfText() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertBrowsePrivatelyHeader() =
|
private fun assertBrowsePrivatelyHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Browse privately")))
|
onView(allOf(withText("Browse privately")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertBrowsePrivatelyText() =
|
private fun assertBrowsePrivatelyText() =
|
||||||
onView(CoreMatchers.allOf(withText(containsString("private browsing is just a tap away."))))
|
onView(allOf(withText(containsString("private browsing is just a tap away."))))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertYourPrivacyHeader() =
|
private fun assertYourPrivacyHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Your privacy")))
|
onView(allOf(withText("Your privacy")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertYourPrivacyText() =
|
private fun assertYourPrivacyText() =
|
||||||
onView(CoreMatchers.allOf(withText(
|
onView(
|
||||||
"We’ve designed Firefox Preview to give you control over what you share online and what you share with us.")))
|
allOf(
|
||||||
|
withText(
|
||||||
|
"We’ve designed Firefox Preview to give you control over what you share online and what you share with us."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertPrivacyNoticeButton() =
|
private fun assertPrivacyNoticeButton() =
|
||||||
onView(CoreMatchers.allOf(withText("Read our privacy notice")))
|
onView(allOf(withText("Read our privacy notice")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertStartBrowsingButton() =
|
private fun assertStartBrowsingButton() =
|
||||||
onView(CoreMatchers.allOf(withText("Start browsing")))
|
onView(allOf(withText("Start browsing")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
// Private mode elements
|
// Private mode elements
|
||||||
private fun assertPrivateSessionHeader() =
|
private fun assertPrivateSessionHeader() =
|
||||||
onView(CoreMatchers.allOf(withText("Private tabs")))
|
onView(allOf(withText("Private tabs")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
|
const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
|
||||||
"when you quit the app or close all private tabs. While this doesn’t make you anonymous to websites or " +
|
"when you quit the app or close all private tabs. While this doesn’t make you anonymous to websites or " +
|
||||||
|
@ -345,27 +458,28 @@ const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and brow
|
||||||
"who uses this device."
|
"who uses this device."
|
||||||
|
|
||||||
private fun assertPrivateSessionMessage(visible: Boolean) =
|
private fun assertPrivateSessionMessage(visible: Boolean) =
|
||||||
onView(CoreMatchers.allOf(withText(PRIVATE_SESSION_MESSAGE)))
|
onView(allOf(withText(PRIVATE_SESSION_MESSAGE)))
|
||||||
.check(
|
.check(
|
||||||
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist()
|
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist()
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun assertShareTabsButton(visible: Boolean) =
|
private fun assertShareTabsButton(visible: Boolean) =
|
||||||
onView(CoreMatchers.allOf(withId(R.id.share_tabs_button), isDisplayed()))
|
onView(allOf(withId(R.id.share_tabs_button), isDisplayed()))
|
||||||
.check(matches(withEffectiveVisibility(visibleOrGone(visible))))
|
.check(matches(withEffectiveVisibility(visibleOrGone(visible))))
|
||||||
|
|
||||||
private fun assertCloseTabsButton(visible: Boolean) =
|
private fun assertCloseTabsButton(title: String) =
|
||||||
onView(CoreMatchers.allOf(withId(R.id.close_tab_button), isDisplayed()))
|
onView(allOf(withId(R.id.close_tab_button), withContentDescription("Close tab $title")))
|
||||||
.check(matches(withEffectiveVisibility(visibleOrGone(visible))))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE
|
private fun visibleOrGone(visibility: Boolean) =
|
||||||
|
if (visibility) Visibility.VISIBLE else Visibility.GONE
|
||||||
|
|
||||||
private fun assertExistingTabList() =
|
private fun assertExistingTabList() =
|
||||||
onView(CoreMatchers.allOf(withId(R.id.item_tab)))
|
onView(allOf(withId(R.id.item_tab)))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertExistingOpenTabs(title: String) =
|
private fun assertExistingOpenTabs(title: String) =
|
||||||
onView(withId(R.id.home_component)).perform(
|
onView(withId(R.id.sessionControlRecyclerView)).perform(
|
||||||
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
||||||
ViewMatchers.hasDescendant(withText(title))
|
ViewMatchers.hasDescendant(withText(title))
|
||||||
)
|
)
|
||||||
|
@ -373,6 +487,46 @@ private fun assertExistingOpenTabs(title: String) =
|
||||||
|
|
||||||
private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button)))
|
private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button)))
|
||||||
|
|
||||||
private fun collectionThreeDotButton() = onView(allOf(withId(R.id.collection_overflow_button)))
|
private fun collectionThreeDotButton() =
|
||||||
|
onView(allOf(withId(R.id.collection_overflow_button)))
|
||||||
|
|
||||||
private fun collectionNameTextField() = onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))
|
private fun collectionNameTextField() =
|
||||||
|
onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))
|
||||||
|
|
||||||
|
private fun closeTabViaX(title: String) {
|
||||||
|
val closeButton = onView(
|
||||||
|
allOf(
|
||||||
|
withId(R.id.close_tab_button),
|
||||||
|
withContentDescription("Close tab $title")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
closeButton.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertPrivateTabsCloseTabsButton() = onView(allOf(withId(R.id.close_tabs_button)))
|
||||||
|
|
||||||
|
private fun assertExistingTopSitesList() =
|
||||||
|
onView(allOf(withId(R.id.top_sites_list)))
|
||||||
|
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
|
||||||
|
|
||||||
|
private fun assertExistingTopSitesTabs(title: String) =
|
||||||
|
onView(allOf(withId(R.id.top_sites_list)))
|
||||||
|
.check(matches(hasItem(hasDescendant(withText(title)))))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun assertNotExistingTopSitesList(title: String) =
|
||||||
|
onView(allOf(withId(R.id.top_sites_list)))
|
||||||
|
.check(matches(not(hasItem(hasDescendant(withText(title))))))
|
||||||
|
|
||||||
|
private fun assertTopSiteContextMenuItems() {
|
||||||
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObject(By.text("Open in private tab")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObject(By.text("Remove")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
||||||
|
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(
|
Until.findObject(
|
||||||
By.text("SHARE A LINK")
|
By.text("ALL ACTIONS")
|
||||||
), waitingTime
|
), waitingTime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
||||||
|
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(
|
Until.findObject(
|
||||||
By.text("SHARE A LINK")
|
By.text("ALL ACTIONS")
|
||||||
), waitingTime
|
), waitingTime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,26 +10,49 @@ import android.net.Uri
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions.pressImeActionButton
|
import androidx.test.espresso.action.ViewActions.pressImeActionButton
|
||||||
import androidx.test.espresso.action.ViewActions.replaceText
|
import androidx.test.espresso.action.ViewActions.replaceText
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.action.ViewActions.typeText
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import androidx.test.uiautomator.Until
|
import androidx.test.uiautomator.Until
|
||||||
|
import org.hamcrest.CoreMatchers.not
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
|
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreEqualTo
|
||||||
|
import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreGreaterThan
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the URL toolbar.
|
* Implementation of Robot Pattern for the URL toolbar.
|
||||||
*/
|
*/
|
||||||
class NavigationToolbarRobot {
|
class NavigationToolbarRobot {
|
||||||
|
|
||||||
|
fun verifySearchSuggestionsAreMoreThan(suggestionSize: Int, searchTerm: String) =
|
||||||
|
assertSuggestionsAreMoreThan(suggestionSize, searchTerm)
|
||||||
|
|
||||||
|
fun verifySearchSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) =
|
||||||
|
assertSuggestionsAreEqualTo(suggestionSize, searchTerm)
|
||||||
|
|
||||||
|
fun verifyNoHistoryBookmarks() = assertNoHistoryBookmarks()
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
|
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
fun enterURLAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun enterURLAndEnterToBrowser(
|
||||||
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), waitingTime)
|
url: Uri,
|
||||||
|
interact: BrowserRobot.() -> Unit
|
||||||
|
): BrowserRobot.Transition {
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
urlBar().click()
|
urlBar().click()
|
||||||
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
||||||
|
|
||||||
|
@ -45,7 +68,10 @@ class NavigationToolbarRobot {
|
||||||
return ThreeDotMenuMainRobot.Transition()
|
return ThreeDotMenuMainRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openNewTabAndEnterToBrowser(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun openNewTabAndEnterToBrowser(
|
||||||
|
url: Uri,
|
||||||
|
interact: BrowserRobot.() -> Unit
|
||||||
|
): BrowserRobot.Transition {
|
||||||
mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime)
|
||||||
newTab().click()
|
newTab().click()
|
||||||
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
||||||
|
@ -54,7 +80,7 @@ class NavigationToolbarRobot {
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visitLinkFromClipboard(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun visitLinkFromClipboard(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_clear_view")),
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_clear_view")),
|
||||||
waitingTime
|
waitingTime
|
||||||
|
@ -62,11 +88,12 @@ class NavigationToolbarRobot {
|
||||||
clearAddressBar().click()
|
clearAddressBar().click()
|
||||||
|
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.text(url.toString())), waitingTime
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/clipboard_title")),
|
||||||
|
waitingTime
|
||||||
)
|
)
|
||||||
|
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.res("org.mozilla.fenix.debug:id/fill_link_from_clipboard")),
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/clipboard_url")),
|
||||||
waitingTime
|
waitingTime
|
||||||
)
|
)
|
||||||
fillLinkButton().click()
|
fillLinkButton().click()
|
||||||
|
@ -74,6 +101,13 @@ class NavigationToolbarRobot {
|
||||||
BrowserRobot().interact()
|
BrowserRobot().interact()
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
|
goBackButton()
|
||||||
|
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return HomeScreenRobot.Transition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +116,34 @@ fun navigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationTo
|
||||||
return NavigationToolbarRobot.Transition()
|
return NavigationToolbarRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dismissOnboardingButton() = onView(ViewMatchers.withId(R.id.close_onboarding))
|
private fun assertSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) {
|
||||||
private fun urlBar() = onView(ViewMatchers.withId(R.id.toolbar))
|
mDevice.waitForIdle()
|
||||||
private fun awesomeBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_edit_url_view))
|
awesomeBar().perform(typeText(searchTerm))
|
||||||
private fun threeDotButton() = onView(ViewMatchers.withContentDescription("Menu"))
|
|
||||||
private fun newTab() = onView(ViewMatchers.withContentDescription("Add tab"))
|
mDevice.waitForIdle()
|
||||||
private fun fillLinkButton() = onView(ViewMatchers.withId(R.id.fill_link_from_clipboard))
|
onView(withId(R.id.awesomeBar)).check(suggestionsAreEqualTo(suggestionSize))
|
||||||
private fun clearAddressBar() = onView(ViewMatchers.withId(R.id.mozac_browser_toolbar_clear_view))
|
}
|
||||||
|
|
||||||
|
private fun assertSuggestionsAreMoreThan(suggestionSize: Int, searchTerm: String) {
|
||||||
|
mDevice.waitForIdle()
|
||||||
|
awesomeBar().perform(typeText(searchTerm))
|
||||||
|
|
||||||
|
mDevice.waitForIdle()
|
||||||
|
onView(withId(R.id.awesomeBar)).check(suggestionsAreGreaterThan(suggestionSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertNoHistoryBookmarks() {
|
||||||
|
onView(withId(R.id.container))
|
||||||
|
.check(matches(not(hasDescendant(withText("Test_Page_1")))))
|
||||||
|
.check(matches(not(hasDescendant(withText("Test_Page_2")))))
|
||||||
|
.check(matches(not(hasDescendant(withText("Test_Page_3")))))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dismissOnboardingButton() = onView(withId(R.id.close_onboarding))
|
||||||
|
private fun urlBar() = onView(withId(R.id.toolbar))
|
||||||
|
private fun awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
|
||||||
|
private fun threeDotButton() = onView(withContentDescription("Menu"))
|
||||||
|
private fun newTab() = onView(withContentDescription("Add tab"))
|
||||||
|
private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard))
|
||||||
|
private fun clearAddressBar() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
||||||
|
private fun goBackButton() = mDevice.pressBack()
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
/* 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)))
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun assertAppearanceColorLight(visible: Boolean) =
|
||||||
|
onView(
|
||||||
|
withId(R.id.mozac_feature_readerview_color_light)
|
||||||
|
).check(
|
||||||
|
matches(withEffectiveVisibility(visibleOrGone(visible)))
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun assertAppearanceColorSepia(visible: Boolean) =
|
||||||
|
onView(
|
||||||
|
withId(R.id.mozac_feature_readerview_color_sepia)
|
||||||
|
).check(
|
||||||
|
matches(withEffectiveVisibility(visibleOrGone(visible)))
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun assertAppearanceColorGroup(visible: Boolean) =
|
||||||
|
onView(
|
||||||
|
withId(R.id.mozac_feature_readerview_color_scheme_group)
|
||||||
|
).check(
|
||||||
|
matches(withEffectiveVisibility(visibleOrGone(visible)))
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun visibleOrGone(visibility: Boolean) =
|
||||||
|
if (visibility) ViewMatchers.Visibility.VISIBLE else ViewMatchers.Visibility.GONE
|
|
@ -39,8 +39,10 @@ class SearchRobot {
|
||||||
fun verifyBrowserToolbar() = assertBrowserToolbarEditView()
|
fun verifyBrowserToolbar() = assertBrowserToolbarEditView()
|
||||||
fun verifyScanButton() = assertScanButton()
|
fun verifyScanButton() = assertScanButton()
|
||||||
fun verifySearchWithText() = assertSearchWithText()
|
fun verifySearchWithText() = assertSearchWithText()
|
||||||
fun verifyDuckDuckGoResults() = assertDuckDuckGoResults()
|
fun verifySearchEngineResults(searchEngineName: String) =
|
||||||
fun verifyDuckDuckGoURL() = assertDuckDuckGoURL()
|
assertSearchEngineResults(searchEngineName)
|
||||||
|
|
||||||
|
fun verifySearchEngineURL(searchEngineName: String) = assertSearchEngineURL(searchEngineName)
|
||||||
fun verifySearchSettings() = assertSearchSettings()
|
fun verifySearchSettings() = assertSearchSettings()
|
||||||
fun verifySearchBarEmpty() = assertSearchBarEmpty()
|
fun verifySearchBarEmpty() = assertSearchBarEmpty()
|
||||||
|
|
||||||
|
@ -60,13 +62,21 @@ class SearchRobot {
|
||||||
browserToolbarEditView().perform(typeText(searchTerm))
|
browserToolbarEditView().perform(typeText(searchTerm))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clickDuckDuckGoEngineButton() {
|
fun clickSearchEngineButton(searchEngineName: String) {
|
||||||
duckDuckGoEngineButton().perform(click())
|
searchEngineButton(searchEngineName).perform(click())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clickDuckDuckGoResult() {
|
fun clickSearchEngineResult(searchEngineName: String) {
|
||||||
mDevice.waitNotNull(Until.findObjects(By.text("DuckDuckGo")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(
|
||||||
awesomeBar().perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click()))
|
Until.findObjects(By.text(searchEngineName)),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
|
awesomeBar().perform(
|
||||||
|
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||||
|
0,
|
||||||
|
click()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollToSearchEngineSettings(): UiScrollable {
|
fun scrollToSearchEngineSettings(): UiScrollable {
|
||||||
|
@ -88,7 +98,7 @@ class SearchRobot {
|
||||||
|
|
||||||
fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
browserToolbarEditView().perform(typeText("Mozilla\n"))
|
browserToolbarEditView().perform(typeText("mozilla\n"))
|
||||||
|
|
||||||
BrowserRobot().interact()
|
BrowserRobot().interact()
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
|
@ -98,11 +108,12 @@ class SearchRobot {
|
||||||
|
|
||||||
private fun awesomeBar() = onView(withId(R.id.awesomeBar))
|
private fun awesomeBar() = onView(withId(R.id.awesomeBar))
|
||||||
|
|
||||||
private fun browserToolbarEditView() = onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view)))
|
private fun browserToolbarEditView() =
|
||||||
|
onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view)))
|
||||||
|
|
||||||
private fun duckDuckGoEngineButton(): ViewInteraction {
|
private fun searchEngineButton(searchEngineName: String): ViewInteraction {
|
||||||
mDevice.waitNotNull(Until.findObject(By.text("DuckDuckGo")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.text(searchEngineName)), TestAssetHelper.waitingTime)
|
||||||
return onView(Matchers.allOf(withText("DuckDuckGo")))
|
return onView(Matchers.allOf(withText(searchEngineName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun denyPermissionButton(): UiObject {
|
private fun denyPermissionButton(): UiObject {
|
||||||
|
@ -122,14 +133,18 @@ private fun scanButton(): ViewInteraction {
|
||||||
|
|
||||||
private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
||||||
|
|
||||||
private fun assertDuckDuckGoURL() {
|
private fun assertSearchEngineURL(searchEngineName: String) {
|
||||||
mDevice.waitNotNull(Until.findObject(By.textContains("https://duckduckgo.com/?q=mozilla")), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(
|
||||||
onView(allOf(withText(startsWith("https://duckduckgo.com"))))
|
Until.findObject(By.textContains("https://${searchEngineName.toLowerCase()}.com/?q=mozilla")),
|
||||||
|
TestAssetHelper.waitingTime
|
||||||
|
)
|
||||||
|
onView(allOf(withText(startsWith("https://${searchEngineName.toLowerCase()}.com"))))
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertDuckDuckGoResults() {
|
private fun assertSearchEngineResults(searchEngineName: String) {
|
||||||
val count = mDevice.wait(Until.findObjects(By.text(("DuckDuckGo"))), TestAssetHelper.waitingTime)
|
val count =
|
||||||
|
mDevice.wait(Until.findObjects(By.text((searchEngineName))), TestAssetHelper.waitingTime)
|
||||||
assert(count.size > 1)
|
assert(count.size > 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import androidx.test.espresso.intent.Intents.intended
|
||||||
import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage
|
import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
|
@ -35,10 +36,10 @@ import org.mozilla.fenix.helpers.click
|
||||||
class SettingsRobot {
|
class SettingsRobot {
|
||||||
|
|
||||||
// BASICS SECTION
|
// BASICS SECTION
|
||||||
fun verifyBasicsHeading() = assertBasicsHeading()
|
fun verifyBasicsHeading() = assertGeneralHeading()
|
||||||
|
|
||||||
fun verifySearchEngineButton() = assertSearchEngineButton()
|
fun verifySearchEngineButton() = assertSearchEngineButton()
|
||||||
fun verifyThemeButton() = assertThemeButton()
|
fun verifyThemeButton() = assertCustomizeButton()
|
||||||
fun verifyThemeSelected() = assertThemeSelected()
|
fun verifyThemeSelected() = assertThemeSelected()
|
||||||
fun verifyAccessibilityButton() = assertAccessibilityButton()
|
fun verifyAccessibilityButton() = assertAccessibilityButton()
|
||||||
fun verifySetAsDefaultBrowserButton() = assertSetAsDefaultBrowserButton()
|
fun verifySetAsDefaultBrowserButton() = assertSetAsDefaultBrowserButton()
|
||||||
|
@ -51,7 +52,7 @@ class SettingsRobot {
|
||||||
fun verifyEnhancedTrackingProtectionValue(state: String) =
|
fun verifyEnhancedTrackingProtectionValue(state: String) =
|
||||||
assertEnhancedTrackingProtectionValue(state)
|
assertEnhancedTrackingProtectionValue(state)
|
||||||
|
|
||||||
fun verifyAddPrivateBrowsingShortcutButton() = assertAddPrivateBrowsingShortcutButton()
|
fun verifyAddPrivateBrowsingShortcutButton() = assertPrivateBrowsingButton()
|
||||||
fun verifySitePermissionsButton() = assertSitePermissionsButton()
|
fun verifySitePermissionsButton() = assertSitePermissionsButton()
|
||||||
fun verifyDeleteBrowsingDataButton() = assertDeleteBrowsingDataButton()
|
fun verifyDeleteBrowsingDataButton() = assertDeleteBrowsingDataButton()
|
||||||
fun verifyDeleteBrowsingDataOnQuitButton() = assertDeleteBrowsingDataOnQuitButton()
|
fun verifyDeleteBrowsingDataOnQuitButton() = assertDeleteBrowsingDataOnQuitButton()
|
||||||
|
@ -101,10 +102,10 @@ class SettingsRobot {
|
||||||
return SettingsSubMenuSearchRobot.Transition()
|
return SettingsSubMenuSearchRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openThemeSubMenu(interact: SettingsSubMenuThemeRobot.() -> Unit): SettingsSubMenuThemeRobot.Transition {
|
fun openCustomizeSubMenu(interact: SettingsSubMenuThemeRobot.() -> Unit): SettingsSubMenuThemeRobot.Transition {
|
||||||
|
|
||||||
fun themeButton() = onView(ViewMatchers.withText("Theme"))
|
fun customizeButton() = onView(ViewMatchers.withText("Customize"))
|
||||||
themeButton().click()
|
customizeButton().click()
|
||||||
|
|
||||||
SettingsSubMenuThemeRobot().interact()
|
SettingsSubMenuThemeRobot().interact()
|
||||||
return SettingsSubMenuThemeRobot.Transition()
|
return SettingsSubMenuThemeRobot.Transition()
|
||||||
|
@ -145,19 +146,27 @@ class SettingsRobot {
|
||||||
SettingsSubMenuLoginsAndPasswordRobot().interact()
|
SettingsSubMenuLoginsAndPasswordRobot().interact()
|
||||||
return SettingsSubMenuLoginsAndPasswordRobot.Transition()
|
return SettingsSubMenuLoginsAndPasswordRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openTurnOnSyncMenu(interact: SettingsTurnOnSyncRobot.() -> Unit): SettingsTurnOnSyncRobot.Transition {
|
||||||
|
fun turnOnSyncButton() = onView(ViewMatchers.withText("Turn on Sync"))
|
||||||
|
turnOnSyncButton().click()
|
||||||
|
|
||||||
|
SettingsTurnOnSyncRobot().interact()
|
||||||
|
return SettingsTurnOnSyncRobot.Transition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertSettingsView() {
|
private fun assertSettingsView() {
|
||||||
// verify that we are in the correct library view
|
// verify that we are in the correct library view
|
||||||
assertBasicsHeading()
|
assertGeneralHeading()
|
||||||
assertPrivacyHeading()
|
assertPrivacyHeading()
|
||||||
assertDeveloperToolsHeading()
|
assertDeveloperToolsHeading()
|
||||||
assertAboutHeading()
|
assertAboutHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BASICS SECTION
|
// GENERAL SECTION
|
||||||
private fun assertBasicsHeading() = onView(ViewMatchers.withText("Basics"))
|
private fun assertGeneralHeading() = onView(ViewMatchers.withText("General"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertSearchEngineButton() {
|
private fun assertSearchEngineButton() {
|
||||||
|
@ -166,7 +175,7 @@ private fun assertSearchEngineButton() {
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertThemeButton() = onView(ViewMatchers.withText("Theme"))
|
private fun assertCustomizeButton() = onView(ViewMatchers.withText("Customize"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertThemeSelected() = onView(ViewMatchers.withText("Light"))
|
private fun assertThemeSelected() = onView(ViewMatchers.withText("Light"))
|
||||||
|
@ -181,7 +190,7 @@ private fun assertSetAsDefaultBrowserButton() =
|
||||||
|
|
||||||
// PRIVACY SECTION
|
// PRIVACY SECTION
|
||||||
private fun assertPrivacyHeading() {
|
private fun assertPrivacyHeading() {
|
||||||
onView(ViewMatchers.withText("Privacy"))
|
onView(ViewMatchers.withText("Privacy and security"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,10 +211,10 @@ private fun assertLoginsButton() {
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAddPrivateBrowsingShortcutButton() {
|
private fun assertPrivateBrowsingButton() {
|
||||||
TestHelper.scrollToElementByText("Add private browsing shortcut")
|
TestHelper.scrollToElementByText("Private browsing")
|
||||||
mDevice.wait(Until.findObject(By.text("Add private browsing shortcut")), waitingTime)
|
mDevice.wait(Until.findObject(By.text("Private browsing")), waitingTime)
|
||||||
onView(ViewMatchers.withText("Add private browsing shortcut"))
|
onView(ViewMatchers.withText("Private browsing"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,19 +259,19 @@ private fun assertRemoteDebug() {
|
||||||
private fun assertAboutHeading(): ViewInteraction {
|
private fun assertAboutHeading(): ViewInteraction {
|
||||||
TestHelper.scrollToElementByText("About")
|
TestHelper.scrollToElementByText("About")
|
||||||
return onView(ViewMatchers.withText("About"))
|
return onView(ViewMatchers.withText("About"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(isCompletelyDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertRateOnGooglePlay(): ViewInteraction {
|
private fun assertRateOnGooglePlay(): ViewInteraction {
|
||||||
TestHelper.scrollToElementByText("About Firefox Preview")
|
TestHelper.scrollToElementByText("About Firefox Preview")
|
||||||
return onView(ViewMatchers.withText("Rate on Google Play"))
|
return onView(ViewMatchers.withText("Rate on Google Play"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(isCompletelyDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAboutFirefoxPreview(): ViewInteraction {
|
private fun assertAboutFirefoxPreview(): ViewInteraction {
|
||||||
TestHelper.scrollToElementByText("About Firefox Preview")
|
TestHelper.scrollToElementByText("About Firefox Preview")
|
||||||
return onView(ViewMatchers.withText("About Firefox Preview"))
|
return onView(ViewMatchers.withText("About Firefox Preview"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(isCompletelyDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun swipeToBottom() = onView(ViewMatchers.withId(R.id.recycler_view)).perform(ViewActions.swipeUp())
|
fun swipeToBottom() = onView(ViewMatchers.withId(R.id.recycler_view)).perform(ViewActions.swipeUp())
|
||||||
|
|
|
@ -6,27 +6,67 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
import androidx.test.espresso.Espresso
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
|
||||||
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 android.view.KeyEvent
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
|
||||||
|
import android.view.KeyEvent.ACTION_DOWN
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.SeekBar
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.test.espresso.UiController
|
||||||
|
import androidx.test.espresso.ViewAction
|
||||||
|
import androidx.test.espresso.ViewAssertion
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
||||||
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.mozilla.fenix.components.Components
|
||||||
|
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.DECIMAL_CONVERSION
|
||||||
|
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.MIN_VALUE
|
||||||
|
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.STEP_SIZE
|
||||||
|
import org.mozilla.fenix.ui.robots.SettingsSubMenuAccessibilityRobot.Companion.TEXT_SIZE
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the settings Accessibility sub menu.
|
* Implementation of Robot Pattern for the settings Accessibility sub menu.
|
||||||
*/
|
*/
|
||||||
class SettingsSubMenuAccessibilityRobot {
|
class SettingsSubMenuAccessibilityRobot {
|
||||||
|
|
||||||
fun verifyAutomaticFontSizing() = assertAutomaticFontSizing()
|
companion object {
|
||||||
|
const val STEP_SIZE = 5
|
||||||
|
const val MIN_VALUE = 50
|
||||||
|
const val DECIMAL_CONVERSION = 100f
|
||||||
|
const val TEXT_SIZE = 16f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyAutomaticFontSizingMenuItems() = assertAutomaticFontSizingMenuItems()
|
||||||
|
|
||||||
|
fun clickFontSizingSwitch() = toggleFontSizingSwitch()
|
||||||
|
|
||||||
|
fun verifyNewMenuItems() = assertNewMenuItems()
|
||||||
|
|
||||||
|
fun verifyNewMenuItemsAreGone() = assertNewMenuItemsAreGone()
|
||||||
|
|
||||||
|
fun changeTextSizeSlider(seekBarPercentage: Int) = adjustTextSizeSlider(seekBarPercentage)
|
||||||
|
|
||||||
|
fun verifyTextSizePercentage(textSize: Int) = assertTextSizePercentage(textSize)
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
goBackButton().perform(ViewActions.click())
|
goBackButton().perform(click())
|
||||||
|
|
||||||
SettingsRobot().interact()
|
SettingsRobot().interact()
|
||||||
return SettingsRobot.Transition()
|
return SettingsRobot.Transition()
|
||||||
|
@ -34,13 +74,127 @@ class SettingsSubMenuAccessibilityRobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAutomaticFontSizing() {
|
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
Espresso.onView(ViewMatchers.withText("Automatic Font Sizing"))
|
|
||||||
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
private fun assertAutomaticFontSizingMenuItems() {
|
||||||
|
onView(withText("Automatic Font Sizing"))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
val strFont = "Font size will match your Android settings. Disable to manage font size here."
|
val strFont = "Font size will match your Android settings. Disable to manage font size here."
|
||||||
Espresso.onView(ViewMatchers.withText(strFont))
|
onView(withText(strFont))
|
||||||
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleFontSizingSwitch() {
|
||||||
|
// Toggle font size to off
|
||||||
|
onView(withText("Automatic Font Sizing"))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertNewMenuItems() {
|
||||||
|
assertFontSize()
|
||||||
|
assertSliderBar()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertFontSize() {
|
||||||
|
val view = onView(withText("Font Size"))
|
||||||
|
view.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
val strFont = "Make text on websites larger or smaller"
|
||||||
|
onView(withText(strFont))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertSliderBar() {
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.sampleText))
|
||||||
|
.check(matches(withText("This is sample text. It is here to show how text will appear when you increase or decrease the size with this setting.")))
|
||||||
|
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.seekbar_value))
|
||||||
|
.check(matches(withText("100%")))
|
||||||
|
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.seekbar))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adjustTextSizeSlider(seekBarPercentage: Int) {
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.seekbar))
|
||||||
|
.perform(SeekBarChangeProgressViewAction(seekBarPercentage))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertTextSizePercentage(textSize: Int) {
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.sampleText))
|
||||||
|
.check(textSizePercentageEquals(textSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertNewMenuItemsAreGone() {
|
||||||
|
onView(withText("Font Size")).check(doesNotExist())
|
||||||
|
val strFont = "Make text on websites larger or smaller"
|
||||||
|
onView(withText(strFont))
|
||||||
|
.check(doesNotExist())
|
||||||
|
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.sampleText))
|
||||||
|
.check(doesNotExist())
|
||||||
|
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.seekbar_value))
|
||||||
|
.check(doesNotExist())
|
||||||
|
|
||||||
|
onView(withId(org.mozilla.fenix.R.id.seekbar))
|
||||||
|
.check(doesNotExist())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goBackButton() =
|
private fun goBackButton() =
|
||||||
Espresso.onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
|
onView(allOf(withContentDescription("Navigate up")))
|
||||||
|
|
||||||
|
class SeekBarChangeProgressViewAction(val seekBarPercentage: Int) : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View> {
|
||||||
|
return isAssignableFrom(SeekBar::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun perform(uiController: UiController?, view: View?) {
|
||||||
|
val targetStepSize = calculateStepSizeFromPercentage(seekBarPercentage)
|
||||||
|
val seekbar = view as SeekBar
|
||||||
|
var progress = seekbar.progress
|
||||||
|
|
||||||
|
if (targetStepSize > progress) {
|
||||||
|
for (i in progress until targetStepSize) {
|
||||||
|
seekbar.onKeyDown(KEYCODE_DPAD_RIGHT, KeyEvent(ACTION_DOWN, KEYCODE_DPAD_RIGHT))
|
||||||
|
}
|
||||||
|
} else if (progress > targetStepSize) {
|
||||||
|
for (i in progress downTo targetStepSize) {
|
||||||
|
seekbar.onKeyDown(KEYCODE_DPAD_LEFT, KeyEvent(ACTION_DOWN, KEYCODE_DPAD_LEFT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescription(): String {
|
||||||
|
return "Changes the progress on a SeekBar, based on the percentage value."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun textSizePercentageEquals(textSizePercentage: Int): ViewAssertion {
|
||||||
|
return ViewAssertion { view, noViewFoundException ->
|
||||||
|
if (noViewFoundException != null) throw noViewFoundException
|
||||||
|
|
||||||
|
val textView = view as TextView
|
||||||
|
val scaledPixels =
|
||||||
|
textView.textSize / InstrumentationRegistry.getInstrumentation().context.resources.displayMetrics.scaledDensity
|
||||||
|
val currentTextSizePercentage = calculateTextPercentageFromTextSize(scaledPixels)
|
||||||
|
|
||||||
|
if (currentTextSizePercentage != textSizePercentage) throw AssertionError("The textview has a text size percentage of $currentTextSizePercentage, and does not match $textSizePercentage")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateTextPercentageFromTextSize(textSize: Float): Int {
|
||||||
|
val decimal = textSize / TEXT_SIZE
|
||||||
|
return (decimal * DECIMAL_CONVERSION).roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateStepSizeFromPercentage(textSizePercentage: Int): Int {
|
||||||
|
return ((textSizePercentage - MIN_VALUE) / STEP_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkTextSizeOnWebsite(textSizePercentage: Int, components: Components): Boolean {
|
||||||
|
// Checks the Gecko engine settings for the font size
|
||||||
|
val textSize = calculateStepSizeFromPercentage(textSizePercentage)
|
||||||
|
val newTextScale = ((textSize * STEP_SIZE) + MIN_VALUE).toFloat() / DECIMAL_CONVERSION
|
||||||
|
return components.core.engine.settings.fontSizeFactor == newTextScale
|
||||||
|
}
|
||||||
|
|
|
@ -8,18 +8,37 @@ package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.intent.Intents.intended
|
||||||
|
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withParent
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
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.allOf
|
||||||
|
import org.hamcrest.CoreMatchers.not
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ui.robots.SettingsSubMenuDefaultBrowserRobot.Companion.DEFAULT_APPS_SETTINGS_ACTION
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the settings DefaultBrowser sub menu.
|
* Implementation of Robot Pattern for the settings DefaultBrowser sub menu.
|
||||||
*/
|
*/
|
||||||
class SettingsSubMenuDefaultBrowserRobot {
|
class SettingsSubMenuDefaultBrowserRobot {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_APPS_SETTINGS_ACTION = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"
|
||||||
|
}
|
||||||
|
|
||||||
fun verifyOpenLinksInPrivateTab() = assertOpenLinksInPrivateTab()
|
fun verifyOpenLinksInPrivateTab() = assertOpenLinksInPrivateTab()
|
||||||
|
fun verifyDefaultBrowserIsDisabled() = assertDefaultBrowserIsDisabled()
|
||||||
|
fun clickDefaultBrowserSwitch() = toggleDefaultBrowserSwitch()
|
||||||
|
fun verifyAndroidDefaultAppsMenuAppears() = assertAndroidDefaultAppsMenuAppears()
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
@ -34,10 +53,29 @@ class SettingsSubMenuDefaultBrowserRobot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assertDefaultBrowserIsDisabled() {
|
||||||
|
onView(withId(R.id.switch_widget))
|
||||||
|
.check(matches(isNotChecked()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleDefaultBrowserSwitch() {
|
||||||
|
onView(
|
||||||
|
allOf(
|
||||||
|
withParent(not(withId(R.id.navigationToolbar))),
|
||||||
|
withText("Set as default browser")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertAndroidDefaultAppsMenuAppears() {
|
||||||
|
intended(hasAction(DEFAULT_APPS_SETTINGS_ACTION))
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertOpenLinksInPrivateTab() {
|
private fun assertOpenLinksInPrivateTab() {
|
||||||
onView(ViewMatchers.withText("Open links in private tab"))
|
onView(withText("Open links in private tab"))
|
||||||
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goBackButton() =
|
private fun goBackButton() =
|
||||||
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
|
onView(allOf(withContentDescription("Navigate up")))
|
||||||
|
|
|
@ -6,13 +6,18 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.UiController
|
||||||
|
import androidx.test.espresso.ViewAction
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
||||||
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
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.mozilla.fenix.helpers.TestHelper
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.isChecked
|
import org.mozilla.fenix.helpers.isChecked
|
||||||
|
|
||||||
|
@ -38,8 +43,26 @@ class SettingsSubMenuEnhancedTrackingProtectionRobot {
|
||||||
return SettingsRobot.Transition()
|
return SettingsRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openExceptions(interact: SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.Transition {
|
fun openExceptions(
|
||||||
openExceptions().click()
|
interact: SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.() -> Unit
|
||||||
|
): SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.Transition {
|
||||||
|
TestHelper.scrollToElementByText("Exceptions")
|
||||||
|
openExceptions().perform(
|
||||||
|
object : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View> {
|
||||||
|
// do not check constraints, check if enabled
|
||||||
|
return ViewMatchers.isEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescription(): String {
|
||||||
|
return "Exceptions"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun perform(uiController: UiController?, view: View) {
|
||||||
|
view.performClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot().interact()
|
SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot().interact()
|
||||||
return SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.Transition()
|
return SettingsSubMenuEnhancedTrackingProtectionExceptionsRobot.Transition()
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* 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.robots
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
import org.hamcrest.CoreMatchers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of Robot Pattern for the Privacy Settings > saved logins sub menu
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SettingsSubMenuLoginsAndPasswordOptionsToSaveRobot {
|
||||||
|
fun verifySaveLoginsOptionsView() {
|
||||||
|
onView(ViewMatchers.withText("Ask to save"))
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
onView(ViewMatchers.withText("Never save"))
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Transition {
|
||||||
|
fun goBack(interact: SettingsSubMenuLoginsAndPasswordRobot.() -> Unit): SettingsSubMenuLoginsAndPasswordRobot.Transition {
|
||||||
|
goBackButton().perform(ViewActions.click())
|
||||||
|
|
||||||
|
SettingsSubMenuLoginsAndPasswordRobot().interact()
|
||||||
|
return SettingsSubMenuLoginsAndPasswordRobot.Transition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun goBackButton() =
|
||||||
|
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
|
|
@ -65,6 +65,14 @@ class SettingsSubMenuLoginsAndPasswordRobot {
|
||||||
SettingsTurnOnSyncRobot().interact()
|
SettingsTurnOnSyncRobot().interact()
|
||||||
return SettingsTurnOnSyncRobot.Transition()
|
return SettingsTurnOnSyncRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun saveLoginsAndPasswordsOptions(interact: SettingsSubMenuLoginsAndPasswordOptionsToSaveRobot.() -> Unit): SettingsSubMenuLoginsAndPasswordOptionsToSaveRobot.Transition {
|
||||||
|
fun saveLoginsAndPasswordButton() = onView(ViewMatchers.withText("Save logins and passwords"))
|
||||||
|
saveLoginsAndPasswordButton().click()
|
||||||
|
|
||||||
|
SettingsSubMenuLoginsAndPasswordOptionsToSaveRobot().interact()
|
||||||
|
return SettingsSubMenuLoginsAndPasswordOptionsToSaveRobot.Transition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
@ -29,6 +30,11 @@ class SettingsSubMenuLoginsAndPasswordsSavedLoginsRobot {
|
||||||
|
|
||||||
fun tapSetupLater() = onView(ViewMatchers.withText("Later")).perform(ViewActions.click())
|
fun tapSetupLater() = onView(ViewMatchers.withText("Later")).perform(ViewActions.click())
|
||||||
|
|
||||||
|
fun verifySavedLoginFromPrompt() = mDevice.waitNotNull(Until.findObjects(By.text("test@example.com")))
|
||||||
|
|
||||||
|
fun verifyNotSavedLoginFromPromt() = onView(ViewMatchers.withText("test@example.com"))
|
||||||
|
.check(ViewAssertions.doesNotExist())
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
fun goBack(interact: SettingsSubMenuLoginsAndPasswordRobot.() -> Unit): SettingsSubMenuLoginsAndPasswordRobot.Transition {
|
fun goBack(interact: SettingsSubMenuLoginsAndPasswordRobot.() -> Unit): SettingsSubMenuLoginsAndPasswordRobot.Transition {
|
||||||
goBackButton().perform(ViewActions.click())
|
goBackButton().perform(ViewActions.click())
|
||||||
|
|
|
@ -8,14 +8,15 @@ package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
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
|
||||||
|
@ -31,13 +32,17 @@ class SettingsSubMenuSearchRobot {
|
||||||
fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions()
|
fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions()
|
||||||
fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory()
|
fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory()
|
||||||
fun verifySearchBookmarks() = assertSearchBookmarks()
|
fun verifySearchBookmarks() = assertSearchBookmarks()
|
||||||
|
fun changeDefaultSearchEngine(searchEngineName: String) =
|
||||||
|
selectDefaultSearchEngine(searchEngineName)
|
||||||
|
|
||||||
|
fun disableShowSearchSuggestions() = toggleShowSearchSuggestions()
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
goBackButton().perform(ViewActions.click())
|
goBackButton().perform(click())
|
||||||
|
|
||||||
SettingsRobot().interact()
|
SettingsRobot().interact()
|
||||||
return SettingsRobot.Transition()
|
return SettingsRobot.Transition()
|
||||||
|
@ -46,24 +51,24 @@ class SettingsSubMenuSearchRobot {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertDefaultSearchEngineHeader() =
|
private fun assertDefaultSearchEngineHeader() =
|
||||||
onView(ViewMatchers.withText("Default search engine"))
|
onView(withText("Default search engine"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertSearchEngineList() {
|
private fun assertSearchEngineList() {
|
||||||
onView(ViewMatchers.withText("Google"))
|
onView(withText("Google"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("Amazon.com"))
|
onView(withText("Amazon.com"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("Bing"))
|
onView(withText("Bing"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("DuckDuckGo"))
|
onView(withText("DuckDuckGo"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("Twitter"))
|
onView(withText("Twitter"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("Wikipedia"))
|
onView(withText("Wikipedia"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
onView(ViewMatchers.withText("Add search engine"))
|
onView(withText("Add search engine"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertShowSearchSuggestions() {
|
private fun assertShowSearchSuggestions() {
|
||||||
|
@ -72,8 +77,8 @@ private fun assertShowSearchSuggestions() {
|
||||||
hasDescendant(withText("Show search suggestions"))
|
hasDescendant(withText("Show search suggestions"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
onView(ViewMatchers.withText("Show search suggestions"))
|
onView(withText("Show search suggestions"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertShowSearchShortcuts() {
|
private fun assertShowSearchShortcuts() {
|
||||||
|
@ -82,8 +87,8 @@ private fun assertShowSearchShortcuts() {
|
||||||
hasDescendant(withText("Show search shortcuts"))
|
hasDescendant(withText("Show search shortcuts"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
onView(ViewMatchers.withText("Show search shortcuts"))
|
onView(withText("Show search shortcuts"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertShowClipboardSuggestions() {
|
private fun assertShowClipboardSuggestions() {
|
||||||
|
@ -92,8 +97,8 @@ private fun assertShowClipboardSuggestions() {
|
||||||
hasDescendant(withText("Show clipboard suggestions"))
|
hasDescendant(withText("Show clipboard suggestions"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
onView(ViewMatchers.withText("Show clipboard suggestions"))
|
onView(withText("Show clipboard suggestions"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertSearchBrowsingHistory() {
|
private fun assertSearchBrowsingHistory() {
|
||||||
|
@ -102,8 +107,8 @@ private fun assertSearchBrowsingHistory() {
|
||||||
hasDescendant(withText("Search browsing history"))
|
hasDescendant(withText("Search browsing history"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
onView(ViewMatchers.withText("Search browsing history"))
|
onView(withText("Search browsing history"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertSearchBookmarks() {
|
private fun assertSearchBookmarks() {
|
||||||
|
@ -112,9 +117,30 @@ private fun assertSearchBookmarks() {
|
||||||
hasDescendant(withText("Search bookmarks"))
|
hasDescendant(withText("Search bookmarks"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
onView(ViewMatchers.withText("Search bookmarks"))
|
onView(withText("Search bookmarks"))
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectDefaultSearchEngine(searchEngine: String) {
|
||||||
|
onView(withText(searchEngine))
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectDuckDuckGoAsSearchEngine() {
|
||||||
|
selectDefaultSearchEngine("DuckDuckGo")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleShowSearchSuggestions() {
|
||||||
|
onView(withId(androidx.preference.R.id.recycler_view)).perform(
|
||||||
|
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
||||||
|
hasDescendant(withText("Show search suggestions"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
onView(withText("Show search suggestions"))
|
||||||
|
.perform(click())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goBackButton() =
|
private fun goBackButton() =
|
||||||
onView(CoreMatchers.allOf(ViewMatchers.withContentDescription("Navigate up")))
|
onView(CoreMatchers.allOf(withContentDescription("Navigate up")))
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.ViewInteraction
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
@ -25,7 +27,8 @@ class SettingsSubMenuThemeRobot {
|
||||||
|
|
||||||
fun verifyThemes() = assertThemes()
|
fun verifyThemes() = assertThemes()
|
||||||
|
|
||||||
fun verifyLightThemeApplied(expected: Boolean) = assertFalse("Light theme not selected", expected)
|
fun verifyLightThemeApplied(expected: Boolean) =
|
||||||
|
assertFalse("Light theme not selected", expected)
|
||||||
|
|
||||||
fun verifyDarkThemeApplied(expected: Boolean) = assertTrue("Dark theme not selected", expected)
|
fun verifyDarkThemeApplied(expected: Boolean) = assertTrue("Dark theme not selected", expected)
|
||||||
|
|
||||||
|
@ -47,18 +50,23 @@ class SettingsSubMenuThemeRobot {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertThemes() {
|
private fun assertThemes() {
|
||||||
onView(withText("Light"))
|
lightModeToggle()
|
||||||
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
onView(withText("Dark"))
|
darkModeToggle()
|
||||||
|
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
deviceModeToggle()
|
||||||
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
// Conditionally unavailable on API 25
|
|
||||||
// onView(ViewMatchers.withText("Follow device theme"))
|
|
||||||
// .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goBackButton() =
|
|
||||||
onView(allOf(ViewMatchers.withContentDescription("Navigate up")))
|
|
||||||
|
|
||||||
private fun darkModeToggle() = onView(withText("Dark"))
|
private fun darkModeToggle() = onView(withText("Dark"))
|
||||||
|
|
||||||
private fun lightModeToggle() = onView(withText("Light"))
|
private fun lightModeToggle() = onView(withText("Light"))
|
||||||
|
|
||||||
|
private fun deviceModeToggle(): ViewInteraction {
|
||||||
|
val followDeviceThemeText =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "Follow device theme" else "Set by Battery Saver"
|
||||||
|
return onView(withText(followDeviceThemeText))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun goBackButton() =
|
||||||
|
onView(allOf(ViewMatchers.withContentDescription("Navigate up")))
|
||||||
|
|
|
@ -6,16 +6,21 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasFocus
|
import androidx.test.espresso.matcher.ViewMatchers.hasFocus
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
@ -43,9 +48,11 @@ class ThreeDotMenuMainRobot {
|
||||||
fun verifyRefreshButton() = assertRefreshButton()
|
fun verifyRefreshButton() = assertRefreshButton()
|
||||||
fun verifyCloseAllTabsButton() = assertCloseAllTabsButton()
|
fun verifyCloseAllTabsButton() = assertCloseAllTabsButton()
|
||||||
fun verifyShareButton() = assertShareButton()
|
fun verifyShareButton() = assertShareButton()
|
||||||
|
fun verifyReaderViewToggle(visible: Boolean) = assertReaderViewToggle(visible)
|
||||||
|
fun verifyReaderViewAppearance(visible: Boolean) = assertReaderViewAppearanceButton(visible)
|
||||||
fun clickShareButton() {
|
fun clickShareButton() {
|
||||||
shareButton().click()
|
shareButton().click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.text("SHARE A LINK")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.text("ALL ACTIONS")), waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyShareTabButton() = assertShareTabButton()
|
fun verifyShareTabButton() = assertShareTabButton()
|
||||||
|
@ -72,6 +79,7 @@ class ThreeDotMenuMainRobot {
|
||||||
fun verifySendToDeviceTitle() = assertSendToDeviceTitle()
|
fun verifySendToDeviceTitle() = assertSendToDeviceTitle()
|
||||||
fun verifyShareALinkTitle() = assertShareALinkTitle()
|
fun verifyShareALinkTitle() = assertShareALinkTitle()
|
||||||
fun verifyWhatsNewButton() = assertWhatsNewButton()
|
fun verifyWhatsNewButton() = assertWhatsNewButton()
|
||||||
|
fun verifyAddFirefoxHome() = assertAddToFirefoxHome()
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
|
|
||||||
|
@ -182,11 +190,41 @@ class ThreeDotMenuMainRobot {
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun typeCollectionName(name: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun typeCollectionName(
|
||||||
mDevice.wait(Until.findObject(By.res("org.mozilla.fenix.debug:id/name_collection_edittext")), waitingTime)
|
name: String,
|
||||||
|
interact: BrowserRobot.() -> Unit
|
||||||
|
): BrowserRobot.Transition {
|
||||||
|
mDevice.wait(
|
||||||
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/name_collection_edittext")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
|
|
||||||
collectionNameTextField().check(matches(hasFocus()))
|
collectionNameTextField().check(matches(hasFocus()))
|
||||||
collectionNameTextField().perform(ViewActions.replaceText(name), ViewActions.pressImeActionButton())
|
collectionNameTextField().perform(
|
||||||
|
ViewActions.replaceText(name),
|
||||||
|
ViewActions.pressImeActionButton()
|
||||||
|
)
|
||||||
|
|
||||||
|
BrowserRobot().interact()
|
||||||
|
return BrowserRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleReaderView(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {
|
||||||
|
readerViewToggle().click()
|
||||||
|
|
||||||
|
NavigationToolbarRobot().interact()
|
||||||
|
return NavigationToolbarRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openReaderViewAppearance(interact: ReaderViewRobot.() -> Unit): ReaderViewRobot.Transition {
|
||||||
|
readerViewAppearanceToggle().click()
|
||||||
|
|
||||||
|
ReaderViewRobot().interact()
|
||||||
|
return ReaderViewRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addToFirefoxHome(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
|
addToFirefoxHomeButton().click()
|
||||||
|
|
||||||
BrowserRobot().interact()
|
BrowserRobot().interact()
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
|
@ -198,8 +236,13 @@ private fun threeDotMenuRecyclerViewExists() {
|
||||||
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
|
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun settingsButton() = onView(allOf(withText(R.string.settings),
|
private fun settingsButton() = onView(
|
||||||
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
allOf(
|
||||||
|
withText(R.string.settings),
|
||||||
|
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private fun assertSettingsButton() = settingsButton()
|
private fun assertSettingsButton() = settingsButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
@ -247,8 +290,12 @@ private fun shareButton() = onView(ViewMatchers.withContentDescription("Share"))
|
||||||
private fun assertShareButton() = shareButton()
|
private fun assertShareButton() = shareButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun browserViewSaveCollectionButton() = onView(allOf(withText("Save to Collection"),
|
private fun browserViewSaveCollectionButton() = onView(
|
||||||
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
allOf(
|
||||||
|
withText("Save to Collection"),
|
||||||
|
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private fun saveCollectionButton() = onView(allOf(withText("Save to collection")))
|
private fun saveCollectionButton() = onView(allOf(withText("Save to collection")))
|
||||||
private fun assertSaveCollectionButton() = saveCollectionButton()
|
private fun assertSaveCollectionButton() = saveCollectionButton()
|
||||||
|
@ -276,13 +323,41 @@ private fun assertSendToDeviceTitle() = SendToDeviceTitle()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun ShareALinkTitle() =
|
private fun ShareALinkTitle() =
|
||||||
onView(allOf(withText("SHARE A LINK"), withResourceName("link_header")))
|
onView(allOf(withText("ALL ACTIONS"), withResourceName("apps_link_header")))
|
||||||
|
|
||||||
private fun assertShareALinkTitle() = ShareALinkTitle()
|
private fun assertShareALinkTitle() = ShareALinkTitle()
|
||||||
|
|
||||||
private fun whatsNewButton() = onView(
|
private fun whatsNewButton() = onView(
|
||||||
allOf(
|
allOf(
|
||||||
withText("What’s New"),
|
withText("What’s New"),
|
||||||
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private fun assertWhatsNewButton() = whatsNewButton()
|
private fun assertWhatsNewButton() = whatsNewButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun readerViewToggle() = onView(allOf(withText(R.string.browser_menu_read)))
|
||||||
|
private fun assertReaderViewToggle(visible: Boolean) = readerViewToggle()
|
||||||
|
.check(
|
||||||
|
if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun readerViewAppearanceToggle() =
|
||||||
|
onView(allOf(withText(R.string.browser_menu_read_appearance)))
|
||||||
|
|
||||||
|
private fun assertReaderViewAppearanceButton(visible: Boolean) = readerViewAppearanceToggle()
|
||||||
|
.check(
|
||||||
|
if (visible) matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) else ViewAssertions.doesNotExist()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun addToFirefoxHomeButton() =
|
||||||
|
onView(allOf(withText(R.string.browser_menu_add_to_top_sites)))
|
||||||
|
private fun assertAddToFirefoxHome() {
|
||||||
|
onView(withId(R.id.mozac_browser_menu_recyclerView))
|
||||||
|
.perform(
|
||||||
|
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
||||||
|
hasDescendant(withText(R.string.browser_menu_add_to_top_sites))
|
||||||
|
)
|
||||||
|
).check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#ff20123a</color>
|
||||||
|
</resources>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<resources>
|
||||||
|
<!-- Name of the application -->
|
||||||
|
<string name="app_name" translatable="false">Firefox Beta</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_tab_2"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_tab_2">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_TAB"
|
||||||
|
android:targetPackage="org.mozilla.firefox_beta"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_private_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_private_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_private_tab_2"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_private_tab_2">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_PRIVATE_TAB"
|
||||||
|
android:targetPackage="org.mozilla.firefox_beta"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|