Skip to content

test: stop iPad UI tests flaking on dropped sidebar taps#19

Merged
brendan-ch merged 1 commit into
mainfrom
chore/fix-ipad-test-flake
Jun 20, 2026
Merged

test: stop iPad UI tests flaking on dropped sidebar taps#19
brendan-ch merged 1 commit into
mainfrom
chore/fix-ipad-test-flake

Conversation

@brendan-ch

Copy link
Copy Markdown
Owner

Problem

The iPad CI leg intermittently failed AppListUITests.testAppListsEditableWithoutHardSession with Expected "ruleCard-Sleep" Button to exist within 5.0s. A screen recording of a failing run showed that, after the sidebarItem-rules tap, the sidebar still had Home selected and the detail column still showed HomeView — the rule list never rendered.

Root cause

goToSection navigates differently per layout:

  • iPhone (MainTabView) taps a tab-bar button — a robust hit target, instant switch.
  • iPad (MainSidebarView) taps a NavigationSplitView List(selection:) sidebar row to drive the detail column.

The iPad branch fired that sidebar tap once with no verification or retry. Synthesized taps against a selection-driven sidebar row are occasionally dropped before the app has quiesced (a periodic TimelineView keeps it non-idle at launch — visible as the ~23s "wait for idle" in the failure log). When the tap is dropped, selection never changes, the detail stays on the previous section, and the next content assertion fails. Rare → flaky, and iPhone is unaffected.

Fix

Verify the navigation actually landed before returning. Each section's detail names its navigation bar after the same label as the tab/row (navigationTitle("Rules")navigationBars["Rules"]), giving a device-agnostic post-condition. The iPad branch now taps, waits for that bar, and re-taps if it didn't appear (up to 5 attempts). The iPhone tab-bar path is unchanged; the happy path returns as soon as the bar appears.

Test plan

All run on iPad Pro 11-inch (M5) — the CI device:

  • AppListUITests/testAppListsEditableWithoutHardSession (previously flaky) — pass
  • AppListUITests/testHardModeSessionLocksAppListEditing — pass
  • NavigationChromeUITests/testNavigationChromeMatchesIdiom + testEverySectionIsReachable (exercises all three sidebar paths) — pass
  • Cross-class batch across RuleCreation, RuleManagement, Settings, Usage, HardMode — 8/8 pass
  • 12 UI tests across every goToSection-using class, no regressions

Follow-up (not in this PR)

The ~23s launch "wait for idle" comes from the periodic TimelineView(.periodic(by: 30)) in Home/Rules never letting XCUITest detect quiescence — it slows the whole suite and is the underlying reason synthetic taps are racy here. Worth a separate look.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WReTVa1zD6CHKRY8zqS9Pb

`goToSection` drove the iPad sidebar (a `NavigationSplitView`
`List(selection:)` row) with a single fire-and-forget tap and no
verification. Synthesized taps against a selection-driven sidebar row
are occasionally dropped before the app has quiesced (a periodic
`TimelineView` keeps it non-idle at launch), so the row never becomes
selected, the detail column stays on the previous section, and the
following content assertion fails — e.g.
`testAppListsEditableWithoutHardSession` timing out on `ruleCard-Sleep`.
iPhone is unaffected because it taps a tab-bar button instead.

Confirm the navigation landed before returning: each section's detail
names its navigation bar after the same label as the tab/row
(`navigationTitle("Rules")` -> `navigationBars["Rules"]`), so tap, wait
for that bar, and re-tap if it didn't appear. The iPhone tab-bar path is
unchanged; the happy path returns as soon as the bar appears.

Validated on iPad Pro 11-inch (M5): the previously-flaky test, both
NavigationChrome tests (all three sidebar paths), and a cross-class
batch of UI tests all pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WReTVa1zD6CHKRY8zqS9Pb
@brendan-ch brendan-ch merged commit a0bd43b into main Jun 20, 2026
2 checks passed
@brendan-ch brendan-ch deleted the chore/fix-ipad-test-flake branch June 20, 2026 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant