Communitygithub.com

ComeOnOliver/skillshub

Use when setting up UI test recording in Xcode 26, enhancing recorded tests for stability, or configuring test plans for multi-configuration replay. Based on WWDC 2025-344 "Record, replay, and review".

What is skillshub?

skillshub is a Cursor agent skill that use when setting up UI test recording in Xcode 26, enhancing recorded tests for stability, or configuring test plans for multi-configuration replay. Based on WWDC 2025-344 "Record, replay, and review".

Works with~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/ComeOnOliver/skillshub/tree/HEAD/skills/CharlesWiltgen/Axiom/axiom-ui-recording

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Recording UI Automation (Xcode 26+)

Guide to Xcode 26's Recording UI Automation feature for creating UI tests through user interaction recording.

The Three-Phase Workflow

From WWDC 2025-344:

┌─────────────────────────────────────────────────────────────┐
│                   UI Automation Workflow                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. RECORD ──────► Interact with app in Simulator           │
│                    Xcode captures as Swift test code        │
│                                                             │
│  2. REPLAY ──────► Run across devices, languages, configs   │
│                    Using test plans for multi-config        │
│                                                             │
│  3. REVIEW ──────► Watch video recordings in test report    │
│                    Analyze failures with screenshots        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Phase 1: Recording

Starting a Recording

  1. Open your UI test file in Xcode
  2. Place cursor inside a test method
  3. Debug → Record UI Automation (or use the record button)
  4. App launches in Simulator
  5. Perform interactions - Xcode generates code
  6. Stop recording when done

What Gets Recorded

  • Taps on buttons, cells, controls
  • Text input into text fields
  • Swipes and scrolling
  • Gestures (pinch, rotate)
  • Hardware button presses (Home, volume)

Generated Code Example

// Xcode generates this from your interactions
func testLoginFlow() {
    let app = XCUIApplication()
    app.launch()

    // Recorded: Tap email field, type email
    app.textFields["Email"].tap()
    app.textFields["Email"].typeText("[email protected]")

    // Recorded: Tap password field, type password
    app.secureTextFields["Password"].tap()
    app.secureTextFields["Password"].typeText("password123")

    // Recorded: Tap login button
    app.buttons["Login"].tap()
}

Enhancing Recorded Code

Critical: Recorded code is often fragile. Always enhance it for stability.

1. Add Accessibility Identifiers

Recorded code uses labels which break with localization:

// RECORDED (fragile - breaks with localization)
app.buttons["Login"].tap()

// ENHANCED (stable - uses identifier)
app.buttons["loginButton"].tap()

Add identifiers in your app code:

// SwiftUI
Button("Login") { ... }
    .accessibilityIdentifier("loginButton")

// UIKit
loginButton.accessibilityIdentifier = "loginButton"

2. Add waitForExistence

Recorded code assumes elements exist immediately:

// RECORDED (may fail if app is slow)
app.buttons["Login"].tap()

// ENHANCED (waits for element)
let loginButton = app.buttons["loginButton"]
XCTAssertTrue(loginButton.waitForExistence(timeout: 5))
loginButton.tap()

3. Add Assertions

Recorded code just performs actions without verification:

// RECORDED (no verification)
app.buttons["Login"].tap()

// ENHANCED (with assertion)
app.buttons["loginButton"].tap()
let welcomeLabel = app.staticTexts["welcomeLabel"]
XCTAssertTrue(welcomeLabel.waitForExistence(timeout: 10),
              "Welcome screen should appear after login")

4. Use Shorter Queries

Recorded code may have overly specific queries:

// RECORDED (too specific)
app.tables.cells.element(boundBy: 0).buttons["Action"].tap()

// ENHANCED (simpler)
app.buttons["actionButton"].tap()

Query Selection Guidelines

From WWDC 2025-344:

ScenarioProblemSolution
Localized strings"Login" changes by languageUse accessibilityIdentifier
Deeply nested viewsLong query chains break easilyUse shortest possible query
Dynamic contentCell content changesUse identifier or generic query
Multiple matchesQuery returns many elementsAdd unique identifier

Best Practices

  1. Prefer identifiers over labels
  2. Use the shortest query that works
  3. Avoid index-based queries (element(boundBy: 0))
  4. Add identifiers to dynamic content

Phase 2: Replay with Test Plans

Test plans allow running the same tests across multiple configurations.

Creating a Test Plan

  1. File → New → File → Test Plan
  2. Add test targets
  3. Configure configurations

Test Plan Structure

{
  "configurations": [
    {
      "name": "iPhone - English",
      "options": {
        "targetForVariableExpansion": {
          "containerPath": "container:MyApp.xcodeproj",
          "identifier": "MyApp"
        },
        "language": "en",
        "region": "US"
      }
    },
    {
      "name": "iPhone - Spanish",
      "options": {
        "language": "es",
        "region": "ES"
      }
    },
    {
      "name": "iPhone - Dark Mode",
      "options": {
        "userInterfaceStyle": "dark"
      }
    },
    {
      "name": "iPad - Landscape",
      "options": {
        "defaultTestExecutionTimeAllowance": 120,
        "testTimeoutsEnabled": true
      }
    }
  ],
  "defaultOptions": {
    "targetForVariableExpansion": {
      "containerPath": "container:MyApp.xcodeproj",
      "identifier": "MyApp"
    }
  },
  "testTargets": [
    {
      "target": {
        "containerPath": "container:MyApp.xcodeproj",
        "identifier": "MyAppUITests",
        "name": "MyAppUITests"
      }
    }
  ],
  "version": 1
}

Configuration Options

OptionPurpose
languageTest localization
regionTest regional formatting
userInterfaceStyleTest dark/light mode
targetForVariableExpansionApp target for configuration
testTimeoutsEnabledEnable timeout enforcement
defaultTestExecutionTimeAllowanceTimeout in seconds

Running with Test Plan

# Command line
xcodebuild test \
  -scheme "MyApp" \
  -testPlan "MyTestPlan" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  -resultBundlePath /tmp/results.xcresult

# In Xcode
# Product → Test Plan → Select your plan
# Then Cmd+U to run tests

Phase 3: Review

Test Report Features

After tests complete:

  1. View test results in Report Navigator
  2. Watch video recordings of each test
  3. See screenshots at failure points
  4. Analyze timeline of actions

Enabling Attachments

In test plan or scheme:

"options": {
  "systemAttachmentLifetime": "keepAlways",
  "userAttachmentLifetime": "keepAlways"
}

Capturing Custom Screenshots

func testCheckout() {
    // ... actions ...

    // Manual screenshot at specific point
    let screenshot = app.screenshot()
    let attachment = XCTAttachment(screenshot: screenshot)
    attachment.name = "Checkout Confirmation"
    attachment.lifetime = .keepAlways
    add(attachment)
}

Common Patterns

Login Flow Template

func testLoginWithValidCredentials() throws {
    let app = XCUIApplication()
    app.launch()

    // Navigate to login
    let showLoginButton = app.buttons["showLoginButton"]
    XCTAssertTrue(showLoginButton.waitForExistence(timeout: 5))
    showLoginButton.tap()

    // Enter credentials
    let emailField = app.textFields["emailTextField"]
    XCTAssertTrue(emailField.waitForExistence(timeout: 5))
    emailField.tap()
    emailField.typeText("[email protected]")

    let passwordField = app.secureTextFields["passwordTextField"]
    passwordField.tap()
    passwordField.typeText("password123")

    // Submit
    app.buttons["loginButton"].tap()

    // Verify success
    let welcomeScreen = app.staticTexts["welcomeLabel"]
    XCTAssertTrue(welcomeScreen.waitForExistence(timeout: 10))
}

Navigation Flow Template

func testNavigateToSettings() throws {
    let app = XCUIApplication()
    app.launch()

    // Open tab bar item
    app.tabBars.buttons["Settings"].tap()

    // Verify navigation
    let settingsTitle = app.navigationBars["Settings"]
    XCTAssertTrue(settingsTitle.waitForExistence(timeout: 5))

    // Navigate deeper
    app.tables.cells["Account"].tap()
    XCTAssertTrue(app.navigationBars["Account"].exists)
}

Form Validation Template

func testFormValidation() throws {
    let app = XCUIApplication()
    app.launch()

    // Submit empty form
    app.buttons["submitButton"].tap()

    // Verify error appears
    let errorAlert = app.alerts["Error"]
    XCTAssertTrue(errorAlert.waitForExistence(timeout: 5))
    XCTAssertTrue(errorAlert.staticTexts["Please fill all fields"].exists)

    // Dismiss alert
    errorAlert.buttons["OK"].tap()
}

Troubleshooting

Recording Doesn't Start

  1. Ensure you're in a test method
  2. Check simulator is available
  3. Verify app builds and runs
  4. Try restarting Xcode

Recorded Code Doesn't Work

  1. Add waitForExistence before interactions
  2. Check accessibility identifiers are set
  3. Simplify queries to shortest form
  4. Run app manually to verify flow works

Tests Pass Locally, Fail in CI

  1. Increase timeouts for slower CI machines
  2. Add explicit waits for animations
  3. Check simulator configuration matches
  4. Disable animations in test setup:
    app.launchArguments = ["--disable-animations"]
    

Anti-Patterns

Don't Use Raw Recorded Code in CI

// BAD - Raw recorded code
app.buttons["Login"].tap()
app.textFields["Email"].typeText("[email protected]")

// GOOD - Enhanced for CI
let loginButton = app.buttons["loginButton"]
XCTAssertTrue(loginButton.waitForExistence(timeout: 10))
loginButton.tap()

Don't Hardcode Coordinates

