Skip to content

chore: stabilize Maestro CI#7311

Open
diegolmello wants to merge 63 commits into
developfrom
chore/maestro-ci-bundle
Open

chore: stabilize Maestro CI#7311
diegolmello wants to merge 63 commits into
developfrom
chore/maestro-ci-bundle

Conversation

@diegolmello
Copy link
Copy Markdown
Member

@diegolmello diegolmello commented May 7, 2026

Proposed changes

CI observability: surface E2E server outages (commit 8d9b14f)

  • Flows are driven by REST calls (login, users.create, …) that .maestro/scripts/data-setup.js makes to the test server (mobile.qa.rocket.chat). When that server is down or blips, the flow fails deep inside an evalScript as an opaque [Failed] <flow> with no reason in the job console — diagnosing it meant downloading the Maestro artifact and reading maestro.log (that is how shard 12's room.yaml failure on run 26904017219 turned out to be a transient Non-retryable error 404 on users.create, not an app/test bug). run-maestro.sh's stdout is the job console, so two shell-level signals now render as GitHub annotations with no log/artifact spelunking: (1) a preflight that probes <server>/api/info before running flows and, on non-200, emits a red ::error:: annotation and exits — a full outage then makes every shard fail with the same clear reason instead of 13 mystery failures; (2) a mid-run scan that, on failure, greps the local Maestro logs for retryRequest's Non-retryable error <code> / connection-error fingerprints and annotates that the failure is likely a server/environment flake. Verified locally: the scan flags the real shard-12 404 log, and the preflight passes (HTTP 200) against the healthy server.

Test flow: Room Actions Unstar scroll (commit 11cfa17, shard 11)

  • The Room Actions flow's Unstar step swiped the action sheet up once and then asserted text: 'Unstar' was visible, while the symmetric Star step a few lines above uses scrollUntilVisible. When a single swipe didn't fully expand the sheet, Unstar sat below the fold and the shard failed with Assertion is false: "Unstar" is visible (e.g. run 26904017219 shard 11). It is a flake, not a regression — the same unchanged flow passed on the prior run (26897814998) — and this PR's app code touches neither the starred feature nor the action sheet. Fix: mirror the Star step so the sheet is scrolled until the item is on screen instead of asserting after one swipe.

CI infra follow-up #6 (commit 71ef5b4)

  • Make Sync subscriptions #4's SDK system-image cache actually reach the shards. Sync subscriptions #4 was correct in theory but the cache was LRU-evicted before the shards could restore it: each Maestro shard's AVD cache was read-write, so every shard (× N open PRs) re-persisted a ~3 GB AVD snapshot under the shared avd-<os>-api34 key. With three open PRs that is ~8.5 GB of AVD caches alone — well past GitHub's 10 GB per-repo cap — so the eviction policy (oldest last-access first) purged the smaller restore-only SDK cache. Evicted shards then fell through to the cold-boot path and re-ran android-emulator-runner's internal unretried sdkmanager install, hitting the exact Error on ZipFile unknown archive flake Sync subscriptions #4 set out to kill — just on the shard cold-boot path instead of the test-run path (e.g. run 26897814998 shard 5). Two changes: (1) the shards' AVD cache becomes restore-only (actions/cache/restore) — the seed job is the single writer, so shards stop duplicating the 3 GB snapshot per PR, the footprint drops back under the 10 GB cap, and the SDK cache survives to be restored; (2) the seed job's serialized 3×-retried sdkmanager install (clears partial downloads between tries) is added to the shards too, gated on an SDK-cache miss and run before any emulator boot, so a corrupt download self-heals on both the default cold-boot path and shard 14 — not only inside the seed. Durable next step (separate change, once this validates): move the seed to build-develop.yml so the AVD + SDK caches live on the default branch and are restored by every PR (GitHub lets any branch restore default-branch caches), collapsing N × ~4.7 GB of per-PR caches into one shared copy.

CI infra follow-up #5 (commits 037b120, 96525f6)

  • Drop the jlumbroso/free-disk-space step from the Android Maestro shards. Each shard starts with ~89 GB free (/dev/root 145 G, 39 % used) before anything runs; the emulator image, snapshot, and downloaded APK use a few GB against that — so the step spent ~62 s on every shard freeing space nothing was competing for. The real emulator constraint is RAM (addressed by the 6 GB bump; swap-storage was deliberately kept), which this action does not touch. Removes ~1 min from the matrix critical path and ~13 runner-minutes/run. Supersedes the "Pre-launch disk cleanup" bullet below.
  • Sync the deeplink orphan-socket fix with the now-merged fix: keep live socket on deeplink login (prevent orphan WebSocket clobber) #7380. chore: stabilize Maestro CI #7311 carried the original cherry-pick base; fix: keep live socket on deeplink login (prevent orphan WebSocket clobber) #7380 refined it before merging to develop — guarding the deeplink login gate against the connect-before-select race (METEOR.SUCCESS can fire before SERVER.SELECT_SUCCESS, where the unconditional take would hang), adding regression tests, and clarifying the SDK-patch comments. app/sagas/deepLinking.js, its test, and patches/@rocket.chat+sdk+1.3.3-mobile.patch are now identical to develop, so the branch stops carrying a divergent copy and won't conflict on the eventual develop merge.

CI infra follow-up #4 (commit a3c4788)

  • Eliminate the random Android shard failures inside reactivecircus/android-emulator-runner's internal "Install Android SDK" step (sdkmanager … --channel=0Error on ZipFile unknown archive). Each of the 13 parallel shards re-downloaded the emulator binary + the api-34 system image (~1 GB) from dl.google.com; under that concurrent load the archive intermittently arrived corrupt/truncated and killed a random shard before any test ran. The failing shard roamed (shard 12 emulator pkg, shard 7 system-image pkg in earlier runs), confirming it is download contention, not a shard-specific bug — the existing AVD cache only persists the AVD instance (~/.android/avd), not the SDK packages. The e2e-seed-android-avd seed job now also seeds the SDK packages: a separate read-write cache (key android-sdk-emu-<os>-api34) over the emulator + system-image dirs, plus a single serialized, retried sdkmanager install (3×, clearing partial downloads between tries) that self-heals a corrupt archive. Each Maestro shard (incl. shard 14) restores that cache read-only — the seed job is the single writer — so android-emulator-runner's install becomes a no-op and the per-shard dl.google.com download (and its flake) disappears. Net: 13 concurrent unguarded downloads → 1 serialized retried download.

CI infra follow-up #3 (commit 026a3d3)

  • Overlap the iOS simulator cold boot with setup. maestro-ios.yml now starts simctl boot in a dedicated Start Simulator Boot step before Install Maestro + idb, so the ~3.5 min cold boot runs in the background while Maestro + idb install (~30 s); a later Wait for Simulator Ready step blocks on simctl bootstatus -b. The SpringBoard settle after boot is trimmed 15 s → 5 s (bootstatus -b already guarantees a completed boot). Shaves ~40–55 s off every iOS shard's critical path.
  • Fold the single-flow shard 9 (e2ee/e2e-encryption.yaml, test-9test-3) into shard 3 and drop shard 9 from both the iOS and Android matrices in build-pr.yml. Shard 9 ran one flow, so its ~3.5 min cold boot was almost pure overhead — this removes one boot per platform per run. Shard 3 (onboarding/workspace validation, the lightest 3-flow shard) goes 3 → 4 flows.

CI infra follow-up #2 (commit 63db0eb)

  • Add a serial e2e-seed-android-avd job in build-pr.yml between e2e-hold and e2e-run-android. Every shard in the 14-job matrix was previously hitting actions/cache simultaneously and missing — nothing had been written yet — so every shard ran its own "Generate AVD snapshot for cache" step. The seed job restores or generates the AVD snapshot once, post-uploads, and then the matrix fans out — every shard's cache restore now hits. The repo is also at ~12.5 GB of caches (over the 10 GB cap), so the AVD entry was the LRU victim across runs; the seed job re-populates on each PR run regardless. The per-shard fallback step stays as defense in depth.

CI infra follow-up (commit 2066fbf)

  • Anchor the Open in App? dialog tap selector in .maestro/helpers/open-deeplink.yaml to text: '^Open$'. Unanchored Open matched both the iOS 26 alert title ("Open in 'Rocket.Chat Experimental'?") and the button; on cold-launch (shard 1) Maestro's index: 0 picked the title at (275, 485) pt instead of the button at ~(277, 573) pt, the dialog persisted, and all 4 flows chain-failed. Other shards launch the app via UI first so the dialog either doesn't appear or its hierarchy looks different — same regex happened to work. Anchoring kills the ambiguity.
  • Raise iOS Run Maestro Tests step timeout-minutes 30 → 45. Dropping nick-fields/retry removed the previous 2×30=60 min ceiling; shard 12 ran 35 min on run 26168373950 and was killed mid-flight. 45 min matches the slowest passing shard (~27 min) plus rerun headroom.
  • Raise Android AVD snapshot-generation step timeout-minutes 30 → 45. A cache miss after the 4 GB → 6 GB RAM bump pushed cold-boot + AVD recreate past the cap on shard 3. Once the cache repopulates, future runs hit cache and skip this step.

CI infra (Android & iOS)

  • Bump Maestro CLI 2.2.0 → 2.5.1. 2.5.0 switched from gRPC to dadb's direct ADB socket, eliminating the Broken pipe install failures that were the dominant Android shard flake source.
  • Drop the monkey warmup in run-maestro.sh (+ trailing sleep 6 / am force-stop) — it stressed system_server right before Maestro's driver install.
  • Add explicit AVD snapshot caching for shards 1–13: cache miss → cold boot to seed snapshot; cache hit → replay with -no-snapshot-save to prevent corruption. Keyboard AVD (shard 14) untouched.
  • Bump Android emulator RAM 4 GB → 6 GB on all android-emulator-runner steps.
  • ~~Pre-launch disk cleanup via jlumbroso/free-disk-space@v1.3.1 (Android SDK preserved; ~6 GB freed).~~ Removed in follow-up Show user's list #5 — the shards already start with ~89 GB free.
  • Drop the nick-fields/retry wrapper on iOS Maestro shards and lower MAX_RERUN_ROUNDS in run-maestro.sh from 3 → 2. The compounded retry produced up to 8 reruns of each failing flow (outer max_attempts: 2 × inner 1 main + 3 rerun rounds), wasting ~20 min/job on deterministic failures and re-running every flow in the shard on outer retry. New ceiling per failing flow: 3 runs (1 main + 2 rerun rounds). Android already called the script directly and inherits the new default.
  • Expand artifact upload globs to include JUnit XMLs (maestro-report.xml, maestro-rerun-round-*.xml) and the full ~/.maestro/tests tree — previously only screenshots were captured.
  • Move iOS Maestro shards to macos-26 + Xcode 26.2.0 to match e2e-build-ios.yml. The artifact is built against the iOS 26 SDK; the prior macos-14 runner booted iOS 18.2, which surfaced a rocketchat://room?path= deeplink crash that does not reproduce on the build-matched runtime.

App: sidebar testID fix (unblocks shard 8 + ~12 other flows)
SidebarView wraps the ScrollView in a plain View carrying testID='sidebar-view'. On Android, ScrollView does not propagate testID to the native accessibility tree; a regular View does. Folded in from #7319.

App: profile rate-limit fix (shard 8, Android)
profile.yaml was making three consecutive users.updateOwnBasicInfo calls; the endpoint is rate-limited per user. Collapsed into one combined submit (name, username, nickname, bio, email) before tapping submit. The password-confirm sheet and ChangePasswordView path are preserved.

App: form keyboard scroll fix (shard 6, iOS)
FormContainer swaps KeyboardAvoidingView + ScrollView for KeyboardAwareScrollView from react-native-keyboard-controller (already a dep). KAS scrolls the focused TextInput above the keyboard on focus change, preventing Maestro 2.5.1's tapOn from landing on the QWERTY row instead of the target field.

App: iOS Save Password suppression at FormTextInput (shards 1 & 9, iOS)
iOS 26 surfaces a system Save Password? sheet asynchronously (0.5s–7s variable latency) after any secureTextEntry={true} field submit. It overlays the app and blocks XCUITest hit-testing, breaking shard 1 (change-password.yaml, 100% deterministic — 8/8 failures in run 26117774450 all show the sheet over rooms-list-view) and shard 9 (e2e-encryption.yaml). The earlier YAML-level dismiss (a one-shot runFlow when: visible: 'Securely store your password') missed the late-arriving variant of the sheet and required per-test discipline.

Researched alternatives (no clean sim/CLI/Maestro-config kill switch exists — confirmed by Detox #3761, Selenium #11426, Maestro #2089). iOS only engages Password AutoFill on secureTextEntry={true} fields; setting it to false declassifies the field at the OS level and suppresses the offering entirely. RegisterView already uses this same pattern at register-view-password.

Fix: in app/containers/TextInput/FormTextInput.tsx, when RUNNING_E2E_TESTS === 'true' on iOS, suppress the native secureTextEntry prop passed to the underlying TextInput. Visual masking and the show/hide eye icon stay driven by the original prop. One seam covers every password field that uses the shared input (LoginView, ChangePasswordView, E2EE views, RoomInfoEditView, etc.). Plaintext password rendering under E2E mirrors what RegisterView already does and is acceptable for test environments using throwaway credentials. The YAML dismiss block added in b04b5ab is reverted.

App: jump to message over DDP (fixes NATIVE-1126, unblocks jump-to-message.yaml)
sdk.methodCall appended the 2FA code as this.code || '' — a trailing positional argument on every DDP method call. That empty string was a harmless ignored extra until the server's loadSurroundingMessages grew a typed showThreadMessages: boolean 3rd param (RocketChat/Rocket.Chat#39092, 2026-03-10); the '' then fails the server's check(showThreadMessages, Boolean), returning a 500 that rejects loadSurroundingMessages and aborts the quoted-message "Jump to message" flow (loading spinner shows, never navigates). Fix in app/lib/services/sdk.ts: append the TOTP code only when a 2FA flow is in progress, so non-2FA DDP calls send exactly their declared params (matching the REST path and the server default); the 2FA retry still appends the resolved code. Verified against mobile.qa (server 8.4): the quoted-message jump now loads surroundings and scrolls to message-content-1.

App: jump-to-message scroll race timeout (shard 11, jump-to-message.yaml "search old message and load surroundings" block)
RoomView.jumpToMessage races the list scroll against a fixed 5s wall-clock cap. Reaching an off-screen target grows the rendered take(count) window 50 rows per round (600ms each, via scrollToEnd → onEndReached) until the target row enters it — so the scroll's duration is O(rows already loaded in the DB), not constant. On the slow CI release emulator that loop exceeds 5s, the race cancels, the target never centers, and the assertion on message-content-29 times out. Raised the cap 5s→20s in app/views/RoomView/index.tsx; the Loading overlay already exposes a cancel button, so a longer ceiling is not a UX trap. The proper fix — re-anchoring the rendered window onto the target so the jump is deterministic and O(1) regardless of distance (the approach Slack/Telegram/Matrix use) — is deferred to a follow-up.

Deferred (tracked separately)

  • Shard 12 (room-last-message-thread-50-plus.yaml) — Maestro gesture injection exits RoomView mid-scroll; tracked as NATIVE-1128.
  • Shard 11 (jump-to-message.yaml) — quoted-message jump (NATIVE-1126) fixed here; composer auto-focus (NATIVE-1125) tracked separately.

Issue(s)

NATIVE-1123 · NATIVE-1126

Related (deferred, not fixed here): NATIVE-1125 · NATIVE-1128

How to test or reproduce

  1. Trigger the Build PR workflow on this branch and watch the 13 Android + 13 iOS Maestro shards (shard 9 folded into shard 3, so the matrix skips 9).
  2. Confirm absence of Broken pipe, Monkey aborted, and Failed to install apk in shard logs.
  3. Shard 8 (Android): should progress past the sidebar-view step and complete profile edits + password change in a single submit.
  4. Shard 6 (iOS): helpers/create-account.yaml should complete with a clean email field (no leading t/tmobile character corruption).
  5. Shards 1 & 9 (iOS): change-password.yaml and e2e-encryption.yaml should complete on iOS 26 — no Save Password? sheet appears because every FormTextInput-backed password field is declassified under RUNNING_E2E_TESTS=true.
  6. Shard 11: the quoted-message "Jump to message" now loads surroundings and scrolls to message-content-1 (NATIVE-1126); any remaining red is the separately-tracked composer auto-focus (NATIVE-1125). The Room Actions flow's Unstar step now scrolls the action sheet to the Unstar item instead of asserting after a single swipe, so it no longer flakes on Assertion is false: "Unstar" is visible.
  7. iOS shards: the old Boot Simulator step is split into Start Simulator Boot (async, before Maestro install) + Wait for Simulator Ready (blocks on bootstatus -b); per-shard boot+setup wall time should drop ~40–55 s vs the previous serial boot. Shard 3 now also runs e2e-encryption.yaml and should stay green without becoming the slowest iOS shard.
  8. Android shards: the seed job's Pre-install Android SDK packages step downloads the emulator + api-34 system image once (and retries on a corrupt archive). Each shard's Restore Android SDK packages step should report a cache hit, android-emulator-runner's "Install Android SDK" step should be a no-op (no dl.google.com pull), and no shard should die with Error on ZipFile unknown archive.

Screenshots

n/a

Types of changes

  • Bugfix (non-breaking change which fixes an issue) — sidebar testID, profile rate-limit, form keyboard scroll, iOS 26 Save Password suppression at FormTextInput, jump-to-message DDP 2FA-code arg, jump-to-message scroll race timeout (5s→20s)
  • Improvement (non-breaking change which improves a current function) — CI stabilization

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable) — covered by the Maestro flows this PR unblocks
  • I have added necessary documentation (if applicable) — inline comments next to each pinned version
  • Any dependent changes have been merged and published in downstream modules

Further comments

The sidebar testID fix was originally opened as #7319 and folded here so CI stabilization and its dependency ship together (#7319 closed). Acceptance is measured over a 10-run window on develop after this lands; tracked separately.

Summary by CodeRabbit

  • Chores

    • Upgraded Maestro CLI to 2.5.1 for Android and iOS; improved emulator caching and increased emulator memory for Android.
    • Adjusted test workflow retry behavior and added pre-test app install to improve run reliability.
  • Tests

    • Consolidated profile edit flow into a single submit and added deterministic scrolling in message-thread tests to reduce flakiness.
  • Style

    • Minor Sidebar layout adjustment (no functional change).

Review Change Stack

@diegolmello diegolmello temporarily deployed to approve_e2e_testing May 7, 2026 20:45 — with GitHub Actions Inactive
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR upgrades Maestro to 2.5.1 (Android/iOS), changes Android AVD caching and emulator RAM/options, replaces the Android monkey pre-test step with adb install -r, adjusts iOS retry behavior to error, batches profile test edits, and moves SidebarView's testID to an outer View.

Changes

Maestro Test Infrastructure Upgrade

Layer / File(s) Summary
Maestro Version & iOS retry changes
.github/workflows/maestro-android.yml, .github/workflows/maestro-ios.yml
MAESTRO_VERSION pinned to 2.5.1 (Android & iOS); iOS “Run Maestro Tests” retry changed from timeout to error.
Android Emulator & AVD Caching Strategy
.github/workflows/maestro-android.yml
Gates AVD cache to non-shard-14, boots pixel_7_pro on cache miss to generate a snapshot, increases emulator RAM to 6144M, and adds -no-snapshot-save for non-keyboard runs; shard-14 step also uses 6144M.
Test Execution Script & Maestro Tests
.github/scripts/run-maestro.sh, .maestro/tests/assorted/profile.yaml, .maestro/tests/room/room-last-message-thread-50-plus.yaml
Replaces Android monkey-launch/force-stop with adb install -r app-experimental-release.apk before Maestro; Maestro invocation unchanged; profile test batches multiple field edits into a single submit; room test replaces scrollUntilVisible with a deterministic repeat-scroll sequence.

Sidebar View Layout Change

Layer / File(s) Summary
Imports
app/views/SidebarView/index.tsx
Adds View to react-native imports.
Render
app/views/SidebarView/index.tsx
Wraps ScrollView in an outer View with testID='sidebar-view'; removes testID from ScrollView.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: chore

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'chore: stabilize Maestro CI' directly aligns with the main objective of improving Maestro-based test stability through Maestro version upgrades, emulator resource adjustments, and caching improvements.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (4)
  • NATIVE-1125: Request failed with status code 401
  • NATIVE-1126: Request failed with status code 401
  • NATIVE-1123: Request failed with status code 401
  • EMULATOR-5554: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@diegolmello diegolmello temporarily deployed to experimental_android_build May 7, 2026 20:50 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_android_build May 7, 2026 20:50 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_ios_build May 7, 2026 20:50 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_ios_build May 7, 2026 20:50 — with GitHub Actions Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/maestro-android.yml (1)

41-48: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Shard 14 can poison the shared AVD cache, defeating the snapshot optimization for all other shards

The Cache Android AVD step has no if condition, so shard 14 participates in both cache restore and save under the same key (avd-${{ runner.os }}-api34).

On a cold run, all 14 shards race to save to that key (GitHub Actions is first-writer-wins). If shard 14 wins, the cache stores only Pixel_API_34_Keyboard.avd + Pixel_API_34_Keyboard.ini. On subsequent runs:

  1. Non-keyboard shards see steps.avd-cache.outputs.cache-hit == 'true'
  2. The "Generate AVD snapshot" step is skipped (its condition checks cache-hit != 'true')
  3. The test step runs with force-avd-creation: false — but the expected default-profile AVD is absent from the restored cache

The behavior of reactivecircus/android-emulator-runner when force-avd-creation: false and the named AVD doesn't exist is unspecified; it may silently cold-boot (losing the optimization) or fail outright. Either way, the caching strategy is silently broken.

🐛 Proposed fix — exclude shard 14 from AVD caching
      - name: Cache Android AVD
+       if: ${{ inputs.shard != '14' }}
        id: avd-cache
        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ runner.os }}-api34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maestro-android.yml around lines 41 - 48, The "Cache
Android AVD" step (id: avd-cache, name: Cache Android AVD, key: avd-${{
runner.os }}-api34) must be excluded from shard 14 so it doesn't poison the
shared AVD cache; update the step to run only when the shard is not 14 (e.g. add
an if condition referencing your matrix/shard variable such as if: matrix.shard
!= 14) so shard 14 neither restores nor saves to the common key, leaving other
shards to generate and cache the full AVD snapshot correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/maestro-android.yml:
- Around line 24-33: The workflow currently uses the jlumbroso/free-disk-space
action with swap-storage: true while configuring the emulator's ram-size: 6144M,
which disables swap and leaves under ~800MB host memory — change either the
swap-storage or ram-size to avoid OOMs: set swap-storage: false to retain the
runner swapfile, or reduce ram-size to 5120M or 4608M so host+emulator fit in
physical RAM; update the keys swap-storage and ram-size in the action usage
(uses: jlumbroso/free-disk-space@...) and apply the same change to the other
occurrences noted (the other blocks referenced) so all workflow entries are
consistent.

In @.github/workflows/maestro-ios.yml:
- Around line 14-15: The comment incorrectly mentions the Android-specific
"dadb"/ADB change; update the comment text that currently references "dadb" and
ADB to an iOS-appropriate note explaining that iOS Maestro uses
idb/libimobiledevice (not ADB) and that the Android-specific CLI 2.5.0 change
does not apply to the iOS workflow; either remove the ADB-specific sentence or
replace it with a short iOS-focused explanation and keep or adjust the release
link as needed so the comment accurately reflects iOS tooling.

---

Outside diff comments:
In @.github/workflows/maestro-android.yml:
- Around line 41-48: The "Cache Android AVD" step (id: avd-cache, name: Cache
Android AVD, key: avd-${{ runner.os }}-api34) must be excluded from shard 14 so
it doesn't poison the shared AVD cache; update the step to run only when the
shard is not 14 (e.g. add an if condition referencing your matrix/shard variable
such as if: matrix.shard != 14) so shard 14 neither restores nor saves to the
common key, leaving other shards to generate and cache the full AVD snapshot
correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee299d9c-ce31-45fd-89b1-673983985558

📥 Commits

Reviewing files that changed from the base of the PR and between 8b70425 and 5ee7fad.

📒 Files selected for processing (3)
  • .github/scripts/run-maestro.sh
  • .github/workflows/maestro-android.yml
  • .github/workflows/maestro-ios.yml
💤 Files with no reviewable changes (1)
  • .github/scripts/run-maestro.sh
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: E2E Build Android / android-build
  • GitHub Check: ESLint and Test / run-eslint-and-test

Comment thread .github/workflows/maestro-android.yml Outdated
Comment thread .github/workflows/maestro-ios.yml Outdated
@diegolmello diegolmello deployed to upload_official_android May 7, 2026 21:30 — with GitHub Actions Active
@diegolmello diegolmello temporarily deployed to upload_experimental_android May 7, 2026 21:31 — with GitHub Actions Inactive
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Android Build Available

