From f218484339482309ed97c10ec5515e57a938d26a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:05:21 +0000 Subject: [PATCH 01/16] Initial plan From 0ae8b90ac26050f58cf6690eba28ac36eae4ca19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:15:09 +0000 Subject: [PATCH 02/16] Harmonize CI/CD: CI on PRs, CD on main; move Maestro e2e to CI; fix Maestro tests Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/{cd-android.yml => cd.yml} | 118 +++++++------------ .github/workflows/ci.yml | 65 ++++++++++ .github/workflows/deploy.yml | 59 ---------- 3 files changed, 110 insertions(+), 132 deletions(-) rename .github/workflows/{cd-android.yml => cd.yml} (72%) delete mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/cd-android.yml b/.github/workflows/cd.yml similarity index 72% rename from .github/workflows/cd-android.yml rename to .github/workflows/cd.yml index 1a62e39..8f65268 100644 --- a/.github/workflows/cd-android.yml +++ b/.github/workflows/cd.yml @@ -1,9 +1,5 @@ -name: CD – Android +name: CD -# Triggers: -# • push to main → builds and updates the rolling "latest-android" pre-release -# • release event → attaches the artifacts to the newly published GitHub release -# • manual → same as push to main on: push: branches: [main] @@ -12,10 +8,50 @@ on: workflow_dispatch: permissions: - contents: write # required to create/update releases and upload assets + contents: write + pages: write + id-token: write jobs: - # ── Job 1: build arm64 APK (for distribution) + all-arch AAB ────────────── + deploy-web: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + concurrency: + group: "pages" + cancel-in-progress: false + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + + - uses: swatinem/rust-cache@v2 + + - name: Install Dioxus CLI + uses: taiki-e/install-action@v2 + with: + tool: dioxus-cli + + - name: Build + run: dx build --release --platform web --base-path /LogOut + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./target/dx/log-workout/release/web/public + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + # ── Build arm64 APK (for distribution) + all-arch AAB ───────────────────── build-android: name: Build Android APK (arm64) & AAB (all archs) runs-on: ubuntu-latest @@ -30,7 +66,7 @@ jobs: java-version: "17" distribution: temurin - # ── Step 1: Build arm64-only APK ─────────────────────────────────────── + # ── Step 1: Build arm64-only APK ────────────────────────────────────── # Installing only the arm64 target ensures dx produces a single-ABI APK. - name: Install arm64 Rust target uses: dtolnay/rust-toolchain@stable @@ -62,7 +98,7 @@ jobs: cp "$SRC" logout-android-arm64.apk echo "path=logout-android-arm64.apk" >> "$GITHUB_OUTPUT" - # ── Step 2: Add remaining targets and build all-arch AAB ─────────────── + # ── Step 2: Add remaining targets and build all-arch AAB ────────────── # The arm64 Rust artifacts are cached; only the three extra targets compile. - name: Add remaining Android Rust targets run: rustup target add armv7-linux-androideabi i686-linux-android x86_64-linux-android @@ -146,67 +182,3 @@ jobs: --notes "$NOTES" \ --repo "$GITHUB_REPOSITORY" fi - - # ── Job 2: Android E2E tests using Maestro on an x86_64 emulator ────────── - e2e-android: - name: Android E2E Tests (Maestro) - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: "17" - distribution: temurin - - # Build for x86_64 so the APK runs on the CI emulator. - - name: Install x86_64 Android Rust target - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-linux-android - - - uses: swatinem/rust-cache@v2 - - - name: Install Dioxus CLI - uses: taiki-e/install-action@v2 - with: - tool: dioxus-cli - - - name: Build x86_64 APK for emulator testing - run: >- - dx build - --platform android - --release - --no-default-features - --features mobile-platform - - - name: Locate x86_64 APK - id: apk - run: | - SRC=$(find target/dx -name "*.apk" -maxdepth 10 | head -1) - [ -n "$SRC" ] || { echo "::error::No APK found under target/dx"; exit 1; } - echo "Found APK: $SRC" - echo "path=$(realpath "$SRC")" >> "$GITHUB_OUTPUT" - - # Enable KVM for hardware-accelerated Android emulation on ubuntu-latest. - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Install Maestro - run: | - curl -Ls "https://get.maestro.mobile.dev" | bash - echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" - - - name: Run Maestro flows on Android emulator - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 33 - arch: x86_64 - script: | - adb install "${{ steps.apk.outputs.path }}" - maestro test maestro/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a42ad4..7a819f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,3 +289,68 @@ jobs: - name: Fail if any E2E test failed if: steps.e2e.outcome == 'failure' run: exit 1 + + e2e-android: + name: Android E2E Tests (Maestro) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: "17" + distribution: temurin + + # Build for x86_64 so the APK runs on the CI emulator. + # Omit --release so Rust compiles with debug_assertions=true, which causes + # wry (the Dioxus WebView engine) to call + # WebView.setWebContentsDebuggingEnabled(true). Without this flag Maestro + # cannot read WebView content via the Android Accessibility API. + - name: Install x86_64 Android Rust target + uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-linux-android + + - uses: swatinem/rust-cache@v2 + + - name: Install Dioxus CLI + uses: taiki-e/install-action@v2 + with: + tool: dioxus-cli + + - name: Build x86_64 APK for emulator testing + run: >- + dx build + --platform android + --no-default-features + --features mobile-platform + + - name: Locate x86_64 APK + id: apk + run: | + SRC=$(find target/dx -name "*.apk" -maxdepth 10 | head -1) + [ -n "$SRC" ] || { echo "::error::No APK found under target/dx"; exit 1; } + echo "Found APK: $SRC" + echo "path=$(realpath "$SRC")" >> "$GITHUB_OUTPUT" + + # Enable KVM for hardware-accelerated Android emulation on ubuntu-latest. + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Install Maestro + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" + + - name: Run Maestro flows on Android emulator + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 33 + arch: x86_64 + script: | + adb install "${{ steps.apk.outputs.path }}" + maestro test maestro/ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 88cdbe1..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: [main] - workflow_dispatch: - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: wasm32-unknown-unknown - override: true - - - name: Install Dioxus CLI - uses: taiki-e/install-action@v2 - with: - tool: dioxus-cli - - - name: Build - run: dx build --release --platform web --base-path /LogOut - - - name: Debug Output Content - run: ls -R target/dx - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: ./target/dx/log-workout/release/web/public - - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 From 1c0a04e81210ae2bd544b7dc9cb45afa8931c420 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:07:12 +0000 Subject: [PATCH 03/16] Fix Android e2e tests: pre-launch app before Maestro and add stopApp:false + longer timeouts Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 20 ++++++++++++++++---- maestro/launch.yaml | 6 ++++-- maestro/navigation.yaml | 6 ++++-- maestro/session.yaml | 6 ++++-- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a819f2..20f86af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,10 +303,10 @@ jobs: distribution: temurin # Build for x86_64 so the APK runs on the CI emulator. - # Omit --release so Rust compiles with debug_assertions=true, which causes - # wry (the Dioxus WebView engine) to call - # WebView.setWebContentsDebuggingEnabled(true). Without this flag Maestro - # cannot read WebView content via the Android Accessibility API. + # Omit --release so Rust compiles with debug_assertions=true. wry 0.53+ + # defaults devtools=true when debug_assertions is on, which calls + # WebView.setWebContentsDebuggingEnabled(true) — enabling the Chrome + # DevTools Protocol (CDP) socket that Maestro uses to read WebView content. - name: Install x86_64 Android Rust target uses: dtolnay/rust-toolchain@stable with: @@ -353,4 +353,16 @@ jobs: arch: x86_64 script: | adb install "${{ steps.apk.outputs.path }}" + # Pre-launch the app so the WebView is fully initialized and the + # Chrome DevTools Protocol (CDP) socket is ready before Maestro + # starts polling. Without this, Maestro may try to enumerate CDP + # endpoints before setWebContentsDebuggingEnabled(true) has been + # called, fall back to accessibility mode, and fail to find text. + adb shell monkey -p com.gfaure.logworkout \ + -c android.intent.category.LAUNCHER 1 + # Wait for the Dioxus runtime to initialise the WebView and for wry + # to call setWebContentsDebuggingEnabled(true), which creates the + # CDP Unix-socket that Maestro uses to read WebView content. + # 15 s is generous but avoids flakiness on slow CI workers. + sleep 15 maestro test maestro/ diff --git a/maestro/launch.yaml b/maestro/launch.yaml index 1798739..4e1571a 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,9 +1,11 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false +- waitForAnimationsToEnd - extendedWaitUntil: visible: text: "LogOut" - timeout: 15000 + timeout: 30000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index 69a5319..58fcd21 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,11 +1,13 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false +- waitForAnimationsToEnd - extendedWaitUntil: visible: text: "LogOut" - timeout: 15000 + timeout: 30000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 4684e57..ffebeb5 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,11 +1,13 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false +- waitForAnimationsToEnd - extendedWaitUntil: visible: text: "LogOut" - timeout: 15000 + timeout: 30000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session" From bd58557f11630ac6c1b0f0e1b6be30d10cd97212 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:45:24 +0000 Subject: [PATCH 04/16] Fix Maestro e2e: monkey on single line, CDP socket poll replaces sleep Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20f86af..37e96fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -358,11 +358,23 @@ jobs: # starts polling. Without this, Maestro may try to enumerate CDP # endpoints before setWebContentsDebuggingEnabled(true) has been # called, fall back to accessibility mode, and fail to find text. - adb shell monkey -p com.gfaure.logworkout \ - -c android.intent.category.LAUNCHER 1 - # Wait for the Dioxus runtime to initialise the WebView and for wry - # to call setWebContentsDebuggingEnabled(true), which creates the - # CDP Unix-socket that Maestro uses to read WebView content. - # 15 s is generous but avoids flakiness on slow CI workers. - sleep 15 + # NOTE: keep on ONE LINE — the emulator-runner uses `sh`, not bash, + # and `\` line-continuation is not guaranteed to be joined. + adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 + # Poll /proc/net/unix (up to 30 s) until the abstract CDP socket + # "@com.gfaure.logworkout_devtools_remote" appears, which confirms + # that wry has called setWebContentsDebuggingEnabled(true) and + # Maestro can connect via CDP instead of falling back to accessibility. + i=0 + while [ "$i" -lt 30 ]; do + if adb shell cat /proc/net/unix 2>/dev/null | grep -q "@com.gfaure.logworkout_devtools_remote"; then + echo "CDP socket ready after ${i}s" + break + fi + sleep 1 + i=$((i + 1)) + done + if [ "$i" -ge 30 ]; then + echo "Warning: CDP socket not detected after 30s; Maestro may fall back to accessibility mode" + fi maestro test maestro/ From c866d06f494be3e1b43f451675dfaf276adbf426 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:40:40 +0000 Subject: [PATCH 05/16] Fix Maestro e2e: replace multi-line while loop with sleep 20 (per-line sh -c execution) Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37e96fb..1af747f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -358,23 +358,9 @@ jobs: # starts polling. Without this, Maestro may try to enumerate CDP # endpoints before setWebContentsDebuggingEnabled(true) has been # called, fall back to accessibility mode, and fail to find text. - # NOTE: keep on ONE LINE — the emulator-runner uses `sh`, not bash, - # and `\` line-continuation is not guaranteed to be joined. + # IMPORTANT: reactivecircus/android-emulator-runner runs each LINE + # of this script block as a separate "sh -c" invocation, so all + # commands must be single-line (no multi-line shell constructs). adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - # Poll /proc/net/unix (up to 30 s) until the abstract CDP socket - # "@com.gfaure.logworkout_devtools_remote" appears, which confirms - # that wry has called setWebContentsDebuggingEnabled(true) and - # Maestro can connect via CDP instead of falling back to accessibility. - i=0 - while [ "$i" -lt 30 ]; do - if adb shell cat /proc/net/unix 2>/dev/null | grep -q "@com.gfaure.logworkout_devtools_remote"; then - echo "CDP socket ready after ${i}s" - break - fi - sleep 1 - i=$((i + 1)) - done - if [ "$i" -ge 30 ]; then - echo "Warning: CDP socket not detected after 30s; Maestro may fall back to accessibility mode" - fi + sleep 20 maestro test maestro/ From 7074556994c8165529cce3433621537f5a7ef50b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 18:50:24 +0000 Subject: [PATCH 06/16] Fix Maestro typo: waitForAnimationsToEnd -> waitForAnimationToEnd (singular) Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- maestro/launch.yaml | 2 +- maestro/navigation.yaml | 2 +- maestro/session.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/maestro/launch.yaml b/maestro/launch.yaml index 4e1571a..b7aa509 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -3,7 +3,7 @@ appId: com.gfaure.logworkout --- - launchApp: stopApp: false -- waitForAnimationsToEnd +- waitForAnimationToEnd - extendedWaitUntil: visible: text: "LogOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index 58fcd21..de1e18d 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -3,7 +3,7 @@ appId: com.gfaure.logworkout --- - launchApp: stopApp: false -- waitForAnimationsToEnd +- waitForAnimationToEnd - extendedWaitUntil: visible: text: "LogOut" diff --git a/maestro/session.yaml b/maestro/session.yaml index ffebeb5..4eb4ada 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -3,7 +3,7 @@ appId: com.gfaure.logworkout --- - launchApp: stopApp: false -- waitForAnimationsToEnd +- waitForAnimationToEnd - extendedWaitUntil: visible: text: "LogOut" From 977f88d404af4bd39c89c219666602f6987ee6d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 21:05:54 +0000 Subject: [PATCH 07/16] Fix Maestro tests: use default launchApp, 90s timeout, remove pre-launch from CI Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 10 ---------- maestro/launch.yaml | 6 ++---- maestro/navigation.yaml | 6 ++---- maestro/session.yaml | 6 ++---- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1af747f..abca6a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -353,14 +353,4 @@ jobs: arch: x86_64 script: | adb install "${{ steps.apk.outputs.path }}" - # Pre-launch the app so the WebView is fully initialized and the - # Chrome DevTools Protocol (CDP) socket is ready before Maestro - # starts polling. Without this, Maestro may try to enumerate CDP - # endpoints before setWebContentsDebuggingEnabled(true) has been - # called, fall back to accessibility mode, and fail to find text. - # IMPORTANT: reactivecircus/android-emulator-runner runs each LINE - # of this script block as a separate "sh -c" invocation, so all - # commands must be single-line (no multi-line shell constructs). - adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - sleep 20 maestro test maestro/ diff --git a/maestro/launch.yaml b/maestro/launch.yaml index b7aa509..d554454 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,11 +1,9 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false -- waitForAnimationToEnd +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 90000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index de1e18d..b81bee3 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,13 +1,11 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false -- waitForAnimationToEnd +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 90000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 4eb4ada..52aa0f0 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,13 +1,11 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false -- waitForAnimationToEnd +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 90000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session" From 546cbf01760c61785e0c5db0e6c8eb4edff3e849 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:46:31 +0000 Subject: [PATCH 08/16] Fix Maestro tests: use google_apis emulator target for Chrome WebView CDP support Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abca6a2..d43d499 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -351,6 +351,11 @@ jobs: with: api-level: 33 arch: x86_64 + # google_apis provides the Google Chrome WebView (chromium-based) with + # full Chrome DevTools Protocol (CDP) support. The default AOSP system + # image ships a stripped-down WebView that Maestro cannot inspect via + # CDP, causing all text assertions to time out. + target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" maestro test maestro/ From 694464001d73f2d3c55804d8e93cc990452a09a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:47:49 +0000 Subject: [PATCH 09/16] Fix APK build target: use x86_64-linux-android; add UI dump diagnostics Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d43d499..619bb81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -323,6 +323,7 @@ jobs: run: >- dx build --platform android + --target x86_64-linux-android --no-default-features --features mobile-platform @@ -358,4 +359,7 @@ jobs: target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" + adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 + sleep 15 + adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml || echo "UI dump failed" maestro test maestro/ From ecc9ee238a8f836320991b388b78f96d7d68f3bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:13:00 +0000 Subject: [PATCH 10/16] Add comprehensive diagnostics: screenshot, logcat, CDP check, artifact upload Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 619bb81..aeb37c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -348,6 +348,9 @@ jobs: echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" - name: Run Maestro flows on Android emulator + id: maestro + # continue-on-error so the artifact upload step below always runs + continue-on-error: true uses: reactivecircus/android-emulator-runner@v2 with: api-level: 33 @@ -359,7 +362,26 @@ jobs: target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" + adb logcat -c adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - sleep 15 + sleep 20 + adb exec-out screencap -p > /tmp/before-maestro.png && echo "Screenshot saved" || echo "Screenshot failed" adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml || echo "UI dump failed" - maestro test maestro/ + adb logcat -d -v time | grep -E "Console|AndroidRuntime|System.err|logworkout|dioxus|wry|WebView|chromium" | head -100 || echo "No relevant logcat entries" + adb forward tcp:9222 localabstract:com.gfaure.logworkout_devtools_remote 2>&1 && echo "CDP forward OK" || echo "CDP forward FAILED" + curl -s --max-time 3 http://localhost:9222/json 2>&1 || echo "CDP HTTP FAILED" + MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ + + - name: Upload diagnostics + if: always() + uses: actions/upload-artifact@v4 + with: + name: android-e2e-diagnostics + path: | + /tmp/before-maestro.png + if-no-files-found: ignore + retention-days: 7 + + - name: Fail if Maestro tests failed + if: steps.maestro.outcome == 'failure' + run: exit 1 From 5df5d7b90954be51f39616c1a42d48f50fb19af5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:27:13 +0000 Subject: [PATCH 11/16] Fix Android e2e: add tabindex=0 to headings for Chrome WebView accessibility + add CI diagnostics Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- src/components/active_session.rs | 2 +- src/components/exercise_list.rs | 2 +- src/components/home.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/active_session.rs b/src/components/active_session.rs index e52a164..b04a6f4 100644 --- a/src/components/active_session.rs +++ b/src/components/active_session.rs @@ -281,7 +281,7 @@ pub fn SessionView() -> Element { header { class: "session-header", div { - h2 { class: "session-header__title", "⏱️ Active Session" } + h2 { class: "session-header__title", tabindex: 0, "⏱️ Active Session" } p { class: "session-header__timer", onclick: move |_| { diff --git a/src/components/exercise_list.rs b/src/components/exercise_list.rs index e74a835..3cacc07 100644 --- a/src/components/exercise_list.rs +++ b/src/components/exercise_list.rs @@ -136,7 +136,7 @@ pub fn ExerciseListPage() -> Element { header { class: "page-header", - h1 { class: "page-title", "📚 Exercise Database" } + h1 { class: "page-title", tabindex: 0, "📚 Exercise Database" } p { class: "page-subtitle", "Browse {total} exercises" } diff --git a/src/components/home.rs b/src/components/home.rs index 68a4567..f301b9b 100644 --- a/src/components/home.rs +++ b/src/components/home.rs @@ -33,8 +33,8 @@ pub fn HomePage() -> Element { } else { section { class: "sessions-tab", header { class: "sessions-tab__header", - h1 { class: "app-title", "💪 LogOut" } - p { class: "app-tagline", "Turn off your computer, Log your workOut" } + h1 { class: "app-title", tabindex: 0, "💪 LogOut" } + p { class: "app-tagline", tabindex: 0, "Turn off your computer, Log your workOut" } } if completed_sessions().is_empty() { div { class: "sessions-empty", From d9ed707a9a999e420849e76a4abd493213a0204b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:35:59 +0000 Subject: [PATCH 12/16] Fix Maestro e2e: stopApp:false + for-loop CDP socket wait + 30s DOM load wait Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 10 +++------- maestro/launch.yaml | 5 +++-- maestro/navigation.yaml | 5 +++-- maestro/session.yaml | 5 +++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aeb37c8..ca7d554 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -362,14 +362,10 @@ jobs: target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" - adb logcat -c adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - sleep 20 - adb exec-out screencap -p > /tmp/before-maestro.png && echo "Screenshot saved" || echo "Screenshot failed" - adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml || echo "UI dump failed" - adb logcat -d -v time | grep -E "Console|AndroidRuntime|System.err|logworkout|dioxus|wry|WebView|chromium" | head -100 || echo "No relevant logcat entries" - adb forward tcp:9222 localabstract:com.gfaure.logworkout_devtools_remote 2>&1 && echo "CDP forward OK" || echo "CDP forward FAILED" - curl -s --max-time 3 http://localhost:9222/json 2>&1 || echo "CDP HTTP FAILED" + for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do adb shell cat /proc/net/unix 2>/dev/null | grep -q logworkout_devtools_remote && echo "CDP socket ready" && break; sleep 3; done + sleep 30 + adb exec-out screencap -p > /tmp/before-maestro.png && echo "Screenshot saved" || true MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ - name: Upload diagnostics diff --git a/maestro/launch.yaml b/maestro/launch.yaml index d554454..1ca1656 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,9 +1,10 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index b81bee3..406db36 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,11 +1,12 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 52aa0f0..5d0ea50 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,11 +1,12 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- -- launchApp +- launchApp: + stopApp: false - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session" From 37d1fa504bcacd8d1289fcbbbdeac0ce3470a80b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:13:13 +0000 Subject: [PATCH 13/16] Fix Maestro e2e: correct CDP socket name + remove launchApp to prevent Activity recreation Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 5 +++-- maestro/launch.yaml | 2 -- maestro/navigation.yaml | 2 -- maestro/session.yaml | 2 -- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca7d554..f7562c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -363,9 +363,10 @@ jobs: script: | adb install "${{ steps.apk.outputs.path }}" adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do adb shell cat /proc/net/unix 2>/dev/null | grep -q logworkout_devtools_remote && echo "CDP socket ready" && break; sleep 3; done - sleep 30 + for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do adb shell cat /proc/net/unix 2>/dev/null | grep -q webview_devtools_remote_ && echo "CDP socket ready" && break; sleep 3; done + sleep 15 adb exec-out screencap -p > /tmp/before-maestro.png && echo "Screenshot saved" || true + adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml | head -c 2000 || true MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ - name: Upload diagnostics diff --git a/maestro/launch.yaml b/maestro/launch.yaml index 1ca1656..45619b2 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,8 +1,6 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false - extendedWaitUntil: visible: text: "LogOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index 406db36..f2e2ce1 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,8 +1,6 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false - extendedWaitUntil: visible: text: "LogOut" diff --git a/maestro/session.yaml b/maestro/session.yaml index 5d0ea50..466e9e3 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,8 +1,6 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- -- launchApp: - stopApp: false - extendedWaitUntil: visible: text: "LogOut" From f929a05d85c5bbbce248ebfb1b018804df4b24b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 13:52:24 +0000 Subject: [PATCH 14/16] Fix Maestro e2e: add launchApp for CDP + body background-color CSS fix Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 7 +------ assets/styles.css | 6 ++++++ maestro/launch.yaml | 3 ++- maestro/navigation.yaml | 3 ++- maestro/session.yaml | 3 ++- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7562c3..181f805 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -362,11 +362,6 @@ jobs: target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" - adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do adb shell cat /proc/net/unix 2>/dev/null | grep -q webview_devtools_remote_ && echo "CDP socket ready" && break; sleep 3; done - sleep 15 - adb exec-out screencap -p > /tmp/before-maestro.png && echo "Screenshot saved" || true - adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml | head -c 2000 || true MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ - name: Upload diagnostics @@ -375,7 +370,7 @@ jobs: with: name: android-e2e-diagnostics path: | - /tmp/before-maestro.png + ~/.maestro/tests/ if-no-files-found: ignore retention-days: 7 diff --git a/assets/styles.css b/assets/styles.css index 7d2a245..4cb5f36 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -1,3 +1,9 @@ +/* ===== Base / Reset ===== */ +body { + background-color: #111; + color: #e0e0e0; +} + /* ===== Global / Shared ===== */ .container { padding: 20px; diff --git a/maestro/launch.yaml b/maestro/launch.yaml index 45619b2..24f8fa5 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,8 +1,9 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 60000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index f2e2ce1..47c773a 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,10 +1,11 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 60000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 466e9e3..38504f2 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,10 +1,11 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- +- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 30000 + timeout: 60000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session" From 4c97ebbbe57f7e02f78806e20f9c88db03baddb2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Feb 2026 02:59:13 +0000 Subject: [PATCH 15/16] Fix Maestro e2e: pre-launch warm-up + 90s timeout to beat race condition at 60s boundary Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 5 +++++ maestro/launch.yaml | 2 +- maestro/navigation.yaml | 2 +- maestro/session.yaml | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 181f805..0431340 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -362,6 +362,11 @@ jobs: target: google_apis script: | adb install "${{ steps.apk.outputs.path }}" + # Pre-launch the app so the JVM and Chrome WebView warm up before Maestro starts. + # Without this, Maestro's UIAutomator2 polling during extendedWaitUntil slows + # cold-start rendering from ~22 s to ~60 s, hitting the timeout boundary. + adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 + sleep 30 MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ - name: Upload diagnostics diff --git a/maestro/launch.yaml b/maestro/launch.yaml index 24f8fa5..d554454 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -5,5 +5,5 @@ appId: com.gfaure.logworkout - extendedWaitUntil: visible: text: "LogOut" - timeout: 60000 + timeout: 90000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index 47c773a..b81bee3 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -5,7 +5,7 @@ appId: com.gfaure.logworkout - extendedWaitUntil: visible: text: "LogOut" - timeout: 60000 + timeout: 90000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 38504f2..52aa0f0 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -5,7 +5,7 @@ appId: com.gfaure.logworkout - extendedWaitUntil: visible: text: "LogOut" - timeout: 60000 + timeout: 90000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session" From 72b27341e573bcf947ef417d73ce261925f0a24e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:34:07 +0000 Subject: [PATCH 16/16] Fix Maestro e2e: remove launchApp + 60s pre-launch sleep to eliminate rendering race condition Co-authored-by: gfauredev <19304085+gfauredev@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- maestro/launch.yaml | 3 +-- maestro/navigation.yaml | 3 +-- maestro/session.yaml | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0431340..5559567 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -366,7 +366,7 @@ jobs: # Without this, Maestro's UIAutomator2 polling during extendedWaitUntil slows # cold-start rendering from ~22 s to ~60 s, hitting the timeout boundary. adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1 - sleep 30 + sleep 60 MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/ - name: Upload diagnostics diff --git a/maestro/launch.yaml b/maestro/launch.yaml index d554454..45619b2 100644 --- a/maestro/launch.yaml +++ b/maestro/launch.yaml @@ -1,9 +1,8 @@ # Smoke test: the app launches and displays the home screen. appId: com.gfaure.logworkout --- -- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - assertVisible: "Log your workOut" diff --git a/maestro/navigation.yaml b/maestro/navigation.yaml index b81bee3..f2e2ce1 100644 --- a/maestro/navigation.yaml +++ b/maestro/navigation.yaml @@ -1,11 +1,10 @@ # Test: navigate to the exercise browser via the bottom navigation bar. appId: com.gfaure.logworkout --- -- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - tapOn: "📚" - assertVisible: "Exercise Database" - tapOn: "💪" diff --git a/maestro/session.yaml b/maestro/session.yaml index 52aa0f0..466e9e3 100644 --- a/maestro/session.yaml +++ b/maestro/session.yaml @@ -1,11 +1,10 @@ # Test: start a new workout session then cancel it. appId: com.gfaure.logworkout --- -- launchApp - extendedWaitUntil: visible: text: "LogOut" - timeout: 90000 + timeout: 30000 - tapOn: "+" - assertVisible: "Active Session" - tapOn: "Cancel Session"