ui-scan

SKILL.md

UI Scan

Quick Ref: UI test environment setup: splash/onboarding bypass, accessibility identifier scan, element finding strategies.

YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.

Required output: Every finding MUST include Urgency, Risk, ROI, and Blast Radius ratings using the Issue Rating Table format. Do not omit these ratings.


Pre-flight: Git Safety Check

git status --short

If uncommitted changes exist:

AskUserQuestion with questions:
[
  {
    "question": "You have uncommitted changes. Commit before proceeding?",
    "header": "Git",
    "options": [
      {"label": "Commit first (Recommended)", "description": "Save current work so you can revert if this skill modifies files"},
      {"label": "Continue without committing", "description": "Proceed — I accept the risk"}
    ],
    "multiSelect": false
  }
]

If "Commit first": Ask for a commit message, stage changed files, and commit. Then proceed.


Step 1: Determine Scan Focus

AskUserQuestion with questions:
[
  {
    "question": "What would you like to scan for?",
    "header": "Focus",
    "options": [
      {"label": "Full scan (Recommended)", "description": "Accessibility identifiers + test environment setup + recommendations"},
      {"label": "Accessibility only", "description": "Scan for missing accessibility identifiers and labels"},
      {"label": "Test setup only", "description": "Check for onboarding/splash bypass support"}
    ],
    "multiSelect": false
  }
]

Step 2: Scan for Missing Accessibility Identifiers

# Find buttons without accessibility identifiers
Grep pattern="Button\(" glob="**/*.swift" output_mode="files_with_matches"

# Find images without accessibility descriptions
Grep pattern="Image\(" glob="**/*.swift" output_mode="files_with_matches"

# Count existing accessibility label usage
Grep pattern="\.accessibilityLabel" glob="**/*.swift" output_mode="count"

# Count existing accessibility identifier usage
Grep pattern="\.accessibilityIdentifier" glob="**/*.swift" output_mode="count"

# Find hardcoded font sizes (Dynamic Type gap)
Grep pattern="\.font\(\.system\(size:" glob="**/*.swift" output_mode="content"

For each file with missing identifiers, read it to verify the finding and check surrounding context.

Identifier Naming Patterns

Element Type Pattern Example
Tab bar items tab-{name} tab-home, tab-items
Toolbar actions action-{name} action-add, action-sync
Form fields field-{name} field-title, field-email
Cards/Options {context}-{name} chooser-photo, chooser-manual
Navigation nav-{destination} nav-settings, nav-back

Step 3: Check Test Environment Setup

Scan for UI test bypass support:

# Check for UI testing launch argument handling
Grep pattern="uitesting|isUITesting|UI_TESTING" glob="**/*.swift" output_mode="content"

# Check for splash skip support
Grep pattern="skip-splash|skipSplash" glob="**/*.swift" output_mode="content"

# Check for onboarding bypass
Grep pattern="skipOnboarding|skip.*onboarding" glob="**/*.swift" output_mode="content" -i

# Find existing UI test files
Glob pattern="**/*UITests*.swift"
Glob pattern="**/*UITest*.swift"

Required App-Side Support

If not already present, the app needs:

// Detect UI testing mode
private var isUITesting: Bool {
    ProcessInfo.processInfo.arguments.contains("--uitesting")
}

Required Test-Side Setup

override func setUpWithError() throws {
    try super.setUpWithError()
    continueAfterFailure = false
    app = XCUIApplication()
    app.launchArguments = ["--uitesting", "-skip-splash"]
    app.launch()
}

Step 4: Element Finding Strategies

Check which element finding strategies the existing tests use:

# Check for identifier-based finding
Grep pattern="\.matching\(identifier:" glob="**/*UITest*.swift" output_mode="count"

# Check for label-based finding
Grep pattern="app\.(buttons|staticTexts|textFields)\[" glob="**/*UITest*.swift" output_mode="count"

# Check for predicate-based finding
Grep pattern="NSPredicate" glob="**/*UITest*.swift" output_mode="count"

Recommended Strategy Priority

  1. Accessibility identifier — most stable across localizations
  2. Label text — works for static labels but breaks with i18n
  3. Predicate — partial match, use as fallback

Step 5: Generate Report

Display the summary table and all findings inline, then write to .agents/research/YYYY-MM-DD-ui-scan.md:

# UI Scan Report

**Date:** YYYY-MM-DD

## Accessibility Identifier Coverage

| Metric | Count |
|--------|-------|
| Files with Buttons | N |
| Files with .accessibilityIdentifier | N |
| Files with .accessibilityLabel | N |
| Coverage estimate | X% |

## Issue Rating Table

All findings rated and sorted by Urgency then ROI:

| # | Finding | Urgency | Risk: Fix | Risk: No Fix | ROI | Blast Radius | Fix Effort |
|---|---------|---------|-----------|-------------|-----|-------------|------------|
| 1 | LoginView.swift — Button missing .accessibilityIdentifier | 🟡 High | ⚪ Low | 🟡 High | 🟠 Excellent | ⚪ 1 file | Trivial |
| 2 | ItemCard.swift — Image missing .accessibilityLabel | 🟢 Medium | ⚪ Low | 🟢 Medium | 🟢 Good | ⚪ 1 file | Trivial |

Use the Issue Rating scale:
- **Urgency:** 🔴 CRITICAL (interactive element untestable, blocks automation) · 🟡 HIGH (key flow element missing identifier) · 🟢 MEDIUM (secondary element missing identifier) · ⚪ LOW (decorative element)
- **Risk: Fix:** Risk of adding identifiers (⚪ Low — additive change, no behavioral impact)
- **Risk: No Fix:** Consequence for UI test coverage and accessibility
- **ROI:** 🟠 Excellent · 🟢 Good · 🟡 Marginal · 🔴 Poor
- **Blast Radius:** How many test files / flows are affected by the missing identifier
- **Fix Effort:** Trivial / Small / Medium / Large

## Missing Identifiers (Detail)

| File | Element Type | Recommendation |
|------|-------------|----------------|
| [path] | Button | Add .accessibilityIdentifier("action-name") |
| [path] | Image | Add .accessibilityLabel("description") |

## Test Environment Status

| Check | Status |
|-------|--------|
| `--uitesting` argument handled | Yes/No |
| Splash bypass | Yes/No |
| Onboarding bypass | Yes/No |
| Tutorial bypass | Yes/No |

## Recommendations

1. [Priority recommendation]
2. [Next recommendation]

Step 6: Follow-up

AskUserQuestion with questions:
[
  {
    "question": "How would you like to proceed?",
    "header": "Next",
    "options": [
      {"label": "Add missing identifiers", "description": "Walk through each gap and add identifiers"},
      {"label": "Set up test environment", "description": "Add uitesting bypass to the app"},
      {"label": "Report is sufficient", "description": "I'll handle changes manually"}
    ],
    "multiSelect": false
  }
]

Troubleshooting

Problem Solution
No UI test files found Create a UI test target in Xcode first
Too many missing identifiers Prioritize interactive elements (buttons, fields, nav) first
Onboarding always appears in tests Add --uitesting argument check to onboarding gate
Elements not findable by tests Use .accessibilityIdentifier() instead of label-based finding
Weekly Installs
2
GitHub Stars
36
First Seen
10 days ago
Installed on
opencode2
github-copilot2
claude-code2
windsurf1
amp1
cline1