Claude
Skills
Sign in
Back

xcuitest

Included with Lifetime
$97 forever

API reference: XCUITest. Query for element queries, waiting patterns, Swift 6 @MainActor, assertions, screenshots, launch arguments.

Backend & APIs

What this skill does


# XCUITest Reference

Comprehensive reference for writing reliable XCUITest UI tests in Swift 6.

## Quick Reference

```swift
// Basic test structure
@MainActor
final class MyUITests: XCTestCase {
    var app: XCUIApplication!

    override func setUp() {
        super.setUp()
        continueAfterFailure = false
        app = XCUIApplication()
        app.launch()
    }

    func testExample() {
        let button = app.buttons["Submit"]
        XCTAssertTrue(button.waitForExistence(timeout: 5))
        button.tap()
    }
}
```

## Core API Classes

### XCUIApplication
Proxy for launching, monitoring, and terminating the app under test.

```swift
let app = XCUIApplication()

// Launch configuration
app.launchArguments = ["-UITest", "-DisableAnimations"]
app.launchEnvironment["API_URL"] = "https://test.example.com"

// Lifecycle
app.launch()      // Start the app
app.terminate()   // Stop the app
app.activate()    // Bring to foreground

// State checking
app.state == .runningForeground
app.state == .runningBackground
app.state == .notRunning
```

### XCUIElement
Represents a single UI element. Supports interactions and property queries.

```swift
let element = app.buttons["Submit"]

// Properties
element.exists           // Bool - element is in hierarchy
element.isHittable       // Bool - element can receive taps
element.isEnabled        // Bool - element is enabled
element.isSelected       // Bool - element is selected
element.label            // String - accessibility label
element.value            // Any? - current value
element.identifier       // String - accessibility identifier
element.frame            // CGRect - frame in screen coordinates
element.elementType      // XCUIElement.ElementType
```

### XCUIElementQuery
Defines search criteria for finding UI elements.

```swift
// Type-based queries (convenience)
app.buttons              // All buttons
app.staticTexts          // All text labels
app.textFields           // All text inputs
app.secureTextFields     // Password fields
app.switches             // Toggle switches
app.sliders              // Slider controls
app.tables               // Table views
app.cells                // Table/collection cells
app.scrollViews          // Scroll views
app.images               // Image views
app.alerts               // Alert dialogs
app.sheets               // Action sheets
app.navigationBars       // Navigation bars
app.tabBars              // Tab bars
app.toolbars             // Toolbars

// Querying by identifier (subscript)
app.buttons["Submit"]
app.staticTexts["Welcome"]

// Descendants query (any element type)
app.descendants(matching: .any)
app.descendants(matching: .button)
app.descendants(matching: .staticText)

// Chained queries
app.descendants(matching: .any).matching(identifier: "my-id").firstMatch

// Predicate queries
app.buttons.matching(NSPredicate(format: "label CONTAINS[c] 'Save'"))
app.buttons.matching(NSPredicate(format: "identifier == 'submit-btn'"))
app.staticTexts.matching(NSPredicate(format: "label BEGINSWITH 'Error'"))

// Query results
query.count              // Number of matches
query.element            // Single element (fails if not exactly 1)
query.firstMatch         // First matching element
query.element(boundBy: 0) // Element at index
query.allElementsBoundByIndex  // Array of all elements
```

### XCUICoordinate
Represents a screen location for coordinate-based interactions.

```swift
// Normalized offset (0,0 = top-left, 1,1 = bottom-right)
let center = element.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5))
let topLeft = element.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))

// Absolute offset from normalized point
let point = app.coordinate(withNormalizedOffset: .zero)
    .withOffset(CGVector(dx: 100, dy: 200))

// Screen coordinates
let screenCenter = app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5))
```

## Element Interactions

### Tap Actions
```swift
element.tap()                    // Single tap
element.doubleTap()              // Double tap
element.twoFingerTap()           // Two finger tap (iOS only)
element.tap(withNumberOfTaps: 3, numberOfTouches: 1) // Triple tap
```

### Press Actions
```swift
element.press(forDuration: 1.0)  // Long press
element.press(forDuration: 0.5, thenDragTo: otherElement) // Press and drag
```

### Text Input
```swift
textField.tap()                  // Focus first
textField.typeText("Hello")      // Type text
textField.clearAndEnterText("New text") // Custom helper needed

// Clear text field
textField.tap()
textField.press(forDuration: 1.0)
app.menuItems["Select All"].tap()
textField.typeText("")           // Or use delete key
```

### Swipe Gestures
```swift
element.swipeUp()
element.swipeDown()
element.swipeLeft()
element.swipeRight()

// With velocity (iOS 16+)
element.swipeUp(velocity: .fast)
element.swipeUp(velocity: .slow)
```

### Coordinate-Based Gestures
```swift
// Pull to refresh
let start = cell.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0))
let end = cell.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 6))
start.press(forDuration: 0, thenDragTo: end)

// Custom swipe
let from = app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.8))
let to = app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.2))
from.press(forDuration: 0.1, thenDragTo: to)

// Tap at specific point
let point = app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5))
point.tap()
```

### Other Gestures
```swift
element.pinch(withScale: 0.5, velocity: -1)  // Pinch in
element.pinch(withScale: 2.0, velocity: 1)   // Pinch out
element.rotate(0.5, withVelocity: 1)         // Rotate

// Sliders
slider.adjust(toNormalizedSliderPosition: 0.7)

// Pickers
picker.adjust(toPickerWheelValue: "Option 3")
```

## Waiting Mechanisms

### waitForExistence (Simplest)
```swift
// Returns Bool - does not fail test automatically
let exists = element.waitForExistence(timeout: 5)
XCTAssertTrue(exists, "Element did not appear")

// Common pattern
if button.waitForExistence(timeout: 3) {
    button.tap()
}
```

### XCTWaiter (More Control)
```swift
// Wait with result handling
let predicate = NSPredicate(format: "exists == true")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
let result = XCTWaiter().wait(for: [expectation], timeout: 5)

switch result {
case .completed:
    // Element found
case .timedOut:
    XCTFail("Element did not appear within timeout")
case .incorrectOrder:
    // Multiple expectations fulfilled out of order
case .invertedFulfillment:
    // Inverted expectation was fulfilled (unexpected)
case .interrupted:
    // Wait was interrupted
@unknown default:
    break
}
```

### Wait for Non-Existence (Xcode 16+)
```swift
// Native API (Xcode 16+) - preferred
let loadingIndicator = app.activityIndicators["loading"]
XCTAssertTrue(loadingIndicator.waitForNonExistence(withTimeout: 10), "Loading should complete")

// Legacy approach (pre-Xcode 16)
func waitForNonExistence(_ element: XCUIElement, timeout: TimeInterval) -> Bool {
    let predicate = NSPredicate(format: "exists == false")
    let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
    let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
    return result == .completed
}
```

### Wait for Property Change
```swift
// Wait for element to become enabled
let predicate = NSPredicate(format: "isEnabled == true")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: button)
XCTWaiter().wait(for: [expectation], timeout: 5)

// Wait for label to change
let predicate = NSPredicate(format: "label == 'Done'")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: statusLabel)
XCTWaiter().wait(for: [expectation], timeout: 10)
```

### Multiple Expectations
```swift
let exp1 = XCTNSPredicateExpectation(predicate: pred1, object: element1)
let exp2 = XCTNSPredicateExpectation(predicate: pred2, object: el
Files: 10
Size: 187.5 KB
Complexity: 49/100
Category: Backend & APIs

Related in Backend & APIs