Rocket.Chat 4.72.0.108814

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Android Build Available

Rocket.Chat Experimental 4.72.0.108813

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Android Build Available

Rocket.Chat Experimental 4.72.0.108813

Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNTowuRjjHlDYUgXqroMl8epJWmBJOAe-7N_6W5JjAcJyBHu-MfbZDIilMfFnPJkwzs7kKMzme1NVFTUUxnE

@diegolmello diegolmello had a problem deploying to upload_official_ios May 7, 2026 21:43 — with GitHub Actions Failure
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

iOS Build Available

Rocket.Chat Experimental 4.72.0.108816

@diegolmello diegolmello temporarily deployed to approve_e2e_testing May 8, 2026 08:04 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_ios_build May 8, 2026 08:09 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_ios_build May 8, 2026 08:09 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_android_build May 8, 2026 08:09 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_android_build May 8, 2026 08:09 — with GitHub Actions Inactive
@diegolmello diegolmello had a problem deploying to upload_experimental_android May 8, 2026 08:46 — with GitHub Actions Error
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Android Build Available

Rocket.Chat Experimental 4.72.0.108821

Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNQLTMEQOTK7Yu4n98ufM0ImDLGPoEI7tdqqt4_8PqA3XXsk_0JhIS1tJIiRPRZJU0Eh3mtvcPjDUgnnZ0rq

@diegolmello diegolmello had a problem deploying to upload_official_android May 8, 2026 08:50 — with GitHub Actions Error
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

iOS Build Available

Rocket.Chat Experimental 4.72.0.108822

The iOS / Android Maestro workflows only uploaded *.png under
~/.maestro/tests. JUnit XML (maestro-report.xml,
maestro-rerun-round-*.xml) and Maestro's per-flow command logs were
discarded, so a CI failure surfaced only as a screenshot of the final
state, not the failing step or step trace.

Expand the upload-artifact globs on both workflows to include the
JUnit reports (in CWD) and the full ~/.maestro/tests tree.
Align Maestro iOS shards with e2e-build-ios so the artifact built against
the iOS 26 SDK is executed on an iOS 26 simulator runtime instead of the
macos-14 default (iOS 18.2). Cross-SDK execution surfaced an app crash on
the rocketchat://room?path= deeplink that does not reproduce on the
build-matched runtime.
The macos-26 image does not ship an "iPhone 16 Pro" device; Boot Simulator
failed with "Invalid device: iPhone 16 Pro" and aborted the shard before
maestro could run. Enumerate the available simulator catalog and select the
highest-numbered iPhone N Pro present so the workflow survives image rotation.
iOS 26 surfaces a system "Save Password?" prompt after successful native
form submission. It is presented as a modal sheet on top of the rooms list,
which blocks XCUITest hit-testing for elements underneath. Maestro's
`extendedWaitUntil id: rooms-list-view-sidebar, enabled: true` therefore
never resolves and shard 9 (e2e-encryption) times out on the macos-26 /
iOS 26 runners (reliably green on macos-14 / iOS 18.2).

Dismiss the prompt with "Not Now" if visible, gated on iOS, in both
`helpers/login.yaml` (catches the modal immediately after submit) and
`tests/e2ee/utils/navigate-to-e2ee-security.yaml` (catches it if the
e2ee saga delays the modal past the login wait). On platforms or runs
where the prompt does not appear, the `runFlow when` block is a no-op.
iOS Maestro tests were running each failing flow up to 8 times:
nick-fields/retry max_attempts=2 multiplied by run-maestro.sh's
internal 1 main + 3 rerun rounds. Deterministic failures wasted
~20 min/job; the wrapper also re-ran every flow in the shard, not
just the failed one, since it had no flow-level state.

Drop the wrapper on iOS (Android never had it) and lower
MAX_RERUN_ROUNDS from 3 to 2 so the script-internal loop alone
gives at most 3 runs per failing flow.
…ord flow

The "Save Password?" system sheet that iOS 26 shows after a native password
form submission is the root cause of the change-password.yaml shard-1 flake
(8/8 failure screenshots in run 26117774450 show the same sheet overlaying
rooms-list-view).

Two gaps in b04b5ab covered only login.yaml:

1. The change-password submit (`change-password-view-set-new-password-button`)
   also surfaces the sheet. Nothing dismissed it there, so the subsequent
   `assertVisible: rooms-list-view` was blocked by the modal.
2. The sheet has variable latency on iOS 26 (~0.5s–7s observed). The
   pre-existing one-shot `runFlow when: visible:` in login.yaml fires
   immediately after rooms-list-view becomes visible and frequently misses
   a late-rendering sheet, so the next interactive assertion times out.

Consolidate the dismiss into a shared `helpers/dismiss-save-password.yaml`
that waits up to 8s for the sheet with `optional: true` (no-op on Android /
iOS 18), then taps Not Now with `optional: true`. Call it from login.yaml,
change-password.yaml (both after new-password submit and before the final
re-login assertion), and the existing e2ee navigate helper.
iOS 26 surfaces a system "Save Password?" sheet asynchronously (0.5s–7s
variable latency) after any secureTextEntry field submit. It overlays
the app and blocks XCUITest hit-testing, causing Maestro change-password
shard-1 to fail at rooms-list-view assertions 100% on macos-26 runners
(8/8 failures in run 26117774450 show the same sheet over rooms-list-view).

