feat(playground): Add UI automation regression fixtures#53
Conversation
Add alert, sheet, context menu, modal navigation, and long-scroll fixtures to AXe Playground so XcodeBuildMCP can validate runtime UI automation against stable regression screens. Use a UIKit-backed long-scroll table so compact snapshots expose a real scroll target while retaining tappable rows. Co-Authored-By: OpenAI Codex <noreply@openai.com>
WalkthroughThis pull request extends AxePlayground's accessibility testing fixtures with UIKit support for improved UI automation regression coverage. The context menu fixture was updated to use an interactive Button instead of a static Text view, enabling state updates and context menu actions. The long-scroll fixture was substantially reworked, migrating from a SwiftUI List-based implementation to a UIViewRepresentable wrapping UIKit's UITableView with a coordinator managing row selection state. The changelog was updated to document these newly added fixtures. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swift (1)
323-327: 💤 Low valueAvoid unconditional
reloadData()on every SwiftUI update.
updateUIViewis invoked whenever any observed state in the parent changes — including each timeselectedRow.wrappedValueis set fromdidSelectRowAt. Sincerowsis a constantArray(1...80)inLongScrollTestView, the full table reload on every row tap is wasteful and forces visible cells to be re-dequeued and re-configured. For a fixture used by UI automation, the extra cell churn can also produce transient accessibility snapshots that include momentarily reconfigured cells.Consider guarding the reload on actual row changes (and reassigning the binding is also redundant since
Binding<String>already references the same underlying state):♻️ Proposed refactor
func updateUIView(_ tableView: UITableView, context: Context) { - context.coordinator.rows = rows - context.coordinator.selectedRow = $selectedRow - tableView.reloadData() + context.coordinator.selectedRow = $selectedRow + if context.coordinator.rows != rows { + context.coordinator.rows = rows + tableView.reloadData() + } }🤖 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 `@AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swift` around lines 323 - 327, The updateUIView currently unconditionally assigns context.coordinator.rows and context.coordinator.selectedRow and calls tableView.reloadData() on every SwiftUI update; change it to only update the coordinator and call reloadData() when the underlying data or selected row actually changed (compare rows and selectedRow.wrappedValue to coordinator state before assigning), and remove the unnecessary reassignment of the Binding (do not set context.coordinator.selectedRow = $selectedRow if the coordinator already holds a reference), so interactions from LongScrollTestView / didSelectRowAt only trigger reloads when needed.
🤖 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.
Nitpick comments:
In `@AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swift`:
- Around line 323-327: The updateUIView currently unconditionally assigns
context.coordinator.rows and context.coordinator.selectedRow and calls
tableView.reloadData() on every SwiftUI update; change it to only update the
coordinator and call reloadData() when the underlying data or selected row
actually changed (compare rows and selectedRow.wrappedValue to coordinator state
before assigning), and remove the unnecessary reassignment of the Binding (do
not set context.coordinator.selectedRow = $selectedRow if the coordinator
already holds a reference), so interactions from LongScrollTestView /
didSelectRowAt only trigger reloads when needed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 235408e2-fe8e-40ea-b621-d809d6758bdf
📒 Files selected for processing (2)
AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swiftCHANGELOG.md
Add E2E coverage for the alert, sheet, context menu, modal, and long-scroll Playground routes so the regression app validates the fixtures it exposes. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Adds AXe Playground fixtures for UI automation coverage that was missing from the regression app: alerts, sheets, context menus, modal navigation, and a long scrolling list.
The long-scroll fixture uses a small UIKit table wrapper so accessibility snapshots expose a real scroll target while keeping rows tappable. This gives XcodeBuildMCP a stable fixture for future UI automation regression testing without relying only on system apps.
Adds simulator-backed PresentationFixtureTests coverage for the new routes, validating that describe-ui can discover each fixture and that AXe can drive the alert, sheet, context menu, modal navigation, and long-scroll interactions end to end.
The branch was validated locally with
swift build,swift test, andAXE_E2E=1 SIMULATOR_UDID=A2C64636-37E9-4B68-B872-E7F0A82A5670 swift test --filter PresentationFixtureTests. The default suite now reports 169 tests across 25 suites, with the new presentation fixture suite skipped unless E2E testing is enabled.Note
Low Risk
Low risk: changes are limited to the AxePlayground regression app fixtures, changelog, and new E2E tests; no core automation or production logic is modified.
Overview
Adds new AxePlayground presentation/interaction fixtures (alert, sheet, context menu, modal navigation, and long-scroll) to improve deterministic UI automation coverage, including stable accessibility identifiers/values for state assertions.
Updates the context-menu target to be a real
Button(still exposing the samecontextMenuactions) and rewrites the long-scroll fixture from a SwiftUIListto aUITableViewUIViewRepresentableso snapshots expose a concrete scroll container (long-scroll-test-scroll-view) while keeping rows individually tappable.Introduces
PresentationFixtureTestsE2E coverage to validatedescribe-uiexposure and to exercise tapping/long-pressing through each new fixture path, and documents the addition inCHANGELOG.mdunder[Unreleased].Reviewed by Cursor Bugbot for commit 451e908. Bugbot is set up for automated code reviews on this repo. Configure here.