Back to Skills

axiom-xctest-automation

verified

Use when writing, running, or debugging XCUITests. Covers element queries, waiting strategies, accessibility identifiers, test plans, and CI/CD test execution patterns.

View on GitHub

Marketplace

axiom-marketplace

CharlesWiltgen/Axiom

Plugin

axiom

Repository

CharlesWiltgen/Axiom
289stars

.claude-plugin/plugins/axiom/skills/axiom-xctest-automation/SKILL.md

Last Verified

January 16, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/CharlesWiltgen/Axiom/blob/main/.claude-plugin/plugins/axiom/skills/axiom-xctest-automation/SKILL.md -a claude-code --skill axiom-xctest-automation

Installation paths:

Claude
.claude/skills/axiom-xctest-automation/
Powered by add-skill CLI

Instructions

# XCUITest Automation Patterns

Comprehensive guide to writing reliable, maintainable UI tests with XCUITest.

## Core Principle

**Reliable UI tests require three things**:
1. Stable element identification (accessibilityIdentifier)
2. Condition-based waiting (never hardcoded sleep)
3. Clean test isolation (no shared state)

## Element Identification

### The Accessibility Identifier Pattern

**ALWAYS use accessibilityIdentifier for test-critical elements.**

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

TextField("Email", text: $email)
    .accessibilityIdentifier("emailTextField")

// UIKit
loginButton.accessibilityIdentifier = "loginButton"
emailTextField.accessibilityIdentifier = "emailTextField"
```

### Query Selection Guidelines

From WWDC 2025-344 "Recording UI Automation":

1. **Localized strings change** → Use accessibilityIdentifier instead
2. **Deeply nested views** → Use shortest possible query
3. **Dynamic content** → Use generic query or identifier

```swift
// BAD - Fragile queries
app.buttons["Login"]  // Breaks with localization
app.tables.cells.element(boundBy: 0).buttons.firstMatch  // Too specific

// GOOD - Stable queries
app.buttons["loginButton"]  // Uses identifier
app.tables.cells.containing(.staticText, identifier: "itemTitle").firstMatch
```

## Waiting Strategies

### Never Use sleep()

```swift
// BAD - Hardcoded wait
sleep(5)
XCTAssertTrue(app.buttons["submit"].exists)

// GOOD - Condition-based wait
let submitButton = app.buttons["submit"]
XCTAssertTrue(submitButton.waitForExistence(timeout: 5))
```

### Wait Patterns

```swift
// Wait for element to appear
func waitForElement(_ element: XCUIElement, timeout: TimeInterval = 10) -> Bool {
    element.waitForExistence(timeout: timeout)
}

// Wait for element to disappear
func waitForElementToDisappear(_ element: XCUIElement, timeout: TimeInterval = 10) -> Bool {
    let predicate = NSPredicate(format: "exists == false")
    let expectation = XC

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
9508 chars