Research summary: iOS sim has no documented kill switch (confirmed by
Detox #3761, Selenium #11426, Maestro #2089). Maestro has no
auto-dismiss and no workspace-level onFlowStart hook (#2063). iOS only
engages Password AutoFill on `secureTextEntry={true}` fields, regardless
of `textContentType` value, except `oneTimeCode`. Setting
`secureTextEntry={false}` declassifies the field and suppresses the
offer entirely — the same trick `RegisterView` already uses at
`register-view-password`.

Apply this gating once at `FormTextInput.tsx` so every password field
that uses the shared input (LoginView, ChangePasswordView, E2EE views,
RoomInfoEditView, etc.) is covered. Visual mask + show/hide eye icon
stay driven by the original `secureTextEntry` prop; only the native
prop passed to the underlying TextInput is suppressed. Plaintext
password rendering under E2E mirrors what RegisterView already does
and is acceptable for test environments that use throwaway credentials.

Revert b04b5ab + the dismiss-save-password helper added earlier on this
branch — no longer needed since the prompt never surfaces in E2E builds.

Note: TwoFactor, JoinCode, ProfileView ActionSheets and the generic
ActionSheetContentWithInputAndSubmit use raw TextInput (not
FormTextInput) and are not covered by this fix. They are not currently
exercised by any failing iOS Maestro shard; same pattern can be applied
locally there if a flow lands that exercises them on iOS 26.
iOS classifies a field as a credential for Password AutoFill / Save
Password via any of three signals: secureTextEntry, textContentType in
{password, newPassword, ...}, or autoComplete in {password, password-new,
...}. The previous patch flipped only secureTextEntry, so iOS still
classified LoginView and E2EEnterYourPasswordView (both hardcode
textContentType='password' + autoComplete='password' on iOS) as
credential fields and surfaced the "Save Password?" sheet on iPhone 17
Pro / iOS 26 fresh sims in CI, blocking shard 9 (e2e-encryption.yaml).

Extend the FormTextInput-level suppression to override all three under
RUNNING_E2E_TESTS on iOS so the underlying TextInput presents as a
neutral text field to UIKit. Visual masking and the show/hide eye icon
still follow the original secureTextEntry prop.
iOS shard 1's open-deeplink helper used `text: Open` which is a regex
match. On iOS 26 cold-launch the alert title "Open in 'Rocket.Chat
Experimental'?" also matches `Open`, and Maestro's index:0 hits the
title bounds (~275, 485 pt) instead of the button (~277, 573 pt), so
the dialog stays up and every flow in shard 1 chain-fails. Other shards
launch the app via UI first so the dialog either does not appear or its
hierarchy looks different — same regex happens to work there. Anchor
the selector to `^Open$`.

iOS Run Maestro Tests step was capped at 30 min after we dropped the
nick-fields/retry wrapper (which gave 2x30=60 min). Shard 12 ran ~35
min and was killed mid-flight; raise to 45 to match the longest passing
shard plus rerun budget.

Android AVD snapshot generation step was capped at 30 min. A cache miss
after the 4G→6G RAM bump pushed cold-boot + recreate past that. Raise
to 45 so a one-time cache repopulate succeeds and future runs hit cache.
All 14 Android shards start in parallel and check actions/cache at the
same instant. Nothing has been written yet, so every shard misses and
runs its own "Generate AVD snapshot for cache" step — burning ~90s per
shard on a 6 GB emulator boot the matrix could have shared. The repo
is also at ~12.5 GB of caches (over the 10 GB cap), so the AVD cache
is the LRU victim and gets evicted before the next run anyway.

Add a single serial `e2e-seed-android-avd` job between `e2e-hold` and
`e2e-run-android`. It restores or generates the AVD snapshot once,
post-uploads, and then the matrix kicks off — so every shard's
`Cache Android AVD` step now hits. The existing per-shard fallback
stays as defense in depth for the (rare) eviction-between-jobs case.
…ttern

Bumps `rooms-list-view` (was assertVisible w/ no timeout) and
`rooms-list-view-item-${ROOM}` (was 10s) to the 60s extendedWaitUntil
pattern used elsewhere. Targets the Android 5 / Accessibility flake
observed in run 26244170118 where the search-result visibility check
timed out twice consecutively before finally passing.
…t.Chat.ReactNative into chore/maestro-ci-bundle
…calls

sdk.methodCall appended `this.code || ''` (the TOTP code) as a trailing
positional argument to every DDP method call. That empty string was a
harmless ignored extra until the server's loadSurroundingMessages method
grew a typed `showThreadMessages: boolean` 3rd param (RocketChat/Rocket.Chat
#39092). The '' then fails the server's `check(showThreadMessages, Boolean)`,
returning a 500 that rejects loadSurroundingMessages and aborts the whole
jump-to-message flow (loading shows, no navigation).

Append the TOTP code only when a 2FA flow is in progress, so non-2FA DDP
calls send exactly their declared params — matching the REST path and the
server default. The 2FA flow is preserved: the codeless first call still
gets totp-required, then the retry appends the resolved code.

Covered by the existing .maestro/tests/room/jump-to-message.yaml flow.
RoomView.jumpToMessage races the list scroll against a fixed wall-clock
cap. The scroll grows the rendered take(count) window 50 rows at a time
(600ms/round) until the target enters it, so its duration is O(rows
already loaded), not constant. On the slow CI release emulator the loop
exceeds 5s, the race cancels, the target never centers, and the
jump-to-message shard flakes (message-content-29 never visible).

Bump the cap 5s→20s to cover the slow-device convergence; the Loading
overlay already exposes a cancel button, so a longer ceiling is not a UX
trap. Deterministic re-anchoring of the window is the proper fix and is
deferred to a follow-up.
…hard 8)

On CI, opening the keyboard on ChangePasswordView shrinks the KeyboardView (behavior='padding') scroll viewport until only the title + current-password fit, clipping new-password/confirm below the fold (they drop out of the view hierarchy). The bare assertVisible does not scroll, so it never sees them and shard 8 fails on every attempt that reaches this sub-flow. Dismiss the keyboard via the existing hide-keyboard helper before each assert, mirroring how the ProfileView edits already behave.
@github-actions
Copy link
Copy Markdown

A long background marks the DDP socket stale, so foregrounding triggers
checkAndReopen -> forceReopen, which drops all SDK subscriptions and reopens
the socket without going through connect(). The module-level roomsSubscription
guard therefore stayed set, so subscribeRooms() skipped re-subscribing
stream-notify-user and the rooms list silently stopped reflecting
subscriptions/favorites/reads until a manual reconnect.

Reset the guard from the socket 'close' listener (via unsubscribeRooms), the
same teardown connect() already performs, so the resume-login that follows the
reopen re-subscribes stream-notify-user. Other streams (permissions, presence,
settings, roles) subscribe unconditionally and were never affected.
…bber)

Auth-deeplink login dispatched loginRequest before the socket reached 'connected', so the SDK login-guard opened a second (orphan) socket. When the server later idle-timed-out the abandoned socket, its close flipped Redux to disconnected and the app showed "Waiting for network" while a live socket still existed.

- SDK (patch): onClose ignores close events from a non-current socket; open() tears down the previous connection before replacing it.

- deepLinking saga: wait for METEOR.SUCCESS ('connected') before dispatching the resume loginRequest (auth-deeplink and call-push paths); update saga test accordingly.
…undle

# Conflicts:
#	app/sagas/deepLinking.js
A quoted reply renders its text via a nested <Markdown> inside the message's
single accessible Touchable. On iOS that subtree is merged into the parent
accessibility element, so the quoted text is never exposed on its own (on
Android the raw text node is still enumerated). Add a useQuoteDescriptionLabel
hook, mirroring useImageDescriptionLabel, and fold the quoted text into
useMessageAccessibilityLabel. VoiceOver now announces quoted content, and the
iOS jump-to-message Maestro assertion that matches the quoted text can resolve.
… shard

- maestro-ios.yml: start the simulator cold boot asynchronously before
  installing Maestro + idb so the ~3.5min cold boot overlaps the ~30s
  install, then block on bootstatus afterwards. Trim post-boot settle 15s -> 5s.
- Fold the lone shard-9 flow (e2e-encryption) into shard 3 and drop shard 9
  from both iOS and Android matrices, removing one cold boot per platform per run.
The android-emulator-runner action's internal 'Install Android SDK' step
re-downloads the emulator binary and the api-34 system image (~1 GB) from
dl.google.com on every one of the 13 parallel Maestro shards. Under that
concurrent load the download intermittently arrives corrupt/truncated and
sdkmanager dies with 'Error on ZipFile unknown archive', failing a random
shard before any test runs. The existing AVD cache only persists the AVD
instance (~/.android/avd), not the SDK packages.

Promote the e2e-seed-android-avd seed job to also seed the SDK packages:
- a separate read-write cache (key android-sdk-emu-<os>-api34) over the
  emulator + system-image dirs, and
- a single serialized, retried sdkmanager install (3x, clearing partial
  downloads between tries) that runs before the snapshot step, so a corrupt
  archive self-heals instead of failing the matrix.

Each Maestro shard restores that cache read-only (seed job is the single
writer), so android-emulator-runner's install becomes a no-op and the
per-shard dl.google.com download is eliminated.
#7311 carried the original cherry-pick base of the deeplink/orphan-socket
fix. The standalone PR #7380 refined it before merging to develop:
- guard the login gate against the connect-before-select race (METEOR.SUCCESS
  may fire before SERVER.SELECT_SUCCESS; the unconditional take would hang)
- added regression tests for that ordering + the call-push path
- clarified the SDK patch comments (FIX A primary/defense)

Bring app/sagas/deepLinking.js, its test, and the SDK patch in line with
develop's merged #7380 version so #7311 stops carrying a divergent copy.
The Android test shards start with ~89 GB free (/dev/root 145G, 39% used)
before anything runs; the emulator image + snapshot + downloaded APK use a
few GB against that. jlumbroso/free-disk-space cost ~62s on every shard to
free space nothing was competing for. The real emulator constraint is RAM,
which this action doesn't address (and swap-storage was already kept).

Removes ~1 min from the matrix critical path and ~13 runner-minutes/run.
Android shards each persisted a ~3 GB AVD snapshot under a shared key.
With multiple open PRs this pushed the repo past GitHub's 10 GB Actions
cache cap, LRU-evicting the SDK system-image cache before the shards
restored it. Evicted shards then cold-booted and re-downloaded the
system image in a single unretried sdkmanager call, intermittently
hitting "Error on ZipFile unknown archive" and failing the shard.

- AVD cache -> actions/cache/restore (restore-only). The seed job is the
  single writer, so shards no longer duplicate the 3 GB snapshot per PR;
  the footprint stays under the 10 GB cap and the SDK cache survives.
- Add a 3x-retried sdkmanager install (mirrors the seed job), gated on an
  SDK-cache miss and run before any emulator boot, so a corrupt download
  self-heals on both the default cold-boot path and shard 14.
The Unstar step swiped the action sheet up once and asserted 'Unstar' was
visible, while the symmetric Star step uses scrollUntilVisible. When a single
swipe didn't fully expand the sheet, 'Unstar' stayed below the fold and the
shard failed with "Assertion is false: 'Unstar' is visible". Mirror the Star
step so the sheet is scrolled until the item is on screen.
Flows are driven by REST calls (login, users.create, …) that data-setup.js
makes to the test server. When the server is down or blips, a flow fails deep
inside an evalScript as an opaque "[Failed] <flow>" with no reason in the job
log — diagnosing it meant downloading the Maestro artifact and reading
maestro.log. Two shell-level signals (run-maestro.sh stdout is the job console,
so these render as GitHub annotations without opening logs):

- Preflight: probe <server>/api/info before running flows; on non-200 emit a
  red annotation and exit. A full outage makes every shard fail with the same
  clear reason instead of 13 mystery flow failures.
- Mid-run scan: on failure, grep the local Maestro logs for retryRequest's
  "Non-retryable error <code>" / connection-error fingerprints and annotate
  that the failure is likely a server/environment flake.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant