Skip to content

feat(playground): Add UI automation regression fixtures#53

Merged
cameroncooke merged 2 commits into
mainfrom
cam/feat/playground-ui-fixtures
May 17, 2026
Merged

feat(playground): Add UI automation regression fixtures#53
cameroncooke merged 2 commits into
mainfrom
cam/feat/playground-ui-fixtures

Conversation

@cameroncooke

@cameroncooke cameroncooke commented May 13, 2026

Copy link
Copy Markdown
Owner

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, and AXE_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 same contextMenu actions) and rewrites the long-scroll fixture from a SwiftUI List to a UITableView UIViewRepresentable so snapshots expose a concrete scroll container (long-scroll-test-scroll-view) while keeping rows individually tappable.

Introduces PresentationFixtureTests E2E coverage to validate describe-ui exposure and to exercise tapping/long-pressing through each new fixture path, and documents the addition in CHANGELOG.md under [Unreleased].

Reviewed by Cursor Bugbot for commit 451e908. Bugbot is set up for automated code reviews on this repo. Configure here.

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>
@cameroncooke cameroncooke marked this pull request as ready for review May 13, 2026 13:19
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This 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)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding UI automation regression fixtures to the AxePlayground, which aligns with the substantial updates to AccessibilityFixturesView and CHANGELOG.
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.
Description check ✅ Passed The PR description clearly describes the changeset, detailing new AxePlayground fixtures for UI automation testing, including alerts, sheets, context menus, modal navigation, and a long-scroll list.

✏️ 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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swift (1)

323-327: 💤 Low value

Avoid unconditional reloadData() on every SwiftUI update.

updateUIView is invoked whenever any observed state in the parent changes — including each time selectedRow.wrappedValue is set from didSelectRowAt. Since rows is a constant Array(1...80) in LongScrollTestView, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 453922c and 635380d.

📒 Files selected for processing (2)
  • AxePlaygroundApp/AxePlayground/Views/AccessibilityFixturesView.swift
  • CHANGELOG.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>
@cameroncooke cameroncooke merged commit ab3e753 into main May 17, 2026
5 checks passed
@cameroncooke cameroncooke deleted the cam/feat/playground-ui-fixtures branch May 17, 2026 17:11
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