Compare commits
No commits in common. 'fork' and 'iceraven-2.8.4' have entirely different histories.
fork
...
iceraven-2
@ -0,0 +1,152 @@
|
||||
projects:
|
||||
app:
|
||||
upstream_dependencies:
|
||||
- browser-domains
|
||||
- browser-engine-gecko
|
||||
- browser-errorpages
|
||||
- browser-icons
|
||||
- browser-menu
|
||||
- browser-menu2
|
||||
- browser-session-storage
|
||||
- browser-state
|
||||
- browser-storage-sync
|
||||
- browser-tabstray
|
||||
- browser-thumbnails
|
||||
- browser-toolbar
|
||||
- compose-awesomebar
|
||||
- compose-cfr
|
||||
- concept-awesomebar
|
||||
- concept-base
|
||||
- concept-engine
|
||||
- concept-fetch
|
||||
- concept-menu
|
||||
- concept-push
|
||||
- concept-storage
|
||||
- concept-sync
|
||||
- concept-tabstray
|
||||
- concept-toolbar
|
||||
- feature-accounts
|
||||
- feature-accounts-push
|
||||
- feature-addons
|
||||
- feature-app-links
|
||||
- feature-autofill
|
||||
- feature-awesomebar
|
||||
- feature-contextmenu
|
||||
- feature-customtabs
|
||||
- feature-downloads
|
||||
- feature-findinpage
|
||||
- feature-intent
|
||||
- feature-logins
|
||||
- feature-media
|
||||
- feature-privatemode
|
||||
- feature-prompts
|
||||
- feature-push
|
||||
- feature-pwa
|
||||
- feature-qr
|
||||
- feature-readerview
|
||||
- feature-recentlyclosed
|
||||
- feature-search
|
||||
- feature-session
|
||||
- feature-share
|
||||
- feature-sitepermissions
|
||||
- feature-syncedtabs
|
||||
- feature-tab-collections
|
||||
- feature-tabs
|
||||
- feature-toolbar
|
||||
- feature-top-sites
|
||||
- feature-webauthn
|
||||
- feature-webcompat
|
||||
- feature-webcompat-reporter
|
||||
- feature-webnotifications
|
||||
- lib-crash
|
||||
- lib-crash-sentry
|
||||
- lib-dataprotect
|
||||
- lib-publicsuffixlist
|
||||
- lib-push-firebase
|
||||
- lib-state
|
||||
- service-contile
|
||||
- service-digitalassetlinks
|
||||
- service-firefox-accounts
|
||||
- service-glean
|
||||
- service-location
|
||||
- service-nimbus
|
||||
- service-pocket
|
||||
- service-sync-autofill
|
||||
- service-sync-logins
|
||||
- support-base
|
||||
- support-images
|
||||
- support-ktx
|
||||
- support-locale
|
||||
- support-rusterrors
|
||||
- support-rusthttp
|
||||
- support-rustlog
|
||||
- support-test
|
||||
- support-test-libstate
|
||||
- support-utils
|
||||
- support-webextensions
|
||||
- ui-autocomplete
|
||||
- ui-colors
|
||||
- ui-icons
|
||||
- ui-tabcounter
|
||||
- ui-widgets
|
||||
variants:
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-debug.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-debug.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-debug.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-debug.apk
|
||||
build_type: debug
|
||||
name: fenixDebug
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-release-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-release-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-release-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-release-unsigned.apk
|
||||
build_type: release
|
||||
name: fenixRelease
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-nightly-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-nightly-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-nightly-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-nightly-unsigned.apk
|
||||
build_type: nightly
|
||||
name: fenixNightly
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-beta-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-beta-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-beta-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-beta-unsigned.apk
|
||||
build_type: beta
|
||||
name: fenixBeta
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-benchmark-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-benchmark-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-benchmark-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-benchmark-unsigned.apk
|
||||
build_type: benchmark
|
||||
name: fenixBenchmark
|
||||
- apks:
|
||||
- abi: noarch
|
||||
fileName: app-debug-androidTest.apk
|
||||
build_type: androidTest
|
||||
name: androidTest
|
@ -1,41 +0,0 @@
|
||||
# Definitions for jobs that run periodically. For details on the format, see
|
||||
# `taskcluster/taskgraph/cron/schema.py`. For documentation, see
|
||||
# `taskcluster/docs/cron.rst`.
|
||||
---
|
||||
|
||||
jobs:
|
||||
- name: nightly
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nd
|
||||
target-tasks-method: nightly
|
||||
when:
|
||||
- {hour: 5, minute: 0}
|
||||
- {hour: 17, minute: 0}
|
||||
- name: nightly-test
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nt
|
||||
target-tasks-method: nightly-test
|
||||
when:
|
||||
- {hour: 5, minute: 0}
|
||||
- name: fennec-production
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: fennec-production
|
||||
target-tasks-method: fennec-production
|
||||
when: [] # Force hook only
|
||||
- name: screenshots
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: screenshots-D
|
||||
target-tasks-method: screenshots
|
||||
when: [{weekday: 'Monday', hour: 10, minute: 0}]
|
||||
- name: legacy-api-ui-tests
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: legacy-api-ui
|
||||
target-tasks-method: legacy_api_ui_tests
|
||||
when:
|
||||
- {hour: 11, minute: 0}
|
||||
- {hour: 20, minute: 0}
|
@ -1,5 +0,0 @@
|
||||
# .git-blame-ignore-revs
|
||||
# For #27667 - Remove import-ordering from the list of disabled ktlint rules (#27680)
|
||||
9654b4dfb122b54b04369fe80a2f9c95811478e8
|
||||
# For #26844: Fix ktlint issues and remove them from baseline. (#26901)
|
||||
ffcef5ff2e3f78b6972dd16551f3f653b7035ccc
|
@ -1,31 +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/.
|
||||
|
||||
# This CODEOWNERS file defines individuals or teams that are responsible
|
||||
# for code in this repository. Code owners are automatically requested
|
||||
# for review when someone opens a pull request that modifies code that
|
||||
# they own. Order is important; the last matching pattern takes the most
|
||||
# precedence.
|
||||
# A CODEOWNERS file uses a pattern that follows the same rules used in
|
||||
# gitignore files. The pattern is followed by one or more GitHub usernames
|
||||
# or team names using the standard @username or @org/team-name format.
|
||||
# You can also refer to a user by an email address that has been added
|
||||
# to their GitHub account, for example user@example.com.
|
||||
# https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# WARNING: if there is a single syntax error in this file, CODEOWNERS
|
||||
# WILL NOT WORK AT ALL. Please be careful when editing this file.
|
||||
#
|
||||
# You can use the technique described in this blog post to validate
|
||||
# the paths you specify in .gitignore:
|
||||
# http://www.benjaminoakes.com/git/2018/08/10/Testing-changes-to-GitHub-CODEOWNERS/
|
||||
|
||||
# By default the Android Components team will be the owner for everything in
|
||||
# the repo. Unless a later match takes precedence.
|
||||
* @mozilla-mobile/ACT @mozilla-mobile/fenix
|
||||
/.cron.yml @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/.taskcluster.yml @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/automation/ @mozilla-mobile/fenix
|
||||
/taskcluster/ @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/.github/ @mozilla-mobile/fenix
|
@ -1,91 +0,0 @@
|
||||
name: "\U0001F41E Bug report"
|
||||
description: Create a report to help us improve.
|
||||
title: "[Bug]: "
|
||||
labels: ["\U0001F41E bug", "needs:triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
- Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean.
|
||||
- Have a look at ["I want to file an issue!"][info] for more information.
|
||||
- Read the [Community Participation Guidelines][guidelines] and the [Bugzilla Etiquette guidelines][bugzilla] before filing an issue.
|
||||
|
||||
[info]: https://github.com/mozilla-mobile/fenix#i-want-to-file-an-issue
|
||||
[guidelines]: https://www.mozilla.org/en-US/about/governance/policies/participation/
|
||||
[bugzilla]: https://bugzilla.mozilla.org/page.cgi?id=etiquette.html
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Steps to reproduce the behaviour.
|
||||
placeholder: |
|
||||
1. Have a tab open..
|
||||
2. Go to..
|
||||
3. Click on..
|
||||
4. Observe..
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
placeholder: A menu should open..
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual behaviour
|
||||
placeholder: The app closes unexpectedly..
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Device information
|
||||
- type: input
|
||||
attributes:
|
||||
label: Device name
|
||||
description: The name of the device model and manufacturer.
|
||||
placeholder: Google Pixel 2
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Android version
|
||||
description: You can find the Android version information in the About section of your device's system settings.
|
||||
placeholder: Android 10
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Firefox release type
|
||||
description: You can find this information in Settings -> About Firefox.
|
||||
options:
|
||||
- Firefox Nightly
|
||||
- Firefox Beta
|
||||
- Firefox
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Firefox version
|
||||
description: You can find this information in Settings -> About Firefox.
|
||||
placeholder: 89.0.10
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Device logs
|
||||
description: |
|
||||
Device logs or crash information can greatly aid in debugging. You can find some details here on how to [retrieve device logs or crash IDs][log].
|
||||
|
||||
[log]: https://github.com/mozilla-mobile/fenix/wiki/Logging-Crash-Information
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
If you have any additional information for us, use the field below.
|
||||
Please note, you can attach screenshots or screen recordings here, by
|
||||
dragging and dropping files in the field below.
|
||||
validations:
|
||||
required: false
|
@ -1,19 +0,0 @@
|
||||
---
|
||||
name: "⌛ Performance issue"
|
||||
about: Create a performance issue if the app is slow or it uses too much memory, disk space, battery, or network data
|
||||
title: ""
|
||||
labels: "performance"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Device information
|
||||
|
||||
* Android device: ?
|
||||
* Fenix version: ?
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
name: "\U0001F4BB Web content issue report"
|
||||
about: Create an issue specifically about something wrong with web content while using Fenix
|
||||
title: "[webcontent]"
|
||||
labels: "\U0001F4BB bug"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Site with issue and any steps to reproduce
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Does toggling Tracking Protection fix the issue? (Press the shield icon in the toolbar while on the site to see toggle)
|
||||
|
||||
### Can you reproduce in Chrome (or other non-Mozilla browser)?
|
||||
<!--- Note: If you can reproduce the same issue in Firefox for Android AND Chrome, this issue is very unlikely to be fixed by our teams. -->
|
||||
<!-- If you cannot reproduce in Chrome and know how to do so, please consider filing a Bugzilla issue here for faster triage https://bugzilla.mozilla.org/enter_bug.cgi?product=GeckoView&component=General -->
|
||||
|
||||
### Device information
|
||||
|
||||
* Android device: ?
|
||||
* Fenix version: ?
|
@ -1,24 +0,0 @@
|
||||
---
|
||||
name: "\U000026CF Investigative Spike"
|
||||
about: Create an investigation spike
|
||||
title: "[Spike]"
|
||||
|
||||
---
|
||||
|
||||
## Title
|
||||
Brief description of what needs to be investigated, including the User story for which the spike is needed.
|
||||
|
||||
## Description
|
||||
Description of what is being investigated, including:
|
||||
Method of investigation (engineering research, prototype, etc.
|
||||
Boundaries of investigation (time box to x hours, does not include UX, etc.)
|
||||
|
||||
## Deliverables
|
||||
Description of deliverables, including:
|
||||
Documentation of investigation results (within the spike ticket, or linked to it), including:
|
||||
Findings
|
||||
Recommendations
|
||||
List of possible user stories to implement recommendations, including estimates
|
||||
Next Steps
|
||||
Reach out to Product to go over results of investigation.
|
||||
|
@ -1,21 +0,0 @@
|
||||
---
|
||||
name: "\U0001F4C8 Telemetry User Story"
|
||||
about: Create a telemetry user story, assigned to an Epic to track telemetry
|
||||
title: "[Telemetry]"
|
||||
labels: Feature:Telemetry
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Description & Product Manager / Data Scientist User Story
|
||||
|
||||
## What questions will you answer with this data?
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ] ENG files a [DS JIRA](https://jira.mozilla.com/projects/DO/issues/DO-228?filter=allopenissues) request outlining their methodology.
|
||||
- [ ] DS sign off on instrumentation methodology addressing product questions.
|
||||
- [ ] Event pings can be queried via re:dash
|
||||
- [ ] Event pings can be queried via amplitude
|
||||
- [ ] We are sending telemetry events for the actions listed in the requirements
|
||||
- [ ] We have documented the telemetry
|
||||
- [ ] We have asked a data steward to [review](https://github.com/mozilla/data-review/blob/master/request.md) the telemetry
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
name: "\U0001F494 Intermittent UI Test Issue"
|
||||
about: Create an issue to help log a UI test failure
|
||||
labels: "eng:ui-test, intermittent-test"
|
||||
title: "Intermittent UI test failure - <Classname.testName>"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Firebase Test Run:
|
||||
Provide a Firebase test run report link here showcasing the problem
|
||||
### Stacktrace:
|
||||
### Build:
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
name: "\U0001F6A8 Intermittent Unit Test Issue"
|
||||
about: Create an issue to help log a Unit Test failure
|
||||
labels: "eng:intermittent-test"
|
||||
title: "Intermittent Unit Test failure - <Classname.testName>"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Test Run:
|
||||
Provide a test run report link here showcasing the problem (e.g, Taskcluster), and a link to the source Github event
|
||||
### Stacktrace:
|
||||
### Build:
|
@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
### Pull Request checklist
|
||||
<!-- Before submitting the PR, please address each item -->
|
||||
- [ ] **Tests**: This PR includes thorough tests or an explanation of why it does not
|
||||
- [ ] **Screenshots**: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not
|
||||
- [ ] **Accessibility**: The code in this PR follows [accessibility best practices](https://github.com/mozilla-mobile/shared-docs/blob/master/android/accessibility_guide.md) or does not include any user facing features. In addition, it includes a screenshot of a successful [accessibility scan](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) to ensure no new defects are added to the product.
|
||||
|
||||
### To download an APK when reviewing a PR:
|
||||
The PR runs an Android build check (`run-build`) that builds a `forkRelease` variant of the app. If it succeeds, then we upload the apks (signed with debug keys) via Github actions. We also generate a comment with some instructions and a link to help you find the downloads. You can also follow the instructions below:
|
||||
1. Click Details next to "run-build (pull_request_target)" after it finishes with a green checkmark.
|
||||
2. Click the "Artifacts" drop-down near the top right of the page.
|
||||
3. The apk links should be present in the drop-down menu. You can click on the suitable CPU architecture to download a zipped apk file.
|
||||
4. Unzip the file and install the apk.
|
@ -1,115 +0,0 @@
|
||||
name: Android build PR
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- fork
|
||||
jobs:
|
||||
run-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
- name: Build forkRelease variant of app
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
|
||||
|
||||
|
||||
run-testDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run tests
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: testDebug
|
||||
|
||||
|
||||
run-detekt:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run detekt
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: detekt
|
||||
- name: Archive detekt results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: detekt report
|
||||
path: build/reports/detekt.html
|
||||
|
||||
|
||||
run-ktlint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run ktlint
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: ktlint
|
||||
|
||||
|
||||
run-lintDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run lintDebug
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: lintDebug
|
||||
- name: Archive lint results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lintDebug report
|
||||
path: app/build/reports/lint-results-debug.html
|
@ -1,143 +0,0 @@
|
||||
name: Android build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- fork
|
||||
jobs:
|
||||
run-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
- name: Build forkRelease variant of app
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
|
||||
- name: Create signed APKs
|
||||
uses: abhijitvalluri/sign-apks@v0.8
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/forkRelease/
|
||||
signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
|
||||
alias: ${{ secrets.DEBUG_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
|
||||
- name: Archive arm64 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-arm64-v8a-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-arm64-v8a-forkRelease.apk
|
||||
- name: Archive armeabi apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-armeabi-v7a-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-armeabi-v7a-forkRelease.apk
|
||||
- name: Archive x86 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-x86-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-x86-forkRelease.apk
|
||||
- name: Archive x86_64 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-x86_64-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-x86_64-forkRelease.apk
|
||||
|
||||
|
||||
run-testDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run tests
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: testDebug
|
||||
|
||||
|
||||
run-detekt:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run detekt
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: detekt
|
||||
- name: Archive detekt results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: detekt report
|
||||
path: build/reports/detekt.html
|
||||
|
||||
|
||||
run-ktlint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run ktlint
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: ktlint
|
||||
|
||||
|
||||
run-lintDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run lintDebug
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: lintDebug
|
||||
- name: Archive lint results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lintDebug report
|
||||
path: app/build/reports/lint-results-debug.html
|
@ -1,24 +0,0 @@
|
||||
name: PR comment
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
branches:
|
||||
- fork
|
||||
jobs: # Disabled because we cannot build changes from fork PRs using this repo's secrets due to Github limitations. So, the built apk will be from wrong code, so this is pointless.
|
||||
comment-on-pr:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Comment on PR with link to checks page
|
||||
uses: mshick/add-pr-comment@v1
|
||||
with:
|
||||
message: |
|
||||
### Download the built apks
|
||||
You can download the apks built by Github actions **after** the CI checks pass.
|
||||
Please go to the <a href="${{ github.event.pull_request.html_url }}/checks">checks page for this PR</a> to find the zipped apk files under the artifacts drop-down, as seen in the example screenshot below.
|
||||
|
||||
Note that you will have to click on the "Android build PR" tab on the left side to see the artifacts.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/fork-maintainers/iceraven-browser/fork/.github/imgs/download-artifacts-screenshot.png" />
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allow-repeats: false
|
Binary file not shown.
Before Width: | Height: | Size: 99 KiB |
@ -1,63 +0,0 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 180
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- pin
|
||||
- "feature request 🌟"
|
||||
- "eng:disabled-test"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: wontfix
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
See: https://github.com/mozilla-mobile/fenix/issues/17373
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
# closeComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
issues:
|
||||
exemptLabels:
|
||||
- pin
|
||||
- "feature request 🌟"
|
@ -0,0 +1,86 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- iceraven
|
||||
|
||||
jobs:
|
||||
release-automation:
|
||||
name: Build App
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
|
||||
- name: Inspect memory
|
||||
run: free -h
|
||||
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: Patch on the fly
|
||||
run: sed -i 's#\.\./version.txt#\./version.txt#g' android-components/plugins/config/src/main/java/ConfigPlugin.kt
|
||||
|
||||
- name: Relpace strings
|
||||
run: |
|
||||
sed -i 's/Firefox/Iceraven/g' app/src/*/res/values*/*strings.xml
|
||||
sed -i '/about_content/s/Mozilla/@forkmaintainers/' app/src/*/res/values*/*strings.xml
|
||||
|
||||
- name: Build forkRelease variant of app
|
||||
uses: gradle/gradle-build-action@v2
|
||||
env:
|
||||
# Try to stop the daemon from magically vanishing by adding random memory-related arguments.
|
||||
# See <https://stackoverflow.com/a/70010526> and <https://stackoverflow.com/a/70756876>
|
||||
# The runner seems to have ~6 gigs of memory, so we make sure to stay under that.
|
||||
# We have Java 11 so we don't have a perm size anymore.
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-XX:MaxMetaspaceSize=2g -Xms1g -Xmx3g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dev/stderr"
|
||||
with:
|
||||
gradle-home-cache-cleanup: true
|
||||
gradle-executable: /usr/bin/time
|
||||
arguments: -v ./gradlew app:assemblefenixForkRelease -x lintVitalFenixForkRelease -PversionName=${{ env.VERSION_NAME }} --stacktrace
|
||||
|
||||
- name: Create signed APKs
|
||||
uses: abhijitvalluri/sign-apks@v0.8
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/fenix/forkRelease/
|
||||
signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
|
||||
alias: ${{ secrets.DEBUG_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
|
||||
|
||||
- name: Upload arm64 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-arm64-v8a-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-arm64-v8a-forkRelease.apk
|
||||
|
||||
- name: Upload armeabi apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-armeabi-v7a-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-armeabi-v7a-forkRelease.apk
|
||||
|
||||
- name: Upload x86 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-x86-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-x86-forkRelease.apk
|
||||
|
||||
- name: Upload x86_64 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-x86_64-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-x86_64-forkRelease.apk
|
@ -1,16 +0,0 @@
|
||||
name: AssignTriageLabel
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
assign:
|
||||
name: Triage Issues
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add Triage Label
|
||||
uses: boek/AddTriageLabel@v1.2
|
||||
with:
|
||||
repotoken: ${{ secrets.GITHUB_TOKEN }}
|
||||
labeltoadd: "needs:triage"
|
@ -0,0 +1,3 @@
|
||||
[submodule "android-components"]
|
||||
path = android-components
|
||||
url = https://github.com/akliuxingyuan/android-components
|
@ -1,122 +0,0 @@
|
||||
queue_rules:
|
||||
- name: default
|
||||
conditions:
|
||||
- status-success=complete-pr
|
||||
pull_request_rules:
|
||||
- name: Resolve conflict
|
||||
conditions:
|
||||
- conflict
|
||||
actions:
|
||||
comment:
|
||||
message: This pull request has conflicts when rebasing. Could you fix it @{{author}}? 🙏
|
||||
- name: MickeyMoz - Auto Merge
|
||||
conditions:
|
||||
- author=MickeyMoz
|
||||
- status-success=pr-complete
|
||||
- files~=(Gecko.kt|AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: MickeyMoz 💪
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: L10N - Auto Merge
|
||||
conditions:
|
||||
- author=mozilla-l10n-automation-bot
|
||||
- status-success=pr-complete
|
||||
- files~=(strings.xml|l10n.toml)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: LGTM 😎
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: Release automation (Old)
|
||||
conditions:
|
||||
- base~=releases[_/].*
|
||||
- author=github-actions[bot]
|
||||
# Listing checks manually beause we do not have a "push complete" check yet.
|
||||
- check-success=build-android-test-debug
|
||||
- check-success=build-debug
|
||||
- check-success=build-nightly-simulation
|
||||
- check-success=lint-compare-locales
|
||||
- check-success=lint-detekt
|
||||
- check-success=lint-ktlint
|
||||
- check-success=lint-lint
|
||||
- check-success=signing-android-test-debug
|
||||
- check-success=signing-debug
|
||||
- check-success=signing-nightly-simulation
|
||||
- check-success=test-debug
|
||||
# TODO Temporarily disabled - should be renamed to -build
|
||||
#- check-success=ui-test-x86-debug
|
||||
- files~=(AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: 🚢
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
delete_head_branch:
|
||||
force: false
|
||||
- name: Release automation (New)
|
||||
conditions:
|
||||
- base~=releases[_/].*
|
||||
- author=github-actions[bot]
|
||||
# Listing checks manually beause we do not have a "push complete" check yet.
|
||||
- check-success=build-android-test-beta
|
||||
- check-success=build-android-test-debug
|
||||
- check-success=build-beta-firebase
|
||||
- check-success=build-debug
|
||||
- check-success=build-nightly-simulation
|
||||
- check-success=lint-compare-locales
|
||||
- check-success=lint-detekt
|
||||
- check-success=lint-ktlint
|
||||
- check-success=lint-lint
|
||||
- check-success=signing-android-test-beta
|
||||
- check-success=signing-beta-firebase
|
||||
- check-success=signing-nightly-simulation
|
||||
- check-success=test-debug
|
||||
- check-success=ui-test-x86-beta
|
||||
- files~=(AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: 🚢
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
delete_head_branch:
|
||||
force: false
|
||||
- name: Needs landing - Rebase
|
||||
conditions:
|
||||
- check-success=pr-complete
|
||||
- label=pr:needs-landing
|
||||
- "#approved-reviews-by>=1"
|
||||
- -draft
|
||||
- label!=pr:work-in-progress
|
||||
- label!=pr:do-not-land
|
||||
actions:
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: Needs landing - Squash
|
||||
conditions:
|
||||
- check-success=pr-complete
|
||||
- label=pr:needs-landing-squashed
|
||||
- "#approved-reviews-by>=1"
|
||||
- -draft
|
||||
- label!=pr:work-in-progress
|
||||
- label!=pr:do-not-land
|
||||
actions:
|
||||
queue:
|
||||
method: squash
|
||||
name: default
|
||||
rebase_fallback: none
|
@ -1,293 +0,0 @@
|
||||
---
|
||||
version: 1
|
||||
reporting: checks-v1
|
||||
policy:
|
||||
# XXX We restrict taskcluster to collaborators so priviledged tests (like UI tests) can run on PRs
|
||||
pullRequests: collaborators
|
||||
tasks:
|
||||
- $let:
|
||||
trustDomain: mobile
|
||||
|
||||
# Github events have this stuff in different places...
|
||||
ownerEmail:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${tasks_for}@noreply.mozilla.org'
|
||||
else:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
$if: 'event.pusher.email'
|
||||
then: '${event.pusher.email}'
|
||||
else: '${event.pusher.name}@users.noreply.github.com'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.user.login}@users.noreply.github.com'
|
||||
baseRepoUrl:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.base.repo.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.url}'
|
||||
repoUrl:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.repo.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.url}'
|
||||
project:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.name}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.repo.name}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.project}'
|
||||
head_branch:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: ${event.pull_request.head.ref}
|
||||
else:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: ${event.ref}
|
||||
else:
|
||||
$if: 'tasks_for in ["action", "cron"]'
|
||||
then: '${push.branch}'
|
||||
head_sha:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.after}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.sha}'
|
||||
else:
|
||||
$if: 'tasks_for in ["action", "cron"]'
|
||||
then: '${push.revision}'
|
||||
ownTaskId:
|
||||
$if: '"github" in tasks_for'
|
||||
then: {$eval: as_slugid("decision_task")}
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${ownTaskId}'
|
||||
pullRequestAction:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: ${event.action}
|
||||
else: 'UNDEFINED'
|
||||
in:
|
||||
$if: >
|
||||
tasks_for in ["action", "cron"]
|
||||
|| (tasks_for == "github-pull-request" && pullRequestAction in ["opened", "reopened", "synchronize"])
|
||||
|| (tasks_for == "github-push" && head_branch[:10] != "refs/tags/") && (head_branch != "staging.tmp") && (head_branch != "trying.tmp") && (head_branch[:8] != "mergify/")
|
||||
then:
|
||||
$let:
|
||||
level:
|
||||
$if: 'tasks_for in ["github-push", "action", "cron"] && repoUrl == "https://github.com/mozilla-mobile/fenix"'
|
||||
then: '3'
|
||||
else: '1'
|
||||
short_head_branch:
|
||||
$if: 'head_branch[:11] == "refs/heads/"'
|
||||
then: {$eval: 'head_branch[11:]'}
|
||||
in:
|
||||
taskId:
|
||||
$if: 'tasks_for != "action"'
|
||||
then: '${ownTaskId}'
|
||||
taskGroupId:
|
||||
$if: 'tasks_for == "action"'
|
||||
then: '${action.taskGroupId}'
|
||||
else: '${ownTaskId}' # same as taskId; this is how automation identifies a decision task
|
||||
schedulerId: '${trustDomain}-level-${level}'
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '1 day'}
|
||||
expires: {$fromNow: '1 year 1 second'} # 1 second so artifacts expire first, despite rounding errors
|
||||
metadata:
|
||||
$merge:
|
||||
- owner: "${ownerEmail}"
|
||||
source: '${repoUrl}/raw/${head_sha}/.taskcluster.yml'
|
||||
- $if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
name: "Decision Task"
|
||||
description: 'The task that creates all of the other tasks in the task graph'
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
name: "Action: ${action.title}"
|
||||
description: |
|
||||
${action.description}
|
||||
|
||||
Action triggered by clientID `${clientId}`
|
||||
else:
|
||||
name: "Decision Task for cron job ${cron.job_name}"
|
||||
description: 'Created by a [cron task](https://firefox-ci-tc.services.mozilla.com/tasks/${cron.task_id})'
|
||||
provisionerId: "${trustDomain}-${level}"
|
||||
workerType: "decision-gcp"
|
||||
tags:
|
||||
$if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
kind: decision-task
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
kind: 'action-callback'
|
||||
else:
|
||||
$if: 'tasks_for == "cron"'
|
||||
then:
|
||||
kind: cron-task
|
||||
routes:
|
||||
$flattenDeep:
|
||||
- checks
|
||||
- $if: 'level == "3" || repoUrl == "https://github.com/mozilla-releng/staging-fenix"'
|
||||
then:
|
||||
- tc-treeherder.v2.${project}.${head_sha}
|
||||
# TODO Bug 1601928: Make this scope fork-friendly once ${project} is better defined. This will enable
|
||||
# staging release promotion on forks.
|
||||
- $if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
- index.${trustDomain}.v2.${project}.branch.${short_head_branch}.latest.taskgraph.decision
|
||||
- index.${trustDomain}.v2.${project}.branch.${short_head_branch}.revision.${head_sha}.taskgraph.decision
|
||||
- index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.decision
|
||||
- $if: 'tasks_for == "cron"'
|
||||
then:
|
||||
# cron context provides ${head_branch} as a short one
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.latest.taskgraph.decision-${cron.job_name}
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.revision.${head_sha}.taskgraph.decision-${cron.job_name}
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.revision.${head_sha}.taskgraph.cron.${ownTaskId}
|
||||
scopes:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
# `https://` is 8 characters so, ${repoUrl[8:]} is the repository without the protocol.
|
||||
- 'assume:repo:${repoUrl[8:]}:branch:${short_head_branch}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then:
|
||||
- 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:pull-request'
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
# when all actions are hooks, we can calculate this directly rather than using a variable
|
||||
- '${action.repo_scope}'
|
||||
else:
|
||||
- 'assume:repo:${repoUrl[8:]}:cron:${cron.job_name}'
|
||||
|
||||
requires: all-completed
|
||||
priority: lowest
|
||||
retries: 5
|
||||
payload:
|
||||
env:
|
||||
# run-task uses these to check out the source; the inputs
|
||||
# to `mach taskgraph decision` are all on the command line.
|
||||
$merge:
|
||||
- MOBILE_BASE_REPOSITORY: '${baseRepoUrl}'
|
||||
MOBILE_HEAD_REPOSITORY: '${repoUrl}'
|
||||
MOBILE_HEAD_REF: '${head_branch}'
|
||||
MOBILE_HEAD_REV: '${head_sha}'
|
||||
MOBILE_REPOSITORY_TYPE: git
|
||||
MOBILE_PIP_REQUIREMENTS: taskcluster/requirements.txt
|
||||
MOZ_AUTOMATION: "1"
|
||||
REPOSITORIES: {$json: {mobile: "Fenix"}}
|
||||
HG_STORE_PATH: /builds/worker/checkouts/hg-store
|
||||
ANDROID_SDK_ROOT: /builds/worker/android-sdk
|
||||
- $if: 'tasks_for in ["github-pull-request"]'
|
||||
then:
|
||||
MOBILE_PULL_REQUEST_NUMBER: '${event.pull_request.number}'
|
||||
- $if: 'tasks_for == "action"'
|
||||
then:
|
||||
ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task
|
||||
ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded)
|
||||
ACTION_INPUT: {$json: {$eval: 'input'}}
|
||||
ACTION_CALLBACK: '${action.cb_name}'
|
||||
features:
|
||||
taskclusterProxy: true
|
||||
chainOfTrust: true
|
||||
# Note: This task is built server side without the context or tooling that
|
||||
# exist in tree so we must hard code the hash
|
||||
image: mozillareleases/taskgraph:decision-mobile-625975b642c148be4c6f1d8ee5cedf7399f5d0dd33d275ff69d5934e3082d4a9@sha256:bfb26700182486e1c6c52701baea6f386fa39e5e25417423c27845933605ad43
|
||||
|
||||
maxRunTime: 1800
|
||||
|
||||
command:
|
||||
- /usr/local/bin/run-task
|
||||
- '--mobile-checkout=/builds/worker/checkouts/src'
|
||||
- '--task-cwd=/builds/worker/checkouts/src'
|
||||
- '--'
|
||||
- bash
|
||||
- -cx
|
||||
- $let:
|
||||
extraArgs:
|
||||
$if: 'tasks_for == "cron"'
|
||||
then: '${cron.quoted_args}'
|
||||
else: ''
|
||||
in:
|
||||
$if: 'tasks_for == "action"'
|
||||
then: >
|
||||
taskcluster/scripts/decision-install-sdk.sh &&
|
||||
ln -s /builds/worker/artifacts artifacts &&
|
||||
~/.local/bin/taskgraph action-callback
|
||||
else: >
|
||||
taskcluster/scripts/decision-install-sdk.sh &&
|
||||
ln -s /builds/worker/artifacts artifacts &&
|
||||
~/.local/bin/taskgraph decision
|
||||
--pushlog-id='0'
|
||||
--pushdate='0'
|
||||
--project='${project}'
|
||||
--message=""
|
||||
--owner='${ownerEmail}'
|
||||
--level='${level}'
|
||||
--base-repository="$MOBILE_BASE_REPOSITORY"
|
||||
--head-repository="$MOBILE_HEAD_REPOSITORY"
|
||||
--head-ref="$MOBILE_HEAD_REF"
|
||||
--head-rev="$MOBILE_HEAD_REV"
|
||||
--repository-type="$MOBILE_REPOSITORY_TYPE"
|
||||
--tasks-for='${tasks_for}'
|
||||
${extraArgs}
|
||||
|
||||
artifacts:
|
||||
'public':
|
||||
type: 'directory'
|
||||
path: '/builds/worker/artifacts'
|
||||
expires:
|
||||
$fromNow: '1 year'
|
||||
'public/docker-contexts':
|
||||
type: 'directory'
|
||||
path: '/builds/worker/checkouts/src/docker-contexts'
|
||||
# This needs to be at least the deadline of the
|
||||
# decision task + the docker-image task deadlines.
|
||||
# It is set to a week to allow for some time for
|
||||
# debugging, but they are not useful long-term.
|
||||
expires:
|
||||
$fromNow: '7 day'
|
||||
|
||||
extra:
|
||||
$merge:
|
||||
- treeherder:
|
||||
$merge:
|
||||
- machine:
|
||||
platform: gecko-decision
|
||||
- $if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
symbol: D
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
groupName: 'action-callback'
|
||||
groupSymbol: AC
|
||||
symbol: "${action.symbol}"
|
||||
else:
|
||||
groupSymbol: cron
|
||||
symbol: "${cron.job_symbol}"
|
||||
- $if: 'tasks_for == "action"'
|
||||
then:
|
||||
parent: '${action.taskGroupId}'
|
||||
action:
|
||||
name: '${action.name}'
|
||||
context:
|
||||
taskGroupId: '${action.taskGroupId}'
|
||||
taskId: {$eval: 'taskId'}
|
||||
input: {$eval: 'input'}
|
||||
clientId: {$eval: 'clientId'}
|
||||
- $if: 'tasks_for == "cron"'
|
||||
then:
|
||||
cron: {$json: {$eval: 'cron'}}
|
||||
- tasks_for: '${tasks_for}'
|
@ -1,16 +0,0 @@
|
||||
language: android
|
||||
dist: trusty
|
||||
script:
|
||||
# Prepare SDK
|
||||
- sudo mkdir -p /usr/local/android-sdk/licenses/
|
||||
- sudo touch /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "8933bad161af4178b1185d1a37fbf41ea5269c55" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "d56f5187479451eabf01fb78af6dfcb131a6481e" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
# The build needs this but Gradle refuses to fetch it.
|
||||
- sdkmanager "ndk;21.0.6113669"
|
||||
# Run tests
|
||||
- ./gradlew -q testDebug 2>&1
|
||||
# Make sure a release build builds
|
||||
- ./gradlew assembleForkRelease -PversionName="$(git describe --tags HEAD)"
|
||||
|
@ -1,373 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
@ -0,0 +1 @@
|
||||
Subproject commit 10bdc0f0a180ea2e892068ebd25e2e9183eb1c95
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,419 @@
|
||||
---
|
||||
about:
|
||||
description: Nimbus Feature Manifest for Fenix (Firefox Android)
|
||||
kotlin:
|
||||
package: org.mozilla.fenix
|
||||
class: .nimbus.FxNimbus
|
||||
channels:
|
||||
- release
|
||||
- beta
|
||||
- nightly
|
||||
- developer
|
||||
- forkDebug
|
||||
- forkRelease
|
||||
includes:
|
||||
- onboarding.fml.yaml
|
||||
import:
|
||||
- path: ../android-components/components/service/nimbus/messaging.fml.yaml
|
||||
channel: release
|
||||
features:
|
||||
messaging:
|
||||
- value:
|
||||
triggers:
|
||||
# Using attributes built into the Nimbus SDK
|
||||
USER_RECENTLY_INSTALLED: days_since_install < 7
|
||||
USER_RECENTLY_UPDATED: days_since_update < 7 && days_since_install != days_since_update
|
||||
USER_TIER_ONE_COUNTRY: ('US' in locale || 'GB' in locale || 'CA' in locale || 'DE' in locale || 'FR' in locale)
|
||||
USER_EN_SPEAKER: "'en' in locale"
|
||||
USER_ES_SPEAKER: "'es' in locale"
|
||||
USER_DE_SPEAKER: "'de' in locale"
|
||||
USER_FR_SPEAKER: "'fr' in locale"
|
||||
DEVICE_ANDROID: os == 'Android'
|
||||
DEVICE_IOS: os == 'iOS'
|
||||
ALWAYS: "true"
|
||||
NEVER: "false"
|
||||
DAY_1_AFTER_INSTALL: days_since_install == 1
|
||||
DAY_2_AFTER_INSTALL: days_since_install == 2
|
||||
DAY_3_AFTER_INSTALL: days_since_install == 3
|
||||
DAY_4_AFTER_INSTALL: days_since_install == 4
|
||||
DAY_5_AFTER_INSTALL: days_since_install == 5
|
||||
MORE_THAN_24H_SINCE_INSTALLED_OR_UPDATED: days_since_update >= 1
|
||||
|
||||
# Using custom attributes for the browser
|
||||
I_AM_DEFAULT_BROWSER: "is_default_browser"
|
||||
I_AM_NOT_DEFAULT_BROWSER: "is_default_browser == false"
|
||||
USER_ESTABLISHED_INSTALL: "number_of_app_launches >=4"
|
||||
|
||||
FUNNEL_PAID: "adjust_campaign != ''"
|
||||
FUNNEL_ORGANIC: "adjust_campaign == ''"
|
||||
|
||||
# Using Glean events, specific to the browser
|
||||
INACTIVE_1_DAY: "'app_launched'|eventLastSeen('Hours') >= 24"
|
||||
INACTIVE_2_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 2"
|
||||
INACTIVE_3_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 3"
|
||||
INACTIVE_4_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 4"
|
||||
INACTIVE_5_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 5"
|
||||
|
||||
# Has the user signed in the last 4 years
|
||||
FXA_SIGNED_IN: "'sync_auth.sign_in'|eventLastSeen('Years', 0) <= 4"
|
||||
FXA_NOT_SIGNED_IN: "'sync_auth.sign_in'|eventLastSeen('Years', 0) > 4"
|
||||
|
||||
# https://mozilla-hub.atlassian.net/wiki/spaces/FJT/pages/11469471/Core+Active
|
||||
USER_INFREQUENT: "'app_launched'|eventCountNonZero('Days', 28) >= 1 && 'app_launched'|eventCountNonZero('Days', 28) < 7"
|
||||
USER_CASUAL: "'app_launched'|eventCountNonZero('Days', 28) >= 7 && 'app_launched'|eventCountNonZero('Days', 28) < 14"
|
||||
USER_REGULAR: "'app_launched'|eventCountNonZero('Days', 28) >= 14 && 'app_launched'|eventCountNonZero('Days', 28) < 21"
|
||||
USER_CORE_ACTIVE: "'app_launched'|eventCountNonZero('Days', 28) >= 21"
|
||||
|
||||
LAUNCHED_ONCE_THIS_WEEK: "'app_launched'|eventSum('Days', 7) == 1"
|
||||
|
||||
actions:
|
||||
ENABLE_PRIVATE_BROWSING: ://enable_private_browsing
|
||||
INSTALL_SEARCH_WIDGET: ://install_search_widget
|
||||
MAKE_DEFAULT_BROWSER: ://make_default_browser
|
||||
VIEW_BOOKMARKS: ://urls_bookmarks
|
||||
VIEW_COLLECTIONS: ://home_collections
|
||||
VIEW_HISTORY: ://urls_history
|
||||
VIEW_HOMESCREEN: ://home
|
||||
OPEN_SETTINGS_ACCESSIBILITY: ://settings_accessibility
|
||||
OPEN_SETTINGS_ADDON_MANAGER: ://settings_addon_manager
|
||||
OPEN_SETTINGS_DELETE_BROWSING_DATA: ://settings_delete_browsing_data
|
||||
OPEN_SETTINGS_LOGINS: ://settings_logins
|
||||
OPEN_SETTINGS_NOTIFICATIONS: ://settings_notifications
|
||||
OPEN_SETTINGS_PRIVACY: ://settings_privacy
|
||||
OPEN_SETTINGS_SEARCH_ENGINE: ://settings_search_engine
|
||||
OPEN_SETTINGS_TRACKING_PROTECTION: ://settings_tracking_protection
|
||||
OPEN_SETTINGS_WALLPAPERS: ://settings_wallpapers
|
||||
OPEN_SETTINGS: ://settings
|
||||
TURN_ON_SYNC: ://turn_on_sync
|
||||
styles:
|
||||
DEFAULT:
|
||||
priority: 50
|
||||
max-display-count: 5
|
||||
SURVEY:
|
||||
priority: 55
|
||||
max-display-count: 1
|
||||
PERSISTENT:
|
||||
priority: 50
|
||||
max-display-count: 20
|
||||
WARNING:
|
||||
priority: 60
|
||||
max-display-count: 10
|
||||
URGENT:
|
||||
priority: 100
|
||||
max-display-count: 10
|
||||
NOTIFICATION:
|
||||
priority: 50
|
||||
max-display-count: 1
|
||||
messages:
|
||||
default-browser:
|
||||
text: default_browser_experiment_card_text
|
||||
surface: homescreen
|
||||
action: "MAKE_DEFAULT_BROWSER"
|
||||
trigger: [ "I_AM_NOT_DEFAULT_BROWSER","USER_ESTABLISHED_INSTALL" ]
|
||||
style: PERSISTENT
|
||||
button-label: preferences_set_as_default_browser
|
||||
default-browser-notification:
|
||||
title: nimbus_notification_default_browser_title
|
||||
text: nimbus_notification_default_browser_text
|
||||
surface: notification
|
||||
style: NOTIFICATION
|
||||
trigger:
|
||||
- I_AM_NOT_DEFAULT_BROWSER
|
||||
- DAY_3_AFTER_INSTALL
|
||||
action: MAKE_DEFAULT_BROWSER
|
||||
|
||||
- channel: developer
|
||||
value:
|
||||
styles:
|
||||
DEFAULT:
|
||||
priority: 50
|
||||
max-display-count: 100
|
||||
EXPIRES_QUICKLY:
|
||||
priority: 100
|
||||
max-display-count: 1
|
||||
notification-config:
|
||||
refresh-interval: 120 # minutes (2 hours)
|
||||
- path: ../android-components/components/browser/engine-gecko/geckoview.fml.yaml
|
||||
channel: release
|
||||
features:
|
||||
pdfjs:
|
||||
- channel: developer
|
||||
value: {
|
||||
download-button: true,
|
||||
open-in-app-button: true
|
||||
}
|
||||
|
||||
features:
|
||||
toolbar:
|
||||
description: The searchbar/awesomebar that user uses to search.
|
||||
variables:
|
||||
toolbar-position-top:
|
||||
description: If true, toolbar appears at top of the screen.
|
||||
type: Boolean
|
||||
default: false
|
||||
homescreen:
|
||||
description: The homescreen that the user goes to when they press home or new tab.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled.
|
||||
If the section is enabled, it should be toggleable in the settings screen, and on by default."
|
||||
type: Map<HomeScreenSection, Boolean>
|
||||
default:
|
||||
{
|
||||
"top-sites": true,
|
||||
"jump-back-in": true,
|
||||
"recently-saved": true,
|
||||
"recent-explorations": true,
|
||||
"pocket": true,
|
||||
"pocket-sponsored-stories": true,
|
||||
}
|
||||
defaults:
|
||||
- channel: nightly
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"top-sites": true,
|
||||
"jump-back-in": true,
|
||||
"recently-saved": true,
|
||||
"recent-explorations": true,
|
||||
"pocket": true,
|
||||
}
|
||||
}
|
||||
nimbus-validation:
|
||||
description: "A feature that does not correspond to an application feature suitable for showing
|
||||
that Nimbus is working. This should never be used in production."
|
||||
variables:
|
||||
settings-title:
|
||||
description: The title of displayed in the Settings screen and app menu.
|
||||
type: Text
|
||||
default: browser_menu_settings
|
||||
settings-punctuation:
|
||||
description: The emoji displayed in the Settings screen title.
|
||||
type: String
|
||||
default: ""
|
||||
settings-icon:
|
||||
description: The drawable displayed in the app menu for Settings
|
||||
type: String
|
||||
default: mozac_ic_settings
|
||||
search-term-groups:
|
||||
description: A feature allowing the grouping of URLs around the search term that it came from.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature shows up on the homescreen and on the new tab screen.
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: nightly
|
||||
value:
|
||||
enabled: true
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: true
|
||||
mr2022:
|
||||
description: Features for MR 2022.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled."
|
||||
type: Map<MR2022Section, Boolean>
|
||||
default:
|
||||
{
|
||||
"home-onboarding-dialog-existing-users": true,
|
||||
"sync-cfr": true,
|
||||
"wallpapers-selection-tool": true,
|
||||
"jump-back-in-cfr": true,
|
||||
"tcp-cfr": true,
|
||||
"tcp-feature": true,
|
||||
}
|
||||
defaults:
|
||||
- channel: developer
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"home-onboarding-dialog-existing-users": true,
|
||||
"sync-cfr": true,
|
||||
"wallpapers-selection-tool": true,
|
||||
"jump-back-in-cfr": true,
|
||||
}
|
||||
}
|
||||
|
||||
cookie-banners:
|
||||
description: Features for cookie banner handling.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled."
|
||||
type: Map<CookieBannersSection, Int>
|
||||
default:
|
||||
{
|
||||
"feature-ui": 0,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4
|
||||
}
|
||||
defaults:
|
||||
- channel: developer
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4
|
||||
}
|
||||
}
|
||||
- channel: nightly
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4
|
||||
}
|
||||
}
|
||||
unified-search:
|
||||
description: A feature allowing user to easily search for specified results directly in the search bar.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature shows up in the search bar.
|
||||
type: Boolean
|
||||
default: true
|
||||
|
||||
growth-data:
|
||||
description: A feature measuring campaign growth data
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature is active
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: release
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
re-engagement-notification:
|
||||
description: A feature that shows the re-engagement notification if the user is inactive.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the re-engagement notification is shown to the inactive user.
|
||||
type: Boolean
|
||||
default: false
|
||||
type:
|
||||
description: The type of re-engagement notification that is shown to the inactive user.
|
||||
type: Int
|
||||
default: 0
|
||||
|
||||
pre-permission-notification-prompt:
|
||||
description: A feature that shows the pre-permission notification prompt.
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, the pre-permission notification prompt is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
|
||||
onboarding:
|
||||
description: "A feature that configures the new user onboarding page.
|
||||
Note that onboarding is a **first run** feature, and should only be modified by first run experiments."
|
||||
variables:
|
||||
order:
|
||||
description: Determines the order of the onboarding page panels
|
||||
type: List<OnboardingPanel>
|
||||
default: ["themes", "toolbar-placement", "sync", "tcp", "privacy-notice"]
|
||||
|
||||
glean:
|
||||
description: "A feature that provides server-side configurations for Glean metrics (aka Server Knobs)."
|
||||
variables:
|
||||
metrics-enabled:
|
||||
description: "A map of metric base-identifiers to booleans representing the state of the 'enabled' flag for that metric."
|
||||
type: Map<String, Boolean>
|
||||
default: {}
|
||||
|
||||
splash-screen:
|
||||
description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run."
|
||||
variables:
|
||||
enabled:
|
||||
description: "If true, the feature is active."
|
||||
type: Boolean
|
||||
default: false
|
||||
maximum_duration_ms:
|
||||
description: The maximum amount of time in milliseconds the splashscreen will be visible while waiting for initialization calls to complete.
|
||||
type: Int
|
||||
default: 0
|
||||
|
||||
shopping-experience:
|
||||
description: A feature that shows product review quality information.
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, the shopping experience feature is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
search_extra_params:
|
||||
description: A feature that provides a search engine name and a channel ID.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature is active.
|
||||
type: Boolean
|
||||
default: false
|
||||
search_name_channel_id:
|
||||
description: The search engine name and the channel ID.
|
||||
type: Map<String, String>
|
||||
default: {}
|
||||
types:
|
||||
objects: {}
|
||||
|
||||
enums:
|
||||
HomeScreenSection:
|
||||
description: The identifiers for the sections of the homescreen.
|
||||
variants:
|
||||
top-sites:
|
||||
description: The frecency and pinned sites.
|
||||
recently-saved:
|
||||
description: The sites the user has bookmarked recently.
|
||||
jump-back-in:
|
||||
description: The tabs the user was looking immediately before being interrupted.
|
||||
recent-explorations:
|
||||
description: The tab groups
|
||||
pocket:
|
||||
description: The pocket section. This should only be available in the US.
|
||||
pocket-sponsored-stories:
|
||||
description: Subsection of the Pocket homescreen section which shows sponsored stories.
|
||||
|
||||
MR2022Section:
|
||||
description: The identifiers for the sections of the MR 2022.
|
||||
variants:
|
||||
home-onboarding-dialog-existing-users:
|
||||
description: Home onboarding dialog for upgraded users.
|
||||
sync-cfr:
|
||||
description: CFR for the first time you see a synced tab on the home screen.
|
||||
wallpapers-selection-tool:
|
||||
description: Wallpapers selection dialog tool for the home screen.
|
||||
jump-back-in-cfr:
|
||||
description: Jump back-in onboarding message.
|
||||
tcp-cfr:
|
||||
description: CFR for the first time you use the browse with Total Cookie Protection on the browser screen.
|
||||
tcp-feature:
|
||||
description: Controls the Total Cookie Protection feature.
|
||||
CookieBannersSection:
|
||||
description: The identifiers for the sections of the MR 2022.
|
||||
variants:
|
||||
feature-ui:
|
||||
description: An integer either 0 or 1 indicating if the UI for cookie banner handling should be visible,
|
||||
0 to hide the UI and 1 to show the UI. The actual UI is composed by cookie banner section
|
||||
in the settings page, the toolbar section and the re-engagement dialog.
|
||||
feature-setting-value:
|
||||
description: An integer either 0 or 1 indicating if cookie banner setting should be enabled or disabled,
|
||||
0 for setting the value to disabled, 1 for enabling the setting with the value reject_all.
|
||||
dialog-re-engage-time:
|
||||
description: An integer indicating the number of hours that needs to happen before
|
||||
the re-engagement dialog shows again since the last seen, for example if set to 4
|
||||
that means if the users has seen the dialog, it will see it 4 hours later.
|
||||
OnboardingPanel:
|
||||
description: The types of onboarding panels in the onboarding page
|
||||
variants:
|
||||
themes:
|
||||
description: The themes onboarding panel where users pick themes
|
||||
toolbar-placement:
|
||||
description: The onboarding panel where users choose their toolbar placement (bottom or top)
|
||||
sync:
|
||||
description: The onboarding panel where users can sign in to sync
|
||||
tcp:
|
||||
description: The onboarding panel where users can choose their total cookie protection settings
|
||||
privacy-notice:
|
||||
description: The onboarding panel where users can tap to view our privacy notice.
|
@ -0,0 +1,114 @@
|
||||
---
|
||||
features:
|
||||
|
||||
juno-onboarding:
|
||||
description: A feature that shows juno onboarding flow.
|
||||
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, juno onboarding is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
cards:
|
||||
description: Collection of user facing onboarding cards.
|
||||
type: Map<String, OnboardingCardData>
|
||||
default:
|
||||
default-browser:
|
||||
card-type: default-browser
|
||||
title: juno_onboarding_default_browser_title_nimbus
|
||||
ordering: 10
|
||||
body: juno_onboarding_default_browser_description_nimbus
|
||||
link-text: juno_onboarding_default_browser_description_link_text
|
||||
image-res: ic_onboarding_welcome
|
||||
primary-button-label: juno_onboarding_default_browser_positive_button
|
||||
secondary-button-label: juno_onboarding_default_browser_negative_button
|
||||
|
||||
sync-sign-in:
|
||||
card-type: sync-sign-in
|
||||
title: juno_onboarding_sign_in_title
|
||||
body: juno_onboarding_sign_in_description
|
||||
image-res: ic_onboarding_sync
|
||||
ordering: 20
|
||||
primary-button-label: juno_onboarding_sign_in_positive_button
|
||||
secondary-button-label: juno_onboarding_sign_in_negative_button
|
||||
|
||||
notification-permission:
|
||||
card-type: notification-permission
|
||||
title: juno_onboarding_enable_notifications_title_nimbus
|
||||
body: juno_onboarding_enable_notifications_description_nimbus
|
||||
image-res: ic_notification_permission
|
||||
ordering: 30
|
||||
primary-button-label: juno_onboarding_enable_notifications_positive_button
|
||||
secondary-button-label: juno_onboarding_enable_notifications_negative_button
|
||||
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: false
|
||||
- channel: nightly
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
objects:
|
||||
|
||||
OnboardingCardData:
|
||||
description: An object to describe a user facing onboarding card.
|
||||
fields:
|
||||
card-type:
|
||||
type: OnboardingCardType
|
||||
description: The type of the card.
|
||||
# This should never be defaulted.
|
||||
default: default-browser
|
||||
title:
|
||||
type: Text
|
||||
description: The title text displayed to the user.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
body:
|
||||
type: Text
|
||||
description: The message text displayed to the user. May contain linkable text.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
link-text:
|
||||
type: Option<Text>
|
||||
description: >
|
||||
The text to link from the body text. This should match the linkable text from the body text exactly.
|
||||
e.g. body: This is a policy link
|
||||
link-text: policy link
|
||||
default: null
|
||||
image-res:
|
||||
type: Image
|
||||
description: The resource id of the image to be displayed.
|
||||
# This should never be defaulted.
|
||||
default: ic_onboarding_welcome
|
||||
image-is-illustration:
|
||||
type: Boolean
|
||||
description: True if the image type is an illustration.
|
||||
default: true
|
||||
ordering:
|
||||
type: Int
|
||||
description: Used to sequence the cards.
|
||||
# This should never be defaulted.
|
||||
default: 0
|
||||
primary-button-label:
|
||||
type: Text
|
||||
description: The text to display on the primary button.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
secondary-button-label:
|
||||
type: Text
|
||||
description: The text to display on the secondary button.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
|
||||
enums:
|
||||
|
||||
OnboardingCardType:
|
||||
description: An enum to describe a type of card.
|
||||
variants:
|
||||
default-browser:
|
||||
description: Allows user to set Firefox as the default browser.
|
||||
sync-sign-in:
|
||||
description: Allows user to sync with a Firefox account.
|
||||
notification-permission:
|
||||
description: Allows user to enable notification permission.
|
@ -0,0 +1,49 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!-- 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/. -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Muted_Video_Test_Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="testContent">Page content: muted video player</p>
|
||||
<div class="playbackState">
|
||||
<p>Media file not playing</p>
|
||||
</div>
|
||||
<div id="video-container" style="text-align:center">
|
||||
<button onclick="play()">Play</button>
|
||||
<button onclick="pause()">Pause</button>
|
||||
<button onclick="fullscreen()">Full Screen</button>
|
||||
<br><br>
|
||||
<video id="mutedVideo" width="420" autoplay muted controls loop>
|
||||
<source src="../resources/clip.mp4" type="video/mp4">
|
||||
Your browser does not support HTML video.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const mutedVideo = document.getElementById("mutedVideo");
|
||||
|
||||
function play() {
|
||||
mutedVideo.play();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
mutedVideo.pause();
|
||||
}
|
||||
|
||||
function fullscreen() {
|
||||
mutedVideo.requestFullscreen();
|
||||
}
|
||||
|
||||
mutedVideo.addEventListener('playing', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is playing";
|
||||
});
|
||||
|
||||
mutedVideo.addEventListener('pause', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is paused";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,14 +1,49 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!-- 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/. -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Video_Test_Page</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
</head>
|
||||
<body>
|
||||
<p id="testContent">Page content: video player</p>
|
||||
<div id="video-container">
|
||||
<video id="videoSample" width="320" height="240" controls loop>
|
||||
<source src="../resources/clip.mp4">
|
||||
<div class="playbackState">
|
||||
<p>Media file not playing</p>
|
||||
</div>
|
||||
<div id="video-container" style="text-align:center">
|
||||
<button onclick="play()">Play</button>
|
||||
<button onclick="pause()">Pause</button>
|
||||
<button onclick="fullscreen()">Full Screen</button>
|
||||
<br><br>
|
||||
<video id="video" width="420" autoplay controls loop>
|
||||
<source src="../resources/clip.mp4" type="video/mp4">
|
||||
Your browser does not support HTML video.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const video = document.getElementById("video");
|
||||
|
||||
function play() {
|
||||
video.play();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
video.pause();
|
||||
}
|
||||
|
||||
function fullscreen() {
|
||||
video.requestFullscreen();
|
||||
}
|
||||
|
||||
video.addEventListener('playing', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is playing";
|
||||
});
|
||||
|
||||
video.addEventListener('pause', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is paused";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
Binary file not shown.
@ -0,0 +1,97 @@
|
||||
package org.mozilla.fenix.onboarding.view
|
||||
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.experiments.nimbus.StringHolder
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.nimbus.OnboardingCardData
|
||||
import org.mozilla.fenix.nimbus.OnboardingCardType
|
||||
|
||||
class JunoOnboardingMapperTest {
|
||||
|
||||
@get:Rule
|
||||
val activityTestRule =
|
||||
HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true)
|
||||
|
||||
@Test
|
||||
fun showNotificationTrue_pagesToDisplay_returnsSortedListOfAllConvertedPages() {
|
||||
val expected = listOf(defaultBrowserPageUiData, syncPageUiData, notificationPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showNotificationFalse_pagesToDisplay_returnsSortedListOfConvertedPagesWithoutNotificationPage() {
|
||||
val expected = listOf(defaultBrowserPageUiData, syncPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(false))
|
||||
}
|
||||
}
|
||||
|
||||
private val defaultBrowserPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
|
||||
imageRes = R.drawable.ic_onboarding_welcome,
|
||||
imageResContentScale = ContentScale.Fit,
|
||||
title = "default browser title",
|
||||
description = "default browser body with link text",
|
||||
linkText = "link text",
|
||||
primaryButtonLabel = "default browser primary button text",
|
||||
secondaryButtonLabel = "default browser secondary button text",
|
||||
)
|
||||
private val syncPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
|
||||
imageRes = R.drawable.ic_onboarding_sync,
|
||||
imageResContentScale = ContentScale.Fit,
|
||||
title = "sync title",
|
||||
description = "sync body",
|
||||
primaryButtonLabel = "sync primary button text",
|
||||
secondaryButtonLabel = "sync secondary button text",
|
||||
)
|
||||
private val notificationPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
|
||||
imageRes = R.drawable.ic_notification_permission,
|
||||
imageResContentScale = ContentScale.Crop,
|
||||
title = "notification title",
|
||||
description = "notification body",
|
||||
primaryButtonLabel = "notification primary button text",
|
||||
secondaryButtonLabel = "notification secondary button text",
|
||||
)
|
||||
|
||||
private val defaultBrowserCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.DEFAULT_BROWSER,
|
||||
imageRes = R.drawable.ic_onboarding_welcome,
|
||||
imageIsIllustration = true,
|
||||
title = StringHolder(null, "default browser title"),
|
||||
body = StringHolder(null, "default browser body with link text"),
|
||||
linkText = StringHolder(null, "link text"),
|
||||
primaryButtonLabel = StringHolder(null, "default browser primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "default browser secondary button text"),
|
||||
ordering = 10,
|
||||
)
|
||||
private val syncCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.SYNC_SIGN_IN,
|
||||
imageRes = R.drawable.ic_onboarding_sync,
|
||||
imageIsIllustration = true,
|
||||
title = StringHolder(null, "sync title"),
|
||||
body = StringHolder(null, "sync body"),
|
||||
primaryButtonLabel = StringHolder(null, "sync primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "sync secondary button text"),
|
||||
ordering = 20,
|
||||
)
|
||||
private val notificationCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.NOTIFICATION_PERMISSION,
|
||||
imageRes = R.drawable.ic_notification_permission,
|
||||
imageIsIllustration = false,
|
||||
title = StringHolder(null, "notification title"),
|
||||
body = StringHolder(null, "notification body"),
|
||||
primaryButtonLabel = StringHolder(null, "notification primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "notification secondary button text"),
|
||||
ordering = 30,
|
||||
)
|
||||
|
||||
private val unsortedAllKnownCardData = listOf(
|
||||
syncCardData,
|
||||
notificationCardData,
|
||||
defaultBrowserCardData,
|
||||
)
|
@ -1,16 +1,17 @@
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
class ADBrun(object):
|
||||
binary = 'adbrun'
|
||||
binary = "adbrun"
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
def launch(self):
|
||||
# First close sim if any then launch
|
||||
os.system('~/Library/Android/sdk/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do ~/Library/Android/sdk/platform-tools/adb -s $line emu kill; done')
|
||||
os.system(
|
||||
"~/Library/Android/sdk/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do ~/Library/Android/sdk/platform-tools/adb -s $line emu kill; done"
|
||||
)
|
||||
# Then launch sim
|
||||
os.system("sh launchSimScript.sh")
|
||||
|
@ -0,0 +1,113 @@
|
||||
package org.mozilla.fenix.ui
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemContainingText
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.ui.robots.browserScreen
|
||||
import org.mozilla.fenix.ui.robots.clickPageObject
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
import org.mozilla.fenix.ui.robots.searchScreen
|
||||
|
||||
class AddToHomeScreenTest {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
private val downloadTestPage =
|
||||
"https://storage.googleapis.com/mobile_test_assets/test_app/downloads.html"
|
||||
private val pdfFileName = "washington.pdf"
|
||||
private val pdfFileURL = "storage.googleapis.com/mobile_test_assets/public/washington.pdf"
|
||||
private val pdfFileContent = "Washington Crossing the Delaware"
|
||||
|
||||
@get:Rule
|
||||
val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
// Verifies the Add to home screen option in a tab's 3 dot menu
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuAddToHomeScreenTest() {
|
||||
val website = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
val shortcutTitle = TestHelper.generateRandomString(5)
|
||||
|
||||
homeScreen {
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(website.url) {
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
clickCancelShortcutButton()
|
||||
}
|
||||
|
||||
browserScreen {
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
verifyShortcutTextFieldTitle("Test_Page_1")
|
||||
addShortcutName(shortcutTitle)
|
||||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(shortcutTitle) {
|
||||
verifyUrl(website.url.toString())
|
||||
verifyTabCounter("1")
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun addPrivateBrowsingShortcutTest() {
|
||||
homeScreen {
|
||||
}.dismissOnboarding()
|
||||
|
||||
homeScreen {
|
||||
}.triggerPrivateBrowsingShortcutPrompt {
|
||||
verifyNoThanksPrivateBrowsingShortcutButton()
|
||||
verifyAddPrivateBrowsingShortcutButton()
|
||||
clickAddPrivateBrowsingShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut("Private ${TestHelper.appName}") {}
|
||||
searchScreen {
|
||||
verifySearchView()
|
||||
}.dismissSearchBar {
|
||||
verifyCommonMythsLink()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun addPDFToHomeScreenTest() {
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(downloadTestPage.toUri()) {
|
||||
clickPageObject(itemContainingText(pdfFileName))
|
||||
verifyUrl(pdfFileURL)
|
||||
verifyPageContent(pdfFileContent)
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
verifyShortcutTextFieldTitle(pdfFileName)
|
||||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(pdfFileName) {
|
||||
verifyUrl(pdfFileURL)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,432 @@
|
||||
package org.mozilla.fenix.ui
|
||||
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResId
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResIdContainingText
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper.exitMenu
|
||||
import org.mozilla.fenix.helpers.TestHelper.packageName
|
||||
import org.mozilla.fenix.ui.robots.clickPageObject
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
|
||||
class AddressAutofillTest {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
@get:Rule
|
||||
val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyAddressAutofillTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}.goBack {
|
||||
}.goBack {
|
||||
}
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun deleteSavedAddressTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
clickDeleteAddressButton()
|
||||
clickCancelDeleteAddressButton()
|
||||
clickDeleteAddressButton()
|
||||
clickConfirmDeleteAddressButton()
|
||||
verifyAddAddressButton()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAddAddressViewTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
verifyAddAddressView()
|
||||
}.goBackToAutofillSettings {
|
||||
verifyAutofillToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEditAddressViewTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
verifyEditAddressView()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAddressAutofillToggleTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
verifySelectAddressButtonExists(true)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickSaveAndAutofillAddressesOption()
|
||||
verifyAddressAutofillSection(false, true)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
verifySelectAddressButtonExists(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyManageAddressesPromptOptionTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
}.clickManageAddressButton {
|
||||
verifyAutofillToolbarTitle()
|
||||
}.goBackToBrowser {
|
||||
verifySaveLoginPromptIsNotDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Failing, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1814032")
|
||||
@Test
|
||||
fun verifyAddressAutofillSelectionTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Android",
|
||||
"Test",
|
||||
"Name",
|
||||
"Fort Street",
|
||||
"San Jose",
|
||||
"Arizona",
|
||||
"95141",
|
||||
"United States",
|
||||
"777-7777",
|
||||
"fuu@bar.org",
|
||||
)
|
||||
verifyManageAddressesToolbarTitle()
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
clearAddressForm()
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Fort Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Fort Street")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifySavedAddressCanBeEditedTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
fillAndSaveAddress(
|
||||
"Android",
|
||||
"Test",
|
||||
"Name",
|
||||
"Fort Street",
|
||||
"San Jose",
|
||||
"Arizona",
|
||||
"95141",
|
||||
"United States",
|
||||
"777-7777",
|
||||
"fuu@bar.org",
|
||||
)
|
||||
verifyManageAddressesToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyStateFieldUpdatesInAccordanceWithCountryFieldTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
verifyCountryOption("United States")
|
||||
verifyStateOption("Alabama")
|
||||
verifyCountryOptions("Canada", "United States")
|
||||
clickCountryOption("Canada")
|
||||
verifyStateOption("Alberta")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyFormFieldCanBeFilledManuallyTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
setTextForApartmentTextBox("Ap. 07")
|
||||
verifyManuallyFilledAddress("Ap. 07")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAutofillAddressSectionTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
verifyAddressAutofillSection(true, true)
|
||||
clickManageAddressesButton()
|
||||
verifyManageAddressesSection(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"US",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,377 @@
|
||||
/* 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.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.RetryTestRule
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper.clickSnackbarButton
|
||||
import org.mozilla.fenix.helpers.TestHelper.verifySnackBarText
|
||||
import org.mozilla.fenix.ui.robots.browserScreen
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
import org.mozilla.fenix.ui.robots.notificationShade
|
||||
|
||||
/**
|
||||
* Tests for verifying basic functionality of tabbed browsing
|
||||
*
|
||||
* Including:
|
||||
* - Opening a tab
|
||||
* - Opening a private tab
|
||||
* - Verifying tab list
|
||||
* - Closing all tabs
|
||||
* - Close tab
|
||||
* - Swipe to close tab (temporarily disabled)
|
||||
* - Undo close tab
|
||||
* - Close private tabs persistent notification
|
||||
* - Empty tab tray state
|
||||
* - Tab tray details
|
||||
* - Shortcut context menu navigation
|
||||
*/
|
||||
|
||||
class ComposeTabbedBrowsingTest {
|
||||
private lateinit var mDevice: UiDevice
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
@get:Rule(order = 0)
|
||||
val composeTestRule =
|
||||
AndroidComposeTestRule(
|
||||
HomeActivityTestRule.withDefaultSettingsOverrides(
|
||||
tabsTrayRewriteEnabled = true,
|
||||
),
|
||||
) { it.activity }
|
||||
|
||||
@Rule(order = 1)
|
||||
@JvmField
|
||||
val retryTestRule = RetryTestRule(3)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun openNewTabTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
mDevice.waitForIdle()
|
||||
verifyTabCounter("1")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNormalBrowsingButtonIsSelected()
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
closeTab()
|
||||
}
|
||||
homeScreen {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNoOpenTabsInNormalBrowsing()
|
||||
}.openNewTab {
|
||||
}.submitQuery(defaultWebPage.url.toString()) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
verifyTabCounter("1")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNormalBrowsingButtonIsSelected()
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun openNewPrivateTabTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
homeScreen {
|
||||
}.togglePrivateBrowsingMode()
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
mDevice.waitForIdle()
|
||||
verifyTabCounter("1")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyPrivateTabsList()
|
||||
verifyPrivateBrowsingButtonIsSelected()
|
||||
}.toggleToNormalTabs {
|
||||
verifyNoOpenTabsInNormalBrowsing()
|
||||
}.toggleToPrivateTabs {
|
||||
verifyPrivateTabsList()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun closeAllTabsTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNormalTabsList()
|
||||
}.openThreeDotMenu {
|
||||
verifyCloseAllTabsButton()
|
||||
verifyShareAllTabsButton()
|
||||
verifySelectTabsButton()
|
||||
}.closeAllTabs {
|
||||
verifyTabCounter("0")
|
||||
}
|
||||
|
||||
// Repeat for Private Tabs
|
||||
homeScreen {
|
||||
}.togglePrivateBrowsingMode()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyPrivateTabsList()
|
||||
}.openThreeDotMenu {
|
||||
verifyCloseAllTabsButton()
|
||||
}.closeAllTabs {
|
||||
verifyTabCounter("0")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun closeTabTest() {
|
||||
val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
closeTab()
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
swipeTabRight("Test_Page_1")
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
swipeTabLeft("Test_Page_1")
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyUndoSnackBarTest() {
|
||||
// disabling these features because they interfere with the snackbar visibility
|
||||
composeTestRule.activityRule.applySettingsExceptions {
|
||||
it.isPocketEnabled = false
|
||||
it.isRecentTabsFeatureEnabled = false
|
||||
it.isRecentlyVisitedFeatureEnabled = false
|
||||
}
|
||||
|
||||
val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
closeTab()
|
||||
verifySnackBarText("Tab closed")
|
||||
clickSnackbarButton("UNDO")
|
||||
}
|
||||
|
||||
browserScreen {
|
||||
verifyTabCounter("1")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun closePrivateTabTest() {
|
||||
val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
homeScreen { }.togglePrivateBrowsingMode()
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
closeTab()
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
swipeTabRight("Test_Page_1")
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
swipeTabLeft("Test_Page_1")
|
||||
}
|
||||
homeScreen {
|
||||
verifyTabCounter("0")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyPrivateTabUndoSnackBarTest() {
|
||||
val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
homeScreen { }.togglePrivateBrowsingMode()
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(genericURL.url) {
|
||||
verifyPageContent(genericURL.content)
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
closeTab()
|
||||
verifySnackBarText("Private tab closed")
|
||||
clickSnackbarButton("UNDO")
|
||||
}
|
||||
|
||||
browserScreen {
|
||||
verifyPageContent(genericURL.content)
|
||||
verifyTabCounter("1")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
verifyPrivateBrowsingButtonIsSelected()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun closePrivateTabsNotificationTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
homeScreen {
|
||||
}.togglePrivateBrowsingMode()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
mDevice.openNotification()
|
||||
}
|
||||
|
||||
notificationShade {
|
||||
verifyPrivateTabsNotification()
|
||||
}.clickClosePrivateTabsNotification {
|
||||
verifyHomeScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyTabTrayNotShowingStateHalfExpanded() {
|
||||
homeScreen {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNoOpenTabsInNormalBrowsing()
|
||||
// With no tabs opened the state should be STATE_COLLAPSED.
|
||||
verifyTabsTrayBehaviorState(BottomSheetBehavior.STATE_COLLAPSED)
|
||||
// Need to ensure the halfExpandedRatio is very small so that when in STATE_HALF_EXPANDED
|
||||
// the tabTray will actually have a very small height (for a very short time) akin to being hidden.
|
||||
verifyMinusculeHalfExpandedRatio()
|
||||
}.clickTopBar {
|
||||
}.waitForTabTrayBehaviorToIdle {
|
||||
// Touching the topBar would normally advance the tabTray to the next state.
|
||||
// We don't want that.
|
||||
verifyTabsTrayBehaviorState(BottomSheetBehavior.STATE_COLLAPSED)
|
||||
}.advanceToHalfExpandedState {
|
||||
}.waitForTabTrayBehaviorToIdle {
|
||||
// TabTray should not be displayed in STATE_HALF_EXPANDED.
|
||||
// When advancing to this state it should immediately be hidden.
|
||||
verifyTabTrayIsClosed()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEmptyTabTray() {
|
||||
homeScreen {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNormalBrowsingButtonIsSelected()
|
||||
verifyPrivateBrowsingButtonIsSelected(false)
|
||||
verifySyncedTabsButtonIsSelected(false)
|
||||
verifyNoOpenTabsInNormalBrowsing()
|
||||
verifyFab()
|
||||
verifyThreeDotButton()
|
||||
}.openThreeDotMenu {
|
||||
verifyTabSettingsButton()
|
||||
verifyRecentlyClosedTabsButton()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyOpenTabDetails() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
verifyNormalBrowsingButtonIsSelected()
|
||||
verifyPrivateBrowsingButtonIsSelected(isSelected = false)
|
||||
verifySyncedTabsButtonIsSelected(isSelected = false)
|
||||
verifyThreeDotButton()
|
||||
verifyNormalTabCounter()
|
||||
verifyNormalTabsList()
|
||||
verifyFab()
|
||||
verifyTabThumbnail()
|
||||
verifyExistingOpenTabs(defaultWebPage.title)
|
||||
verifyTabCloseButton(defaultWebPage.title)
|
||||
}.openTab(defaultWebPage.title) {
|
||||
verifyUrl(defaultWebPage.url.toString())
|
||||
verifyTabCounter("1")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyContextMenuShortcuts() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openTabButtonShortcutsMenu {
|
||||
verifyTabButtonShortcutMenuItems()
|
||||
}.closeTabFromShortcutsMenu {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openTabButtonShortcutsMenu {
|
||||
}.openNewPrivateTabFromShortcutsMenu {
|
||||
verifyKeyboardVisible()
|
||||
verifyFocusedNavigationToolbar()
|
||||
// dismiss search dialog
|
||||
homeScreen { }.pressBack()
|
||||
verifyCommonMythsLink()
|
||||
verifyNavigationToolbar()
|
||||
}
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openTabButtonShortcutsMenu {
|
||||
}.openTabFromShortcutsMenu {
|
||||
verifyKeyboardVisible()
|
||||
verifyFocusedNavigationToolbar()
|
||||
// dismiss search dialog
|
||||
homeScreen { }.pressBack()
|
||||
verifyHomeWordmark()
|
||||
verifyNavigationToolbar()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package org.mozilla.fenix.ui
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.TestHelper.exitMenu
|
||||
import org.mozilla.fenix.helpers.TestHelper.restartApp
|
||||
import org.mozilla.fenix.ui.robots.browserScreen
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
|
||||
class CookieBannerReductionTest {
|
||||
@get:Rule
|
||||
val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true)
|
||||
|
||||
// Bug causing flakiness https://bugzilla.mozilla.org/show_bug.cgi?id=1807440
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyCookieBannerReductionTest() {
|
||||
val webSite = "startsiden.no"
|
||||
|
||||
homeScreen {
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(webSite.toUri()) {
|
||||
waitForPageToLoad()
|
||||
verifyCookieBannerExists(exists = true)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
verifySettingsOptionSummary("Cookie banner reduction", "Off")
|
||||
}.openCookieBannerReductionSubMenu {
|
||||
verifyCookieBannerView(isCookieBannerReductionChecked = false)
|
||||
clickCookieBannerReductionToggle()
|
||||
verifyCheckedCookieBannerReductionToggle(isCookieBannerReductionChecked = true)
|
||||
}.goBack {
|
||||
verifySettingsOptionSummary("Cookie banner reduction", "On")
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
browserScreen {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}
|
||||
|
||||
restartApp(activityTestRule)
|
||||
|
||||
browserScreen {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openCookieBannerReductionSubMenu {
|
||||
clickCookieBannerReductionToggle()
|
||||
verifyCheckedCookieBannerReductionToggle(false)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
browserScreen {
|
||||
waitForPageToLoad()
|
||||
}.openThreeDotMenu {
|
||||
}.refreshPage {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}
|
||||
}
|
||||
|
||||
// Bug causing flakiness https://bugzilla.mozilla.org/show_bug.cgi?id=1807440
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyCookieBannerReductionInPrivateBrowsingTest() {
|
||||
val webSite = "startsiden.no"
|
||||
|
||||
homeScreen {
|
||||
}.togglePrivateBrowsingMode()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(webSite.toUri()) {
|
||||
waitForPageToLoad()
|
||||
verifyCookieBannerExists(exists = true)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
verifySettingsOptionSummary("Cookie banner reduction", "Off")
|
||||
}.openCookieBannerReductionSubMenu {
|
||||
verifyCookieBannerView(isCookieBannerReductionChecked = false)
|
||||
clickCookieBannerReductionToggle()
|
||||
verifyCheckedCookieBannerReductionToggle(isCookieBannerReductionChecked = true)
|
||||
}.goBack {
|
||||
verifySettingsOptionSummary("Cookie banner reduction", "On")
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
browserScreen {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}
|
||||
|
||||
restartApp(activityTestRule)
|
||||
|
||||
homeScreen {
|
||||
}.openTabDrawer {
|
||||
}.openTab("Startsiden.no") {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openCookieBannerReductionSubMenu {
|
||||
clickCookieBannerReductionToggle()
|
||||
verifyCheckedCookieBannerReductionToggle(false)
|
||||
exitMenu()
|
||||
}
|
||||
browserScreen {
|
||||
waitForPageToLoad()
|
||||
}.openThreeDotMenu {
|
||||
}.refreshPage {
|
||||
verifyCookieBannerExists(exists = false)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,668 @@
|
||||
package org.mozilla.fenix.ui
|
||||
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResId
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResIdContainingText
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper.bringAppToForeground
|
||||
import org.mozilla.fenix.helpers.TestHelper.exitMenu
|
||||
import org.mozilla.fenix.helpers.TestHelper.packageName
|
||||
import org.mozilla.fenix.helpers.TestHelper.putAppToBackground
|
||||
import org.mozilla.fenix.ui.robots.clickPageObject
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
import java.time.LocalDate
|
||||
|
||||
class CreditCardAutofillTest {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
object MockCreditCard1 {
|
||||
const val MOCK_CREDIT_CARD_NUMBER = "5555555555554444"
|
||||
const val MOCK_LAST_CARD_DIGITS = "4444"
|
||||
const val MOCK_NAME_ON_CARD = "Mastercard"
|
||||
const val MOCK_EXPIRATION_MONTH = "February"
|
||||
val MOCK_EXPIRATION_YEAR = (LocalDate.now().year + 1).toString()
|
||||
val MOCK_EXPIRATION_MONTH_AND_YEAR = "02/${(LocalDate.now().year + 1)}"
|
||||
}
|
||||
|
||||
object MockCreditCard2 {
|
||||
const val MOCK_CREDIT_CARD_NUMBER = "2720994326581252"
|
||||
const val MOCK_LAST_CARD_DIGITS = "1252"
|
||||
const val MOCK_NAME_ON_CARD = "Mastercard"
|
||||
const val MOCK_EXPIRATION_MONTH = "March"
|
||||
val MOCK_EXPIRATION_YEAR = (LocalDate.now().year + 2).toString()
|
||||
val MOCK_EXPIRATION_MONTH_AND_YEAR = "03/${(LocalDate.now().year + 2)}"
|
||||
}
|
||||
|
||||
@get:Rule
|
||||
val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyCreditCardAutofillTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
// Opening Manage saved cards to dismiss here the Secure your credit prompt
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
}.goBackToAutofillSettings {
|
||||
}.goBack {
|
||||
}.goBack {
|
||||
}
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/credit_card_number",
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
),
|
||||
)
|
||||
verifyAutofilledCreditCard(MockCreditCard1.MOCK_CREDIT_CARD_NUMBER)
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun deleteSavedCreditCardUsingToolbarButtonTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickSavedCreditCard()
|
||||
clickDeleteCreditCardToolbarButton()
|
||||
clickConfirmDeleteCreditCardButton()
|
||||
verifyAddCreditCardsButton()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun cancelDeleteSavedCreditCardUsingToolbarButtonTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickSavedCreditCard()
|
||||
clickDeleteCreditCardToolbarButton()
|
||||
clickCancelDeleteCreditCardButton()
|
||||
verifyEditCreditCardToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun deleteSavedCreditCardUsingMenuButtonTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickSavedCreditCard()
|
||||
clickDeleteCreditCardMenuButton()
|
||||
clickConfirmDeleteCreditCardButton()
|
||||
verifyAddCreditCardsButton()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun cancelDeleteSavedCreditCardUsingMenuButtonTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickSavedCreditCard()
|
||||
clickDeleteCreditCardMenuButton()
|
||||
clickCancelDeleteCreditCardButton()
|
||||
verifyEditCreditCardToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyCreditCardsSectionTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyManageCreditCardsPromptOptionTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
}.clickManageCreditCardsButton {
|
||||
}.goBackToBrowser {
|
||||
verifySelectCreditCardPromptExists(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyCreditCardsAutofillToggleTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
verifySelectCreditCardPromptExists(true)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickSaveAndAutofillCreditCardsOption()
|
||||
verifyCreditCardsAutofillSection(false, true)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
verifySelectCreditCardPromptExists(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEditCardsViewTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickSavedCreditCard()
|
||||
verifyEditCreditCardView(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
}.goBackToSavedCreditCards {
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEditedCardIsSavedTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickSavedCreditCard()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard2.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard2.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard2.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/credit_card_number",
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
),
|
||||
)
|
||||
verifyAutofilledCreditCard(MockCreditCard2.MOCK_CREDIT_CARD_NUMBER)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyCreditCardCannotBeSavedWithoutCardNumberTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickSavedCreditCard()
|
||||
clearCreditCardNumber()
|
||||
clickSaveCreditCardToolbarButton()
|
||||
verifyEditCreditCardToolbarTitle()
|
||||
verifyCreditCardNumberErrorMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyCreditCardCannotBeSavedWithoutNameOnCardTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickSavedCreditCard()
|
||||
clearNameOnCreditCard()
|
||||
clickSaveCreditCardToolbarButton()
|
||||
verifyEditCreditCardToolbarTitle()
|
||||
verifyNameOnCreditCardErrorMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyMultipleCreditCardsCanBeSavedTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard2.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard2.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard2.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
verifyCreditCardSuggestion(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
)
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/credit_card_number",
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
),
|
||||
)
|
||||
verifyAutofilledCreditCard(MockCreditCard2.MOCK_CREDIT_CARD_NUMBER)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyDoNotSaveCreditCardFromFormTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickPageObject(itemWithResId("$packageName:id/save_cancel"))
|
||||
verifyUpdateOrSaveCreditCardPromptExists(exists = false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifySaveCreditCardFromFormTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
clickPageObject(itemWithResId("$packageName:id/save_confirm"))
|
||||
verifyUpdateOrSaveCreditCardPromptExists(exists = false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, true)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyCancelCreditCardUpdatePromptTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard2.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard2.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard2.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
// Opening Manage saved cards to dismiss here the Secure your credit prompt
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/credit_card_number",
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
),
|
||||
)
|
||||
verifyAutofilledCreditCard(MockCreditCard2.MOCK_CREDIT_CARD_NUMBER)
|
||||
changeCreditCardExpiryDate(MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR)
|
||||
clickCreditCardFormSubmitButton()
|
||||
clickPageObject(itemWithResId("$packageName:id/save_cancel"))
|
||||
verifyUpdateOrSaveCreditCardPromptExists(false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, true)
|
||||
clickManageSavedCreditCardsButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyConfirmCreditCardUpdatePromptTest() {
|
||||
val creditCardFormPage = TestAssetHelper.getCreditCardFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard2.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard2.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard2.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard2.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
// Opening Manage saved cards to dismiss here the Secure your credit prompt
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(creditCardFormPage.url) {
|
||||
clickPageObject(itemWithResId("cardNumber"))
|
||||
clickPageObject(itemWithResId("$packageName:id/select_credit_card_header"))
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/credit_card_number",
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
),
|
||||
)
|
||||
verifyAutofilledCreditCard(MockCreditCard2.MOCK_CREDIT_CARD_NUMBER)
|
||||
changeCreditCardExpiryDate(MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR)
|
||||
clickCreditCardFormSubmitButton()
|
||||
clickPageObject(itemWithResId("$packageName:id/save_confirm"))
|
||||
verifyUpdateOrSaveCreditCardPromptExists(false)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, true)
|
||||
clickManageSavedCreditCardsButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard2.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifySavedCreditCardsRedirectionToAutofillAfterInterruptionTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
verifySavedCreditCardsSection(
|
||||
MockCreditCard1.MOCK_LAST_CARD_DIGITS,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH_AND_YEAR,
|
||||
)
|
||||
putAppToBackground()
|
||||
bringAppToForeground()
|
||||
verifyAutofillToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEditCreditCardRedirectionToAutofillAfterInterruptionTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyCreditCardsAutofillSection(true, false)
|
||||
clickAddCreditCardButton()
|
||||
fillAndSaveCreditCard(
|
||||
MockCreditCard1.MOCK_CREDIT_CARD_NUMBER,
|
||||
MockCreditCard1.MOCK_NAME_ON_CARD,
|
||||
MockCreditCard1.MOCK_EXPIRATION_MONTH,
|
||||
MockCreditCard1.MOCK_EXPIRATION_YEAR,
|
||||
)
|
||||
clickManageSavedCreditCardsButton()
|
||||
clickSecuredCreditCardsLaterButton()
|
||||
clickSavedCreditCard()
|
||||
putAppToBackground()
|
||||
bringAppToForeground()
|
||||
verifyAutofillToolbarTitle()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
package org.mozilla.fenix.ui
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import mozilla.components.concept.engine.utils.EngineReleaseChannel
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.RecyclerViewIdlingResource
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper.runWithCondition
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
|
||||
class MainMenuTest {
|
||||
private lateinit var mDevice: UiDevice
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
@get:Rule
|
||||
val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyPageMainMenuItemsTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
waitForPageToLoad()
|
||||
}.openThreeDotMenu {
|
||||
verifyPageThreeDotMainMenuItems(isRequestDesktopSiteEnabled = false)
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuNewTabItemTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.clickNewTabButton {
|
||||
verifySearchView()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuBookmarksItemTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openBookmarks {
|
||||
verifyBookmarksMenuView()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuHistoryItemTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openHistory {
|
||||
verifyHistoryListExists()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuAddonsTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openAddonsManagerMenu {
|
||||
TestHelper.registerAndCleanupIdlingResources(
|
||||
RecyclerViewIdlingResource(
|
||||
activityTestRule.activity.findViewById(R.id.add_ons_list),
|
||||
1,
|
||||
),
|
||||
) {
|
||||
verifyAddonsItems()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuSyncItemTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
mDevice.waitForIdle()
|
||||
}.openThreeDotMenu {
|
||||
}.openSyncSignIn {
|
||||
verifyTurnOnSyncMenu()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuFindInPageTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openFindInPage {
|
||||
verifyFindInPageSearchBarItems()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuDesktopSiteTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.switchDesktopSiteMode {
|
||||
}.openThreeDotMenu {
|
||||
verifyDesktopSiteModeEnabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuReportSiteIssueTest() {
|
||||
runWithCondition(
|
||||
// This test will not run on RC builds because the "Report site issue button" is not available.
|
||||
activityTestRule.activity.components.core.engine.version.releaseChannel !== EngineReleaseChannel.RELEASE,
|
||||
) {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openReportSiteIssue {
|
||||
verifyUrl("webcompat.com/issues/new")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuAddToCollectionTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openSaveToCollection {
|
||||
verifyCollectionNameTextField()
|
||||
}
|
||||
}
|
||||
|
||||
// Test running on beta/release builds in CI:
|
||||
// caution when making changes to it, so they don't block the builds
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun openMainMenuSettingsItemTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
verifySettingsView()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuShareButtonTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
}.clickShareButton {
|
||||
verifyShareTabLayout()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuRefreshButtonTest() {
|
||||
val refreshWebPage = TestAssetHelper.getRefreshAsset(mockWebServer)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(refreshWebPage.url) {
|
||||
mDevice.waitForIdle()
|
||||
}.openThreeDotMenu {
|
||||
verifyThreeDotMenuExists()
|
||||
}.refreshPage {
|
||||
verifyPageContent("REFRESHED")
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuForceRefreshTest() {
|
||||
val refreshWebPage = TestAssetHelper.getRefreshAsset(mockWebServer)
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(refreshWebPage.url) {
|
||||
mDevice.waitForIdle()
|
||||
}.openThreeDotMenu {
|
||||
verifyThreeDotMenuExists()
|
||||
}.forceRefreshPage {
|
||||
verifyPageContent("REFRESHED")
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue