From ffc849918275049601f3683e3c2c6105aee095a8 Mon Sep 17 00:00:00 2001 From: 0nko Date: Wed, 19 Nov 2025 14:20:27 +0100 Subject: [PATCH 1/9] Add split omnibar tests with a privacy config patch --- .github/workflows/omnibar-e2e-tests.yml | 77 ++++++++++++++++ .../shared/omnibar_select_split_type.yaml | 8 ++ .maestro/omnibar/split_omnibar_search.yaml | 87 +++++++++++++++++++ .../split_omnibar_test_patch.json | 25 ++++++ 4 files changed, 197 insertions(+) create mode 100644 .github/workflows/omnibar-e2e-tests.yml create mode 100644 .maestro/omnibar/shared/omnibar_select_split_type.yaml create mode 100644 .maestro/omnibar/split_omnibar_search.yaml create mode 100644 privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json diff --git a/.github/workflows/omnibar-e2e-tests.yml b/.github/workflows/omnibar-e2e-tests.yml new file mode 100644 index 000000000000..c26c46e3a525 --- /dev/null +++ b/.github/workflows/omnibar-e2e-tests.yml @@ -0,0 +1,77 @@ +name: Omnibar End-to-End tests + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + instrumentation_tests: + runs-on: ubuntu-latest + name: End-to-End tests + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up JDK version + uses: actions/setup-java@v4 + with: + java-version-file: .github/.java-version + distribution: 'adopt' + + - name: Create folder + if: always() + run: mkdir apk + + - name: Decode keys + uses: davidSchuppa/base64Secret-toFile-action@v2 + with: + secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }} + fileName: ddg_android_build.properties + destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/ + + - name: Decode key file + uses: davidSchuppa/base64Secret-toFile-action@v2 + with: + secret: ${{ secrets.FAKE_RELEASE_KEY }} + fileName: android + destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/ + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Assemble the project + run: ./gradlew assemblePlayRelease -Pforce-default-variant -Pconfig_patches=privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json + + - name: Move APK to new folder + if: always() + run: find . -name "*.apk" -exec mv '{}' apk/playRelease.apk \; + + - name: Omnibar Maestro run + uses: mobile-dev-inc/action-maestro-cloud@v1.9.8 + timeout-minutes: 120 + with: + api-key: ${{ secrets.ROBIN_API_KEY }} + project-id: ${{ vars.ROBIN_ANDROID_PROJECT_ID }} + name: omnibar_${{ github.sha }} + timeout: ${{ vars.ROBIN_TIMEOUT_MINUTES }} + app-file: apk/playRelease.apk + android-api-level: 30 + workspace: .maestro + include-tags: omnibarTest + + - name: Create Asana task when workflow failed + if: ${{ failure() }} + uses: honeycombio/gha-create-asana-task@main + with: + asana-secret: ${{ secrets.ASANA_ACCESS_TOKEN }} + asana-workspace-id: ${{ secrets.GH_ASANA_WORKSPACE_ID }} + asana-project-id: ${{ secrets.GH_ASANA_AOR_PROJECT_ID }} + asana-section-id: ${{ secrets.GH_ASANA_INCOMING_ID }} + asana-task-name: GH Workflow Failure - Omnibar E2E tests + asana-task-description: The Omnibar end-to-end workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }} \ No newline at end of file diff --git a/.maestro/omnibar/shared/omnibar_select_split_type.yaml b/.maestro/omnibar/shared/omnibar_select_split_type.yaml new file mode 100644 index 000000000000..9cb75b5bf465 --- /dev/null +++ b/.maestro/omnibar/shared/omnibar_select_split_type.yaml @@ -0,0 +1,8 @@ +appId: com.duckduckgo.mobile.android +--- +# enable the Split omnibar +- runFlow: ../../shared/open_appearance_settings_screen.yaml +- tapOn: + id: "splitOmnibarToggleImage" +- action: back +- action: back \ No newline at end of file diff --git a/.maestro/omnibar/split_omnibar_search.yaml b/.maestro/omnibar/split_omnibar_search.yaml new file mode 100644 index 000000000000..453bfeaa55b3 --- /dev/null +++ b/.maestro/omnibar/split_omnibar_search.yaml @@ -0,0 +1,87 @@ +appId: com.duckduckgo.mobile.android +name: "Split omnibar test" +tags: + - omnibarTest + - releaseTest +--- +- retry: + maxRetries: 3 + commands: + - launchApp: + clearState: true + stopApp: true + - runFlow: ../shared/skip_all_onboarding.yaml + - runFlow: ./shared/omnibar_select_split_type.yaml + +# verify that autocomplete suggestions are shown when typing +- tapOn: + id: "omnibarTextInput" + optional: true +- inputText: "reddit" +- assertVisible: + id: "autoCompleteSuggestionsList" +- assertVisible: + text: "reddit.com" + childOf: + id: "autoCompleteSuggestionsList" + +# verify that submitting a search query opens SERP +- pressKey: Enter +- assertVisible: + id: "browserLayout" +- assertVisible: + text: "reddit" + childOf: + id: "browserLayout" + +# add the page to favorites (for future assertions) +- runFlow: ../shared/browser_screen/click_on_menu_button.yaml +- tapOn: + text: "add bookmark" +- runFlow: ../shared/browser_screen/click_on_menu_button.yaml +- tapOn: + text: "bookmarks" +- tapOn: + id: "com.duckduckgo.mobile.android:id/trailingIcon" + index: 0 +- tapOn: + text: "add to favorites" +- action: back + +# verify that clearing the text and submitting a URL opens the web page +- tapOn: + id: "omnibarTextInput" +- tapOn: + id: "clearTextButton" +- inputText: "eff.org" +- pressKey: Enter +- assertVisible: + id: "browserLayout" +- extendedWaitUntil: + visible: + text: "https://www.eff.org/" + childOf: + id: "omnibarTextInput" + timeout: 10000 +- assertVisible: + text: "https://www.eff.org/" + childOf: + id: "omnibarTextInput" + +# verify that tapping on a favorite opens the web page (SERP in this case) +- tapOn: + id: "omnibarTextInput" +- tapOn: + id: "quickAccessFavicon" + childOf: + id: "focusedFavourites" +- assertVisible: + id: "browserLayout" +- assertVisible: + text: "reddit" + childOf: + id: "omnibarTextInput" +- assertVisible: + text: "reddit" + childOf: + id: "browserLayout" diff --git a/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json b/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json new file mode 100644 index 000000000000..72417568af66 --- /dev/null +++ b/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json @@ -0,0 +1,25 @@ +[ + { + "op": "replace", + "path": "/features/androidBrowserConfig/features/splitOmnibar/state", + "value": "enabled" + }, + { + "op": "remove", + "path": "/features/androidBrowserConfig/features/splitOmnibar/hash" + }, + { + "op": "replace", + "path": "/features/androidBrowserConfig/features/useUnifiedOmnibarLayout/state", + "value": "enabled" + }, + { + "op": "remove", + "path": "/features/androidBrowserConfig/features/useUnifiedOmnibarLayout/hash" + }, + { + "op": "replace", + "path": "/version", + "value": "999999999999999" + } +] From 667c0079cf9d9fd13622b40453e8687d5651698d Mon Sep 17 00:00:00 2001 From: 0nko Date: Fri, 21 Nov 2025 19:12:05 +0100 Subject: [PATCH 2/9] Remove the json patch --- .../split_omnibar_test_patch.json | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json diff --git a/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json b/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json deleted file mode 100644 index 72417568af66..000000000000 --- a/privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "op": "replace", - "path": "/features/androidBrowserConfig/features/splitOmnibar/state", - "value": "enabled" - }, - { - "op": "remove", - "path": "/features/androidBrowserConfig/features/splitOmnibar/hash" - }, - { - "op": "replace", - "path": "/features/androidBrowserConfig/features/useUnifiedOmnibarLayout/state", - "value": "enabled" - }, - { - "op": "remove", - "path": "/features/androidBrowserConfig/features/useUnifiedOmnibarLayout/hash" - }, - { - "op": "replace", - "path": "/version", - "value": "999999999999999" - } -] From f6a8aad95686f92e7ec898415b9009ef1656609b Mon Sep 17 00:00:00 2001 From: 0nko Date: Fri, 21 Nov 2025 19:23:32 +0100 Subject: [PATCH 3/9] Update the workflow config --- .github/workflows/omnibar-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/omnibar-e2e-tests.yml b/.github/workflows/omnibar-e2e-tests.yml index c26c46e3a525..40857be9774d 100644 --- a/.github/workflows/omnibar-e2e-tests.yml +++ b/.github/workflows/omnibar-e2e-tests.yml @@ -46,7 +46,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Assemble the project - run: ./gradlew assemblePlayRelease -Pforce-default-variant -Pconfig_patches=privacy-config/privacy-config-internal/local-config-patches/split_omnibar_test_patch.json + run: ./gradlew assemblePlayRelease - name: Move APK to new folder if: always() From 5c5e156a6ad4028dc7f82dfa1bcc341b1d0a6759 Mon Sep 17 00:00:00 2001 From: 0nko Date: Wed, 26 Nov 2025 09:36:58 +0100 Subject: [PATCH 4/9] Make the tests nightly --- .../{omnibar-e2e-tests.yml => omnibar-nightly-e2e-tests.yml} | 2 ++ .maestro/omnibar/split_omnibar_search.yaml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) rename .github/workflows/{omnibar-e2e-tests.yml => omnibar-nightly-e2e-tests.yml} (97%) diff --git a/.github/workflows/omnibar-e2e-tests.yml b/.github/workflows/omnibar-nightly-e2e-tests.yml similarity index 97% rename from .github/workflows/omnibar-e2e-tests.yml rename to .github/workflows/omnibar-nightly-e2e-tests.yml index 40857be9774d..c09e1bb45391 100644 --- a/.github/workflows/omnibar-e2e-tests.yml +++ b/.github/workflows/omnibar-nightly-e2e-tests.yml @@ -1,6 +1,8 @@ name: Omnibar End-to-End tests on: + schedule: + - cron: '0 4 * * *' # run at 4 AM UTC workflow_dispatch: concurrency: diff --git a/.maestro/omnibar/split_omnibar_search.yaml b/.maestro/omnibar/split_omnibar_search.yaml index 453bfeaa55b3..c5bbfaede227 100644 --- a/.maestro/omnibar/split_omnibar_search.yaml +++ b/.maestro/omnibar/split_omnibar_search.yaml @@ -2,7 +2,6 @@ appId: com.duckduckgo.mobile.android name: "Split omnibar test" tags: - omnibarTest - - releaseTest --- - retry: maxRetries: 3 From fe9a235c7272c2cd7ba0d7c6ae20d11da090937e Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay <0nko@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:38:35 +0100 Subject: [PATCH 5/9] Update .github/workflows/omnibar-nightly-e2e-tests.yml Co-authored-by: Craig Russell --- .github/workflows/omnibar-nightly-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/omnibar-nightly-e2e-tests.yml b/.github/workflows/omnibar-nightly-e2e-tests.yml index c09e1bb45391..6bc474d656ae 100644 --- a/.github/workflows/omnibar-nightly-e2e-tests.yml +++ b/.github/workflows/omnibar-nightly-e2e-tests.yml @@ -48,7 +48,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Assemble the project - run: ./gradlew assemblePlayRelease + run: ./gradlew assemblePlayRelease -Pforce-default-variant -Pskip-onboarding -x lint - name: Move APK to new folder if: always() From 78a76ec9dcf851593bdc0fa9fb6501f289925fe5 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay <0nko@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:38:42 +0100 Subject: [PATCH 6/9] Update .github/workflows/omnibar-nightly-e2e-tests.yml Co-authored-by: Craig Russell --- .github/workflows/omnibar-nightly-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/omnibar-nightly-e2e-tests.yml b/.github/workflows/omnibar-nightly-e2e-tests.yml index 6bc474d656ae..ec34b75d472a 100644 --- a/.github/workflows/omnibar-nightly-e2e-tests.yml +++ b/.github/workflows/omnibar-nightly-e2e-tests.yml @@ -2,7 +2,7 @@ name: Omnibar End-to-End tests on: schedule: - - cron: '0 4 * * *' # run at 4 AM UTC + - cron: '0 7 * * *' # run at 7 AM UTC workflow_dispatch: concurrency: From d2ab2914b1808460e7eb7c7e78dab72e0a478b8a Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay <0nko@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:43:45 +0100 Subject: [PATCH 7/9] Update .github/workflows/omnibar-nightly-e2e-tests.yml Co-authored-by: Craig Russell --- .github/workflows/omnibar-nightly-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/omnibar-nightly-e2e-tests.yml b/.github/workflows/omnibar-nightly-e2e-tests.yml index ec34b75d472a..045b6e4100cb 100644 --- a/.github/workflows/omnibar-nightly-e2e-tests.yml +++ b/.github/workflows/omnibar-nightly-e2e-tests.yml @@ -63,7 +63,7 @@ jobs: name: omnibar_${{ github.sha }} timeout: ${{ vars.ROBIN_TIMEOUT_MINUTES }} app-file: apk/playRelease.apk - android-api-level: 30 + android-api-level: 34 workspace: .maestro include-tags: omnibarTest From abaf275c288d4e16d26df55a1d3dad5454ad5fc6 Mon Sep 17 00:00:00 2001 From: 0nko Date: Wed, 26 Nov 2025 15:16:49 +0100 Subject: [PATCH 8/9] Update cached flags on privacy config download if split omnibar not selected --- .../app/browser/omnibar/OmnibarFeatureRepository.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt b/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt index 994b1e94f885..c2adff2a6fe3 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt @@ -24,6 +24,7 @@ import com.duckduckgo.app.pixels.remoteconfig.AndroidBrowserConfigFeature import com.duckduckgo.app.settings.db.SettingsDataStore import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn @@ -42,7 +43,7 @@ open class OmnibarFeatureRepository @Inject constructor( private val browserFeatures: AndroidBrowserConfigFeature, private val dispatcherProvider: DispatcherProvider, @AppCoroutineScope private val coroutineScope: CoroutineScope, -) : OmnibarRepository, MainProcessLifecycleObserver { +) : OmnibarRepository, MainProcessLifecycleObserver, PrivacyConfigCallbackPlugin { private var isSplitOmnibarFlagEnabled: Boolean = false private var isNewCustomTabFlagEnabled: Boolean = false @@ -74,4 +75,13 @@ open class OmnibarFeatureRepository @Inject constructor( settingsDataStore.isSplitOmnibarSelected = false } } + + override fun onPrivacyConfigDownloaded() { + coroutineScope.launch(dispatcherProvider.io()) { + if (settingsDataStore.omnibarType != OmnibarType.SPLIT) { + isSplitOmnibarFlagEnabled = browserFeatures.splitOmnibar().isEnabled() + } + isNewCustomTabFlagEnabled = browserFeatures.newCustomTab().isEnabled() + } + } } From 0698fc690a8eb7c0204bcc0da224a47dd2f650e1 Mon Sep 17 00:00:00 2001 From: 0nko Date: Wed, 26 Nov 2025 15:58:28 +0100 Subject: [PATCH 9/9] Add multibinding attritbute --- .../app/browser/omnibar/OmnibarFeatureRepository.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt b/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt index c2adff2a6fe3..7baf2646162d 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarFeatureRepository.kt @@ -36,6 +36,10 @@ import javax.inject.Inject scope = AppScope::class, boundType = MainProcessLifecycleObserver::class, ) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) @SingleInstanceIn(AppScope::class) @ContributesBinding(scope = AppScope::class, boundType = OmnibarRepository::class) open class OmnibarFeatureRepository @Inject constructor(