// BAD - Coordinates from recording
app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()

// GOOD - Use element queries
app.buttons["centerButton"].tap()

Don't Skip Assertions

// BAD - Actions only
app.buttons["Login"].tap()
sleep(2)  // Hope it works

// GOOD - Verify outcomes
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome"].waitForExistence(timeout: 10))

Resources

WWDC: 2025-344, 2024-10206, 2019-413

Docs: /xcode/testing/recording-ui-tests, /xctest/xcuiapplication

Skills: axiom-xctest-automation, axiom-ui-testing

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

ComeOnOliver/skillshub

Create stunning, animation-rich HTML presentations from scratch or by converting PowerPoint files. Use when the user wants to build a presentation, convert a PPT/PPTX to web, or create slides for a talk/pitch. Helps non-designers discover their aesthetic through visual exploration rather than abstract choices.

ComeOnOliver/skillshub

Next.js 16+ 和 Turbopack — 增量打包、文件系统缓存、开发速度,以及何时使用 Turbopack 与 webpack。

ComeOnOliver/skillshub

SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.

ComeOnOliver/skillshub

Next.js 15 애플리케이션을 위한 프론트엔드 개발 가이드라인. React 19, TypeScript, Shadcn/ui, Tailwind CSS를 사용한 모던 패턴. Server Components, Client Components, App Router, 파일 구조, Shadcn/ui 컴포넌트, 성능 최적화, TypeScript 모범 사례 포함. 컴포넌트, 페이지, 기능 생성, 데이터 페칭, 스타일링, 라우팅, 프론트엔드 코드 작업 시 사용.

ComeOnOliver/skillshub

Provides Tamagui patterns for config v4, compiler optimization, styled context, and cross-platform styling. Must use when working with Tamagui projects (tamagui.config.ts, @tamagui imports).

ComeOnOliver/skillshub

Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.

ComeOnOliver/skillshub

Create high-converting, visually distinctive landing pages. Use when building marketing pages, product launches, SaaS homepages, or any single-page conversion-focused website. Guides section-by-section composition with anti-AI-slop principles.

ComeOnOliver/skillshub

Auto-loaded context for Portfolio Buddy 2 development. Use for ANY task involving: React 19 development, TypeScript, portfolio analysis features, metrics calculations, trading strategy comparison, or working with the Portfolio Buddy 2 codebase. Contains tech stack, known issues, and architectural constraints.

ComeOnOliver/skillshub

Next.js development tooling via MCP. Inspect routes, components, build info, and debug Next.js apps. Use when working on Next.js applications, debugging routing, or inspecting app structure. NOT for general React or non-Next.js projects.

ComeOnOliver/skillshub

Implement UI using Shadcn MCP (atoms/theme) and 21st.dev MCP (complex sections). Use when adding buttons, layouts, or generating landing pages.

ComeOnOliver/skillshub

A conceptual skill for building an API client in Next.js that handles JWT tokens

ComeOnOliver/skillshub

Best practices and patterns for Next.js App Router, Server Actions, and Routing in this project.

ComeOnOliver/skillshub

The Design System, Theme, and UX rules for the Physical AI Hub.

ComeOnOliver/skillshub

Comprehensive frontend development skill for building modern, performant web applications using ReactJS, NextJS, TypeScript, Tailwind CSS. Includes component scaffolding, performance optimization, bundle analysis, and UI best practices. Use when developing frontend features, optimizing performance, implementing UI/UX designs, managing state, or reviewing frontend code.

ComeOnOliver/skillshub

Build Next.js 16 applications with correct patterns and distinctive design. Use when creating pages, layouts, dynamic routes, upgrading from Next.js 15, or implementing proxy.ts. Covers breaking changes (async params/searchParams, Turbopack, cacheComponents) and frontend aesthetics. NOT when building non-React or backend-only applications.

ComeOnOliver/skillshub

Next.js 16+ uses App Router with Server Components by default. Client Components are only used when interactivity is needed (hooks, event handlers, browser APIs).

ComeOnOliver/skillshub

All TypeScript types are defined in `frontend/types/index.ts`. Types match backend API response structure and provide type safety across the frontend application.

ComeOnOliver/skillshub

Use when working with Next.js App Router tasks - creating pages in /app/, setting up dynamic routes ([id]/page.tsx), implementing nested layouts/templates (layout.tsx), optimizing Server/Client components, or building ERP role-based pages (admin/teacher/student dashboards). Auto-use for all /app/ directory operations, dynamic routing, and App Router-specific features.

ComeOnOliver/skillshub

Apple-inspired clean, minimal, premium UI design. Use when building modern interfaces requiring exceptional UX, clean aesthetics, or Apple-like polish. Triggers on: clean UI, modern design, Apple style, minimal, premium, user-friendly, UX.

ComeOnOliver/skillshub

Build interfaces that resonate, not just render. This skill enforces bold, intentional

Related Skills