Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import Foundation
import SwiftUI

struct SliderValueTestView: View {
@State private var sliderValue = 0.25
@State private var state = "Initial"

private var percentText: String {
String(format: "%.2f", locale: Locale(identifier: "en_US_POSIX"), sliderValue * 100.0)
}

private var exactValueText: String {
String(format: "%.4f", locale: Locale(identifier: "en_US_POSIX"), sliderValue)
}

var body: some View {
VStack(spacing: 24) {
Text("Slider Value State: \(state)")
Expand All @@ -20,6 +29,14 @@ struct SliderValueTestView: View {
.accessibilityIdentifier("slider-position-value")
.accessibilityValue(sliderValue.formatted(.number.precision(.fractionLength(2))))

Text("Slider Percent State: \(percentText)")
.accessibilityIdentifier("slider-percent-state")
.accessibilityValue(percentText)

Text("Slider Exact Value: \(exactValueText)")
.accessibilityIdentifier("slider-exact-value-state")
.accessibilityValue(exactValueText)

Slider(value: $sliderValue, in: 0...1)
.accessibilityIdentifier("slider-value-slider")
.accessibilityLabel("Slider Value Slider")
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added `axe slider --id/--label --value 0...100` for selector-based slider setting with orientation-aware HID dragging and AXValue tolerance verification/failure reporting.
- Added `axe drag --start-x/--start-y --end-x/--end-y` for raw point-to-point low-level HID drag validation using explicit touch move events.

### Changed

- Changed `axe slider` to use the shared composite low-level HID drag path with AXValue tolerance verification instead of retrying with correction gestures.

### Fixed

- Fixed `describe-ui` and selector-based `tap --label` exposing and activating real SwiftUI `TabView` tab items, navigation search fields, toolbar segmented picker items, and generated navigation back buttons from the CoreSimulator accessibility bridge. Also fixed selector decoding when the accessibility tree contains numeric `AXValue` fields such as sliders.
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ AXe is a comprehensive CLI tool for interacting with iOS Simulators using Apple'
- [Install AXe Skill](#install-axe-skill)
- [Commands Overview](#commands-overview)
- [**Touch \& Gestures**](#touch--gestures-1)
- [**Sliders**](#sliders)
- [**Gesture Presets**](#gesture-presets)
- [**Text Input**](#text-input)
- [**Hardware Buttons**](#hardware-buttons-1)
Expand All @@ -45,7 +46,9 @@ AXe provides complete iOS Simulator automation capabilities:
### Touch & Gestures
- **Tap**: Precise touch events at specific coordinates with timing controls
- **Swipe**: Multi-touch gestures with configurable duration and delta
- **Drag**: Raw point-to-point low-level HID drags with explicit touch move events
- **Touch Control**: Low-level touch down/up events for advanced gesture control
- **Sliders**: Set slider controls to a verified 0-100 percentage tolerance by accessibility identifier or label
- **Gesture Presets**: Common gesture patterns (scroll-up, scroll-down, scroll-left, scroll-right, edge swipes)
- **Batch Chaining**: Execute ordered multi-step interaction workflows in one invocation

Expand Down Expand Up @@ -144,8 +147,10 @@ axe tap --id "Safari" --udid $UDID
axe tap --label "Safari" --udid $UDID
axe tap --label "Weather Alerts" --udid $UDID # Auto-uses physical touch for matched switches/toggles
axe tap -x 320 -y 780 --tap-style physical --udid $UDID # Force physical touch for coordinate taps
axe slider --id "volume-slider" --value 75 --udid $UDID
axe type 'Hello World!' --udid $UDID
axe swipe --start-x 100 --start-y 300 --end-x 300 --end-y 100 --udid $UDID
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --udid $UDID
axe button home --udid $UDID

# Screenshot
Expand Down Expand Up @@ -199,11 +204,16 @@ axe tap -x 320 -y 780 --tap-style physical --udid SIMULATOR_UDID # Force touch
axe swipe --start-x 100 --start-y 300 --end-x 300 --end-y 100 --udid SIMULATOR_UDID
axe swipe --start-x 50 --start-y 500 --end-x 350 --end-y 500 --duration 2.0 --delta 25 --udid SIMULATOR_UDID

# Raw low-level drag using explicit touch move events
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --udid SIMULATOR_UDID
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --duration 0.4 --steps 40 --udid SIMULATOR_UDID

# Orientation-aware coordinates
# AXe automatically maps logical UI coordinates for rotated landscape and letterboxed landscape-only apps.
# Use the coordinates from describe-ui directly; AXe detects the simulator orientation.
axe tap -x 100 -y 200 --udid SIMULATOR_UDID
axe swipe --start-x 100 --start-y 300 --end-x 300 --end-y 100 --udid SIMULATOR_UDID
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --udid SIMULATOR_UDID

# Advanced touch control
axe touch -x 150 -y 250 --down --udid SIMULATOR_UDID
Expand All @@ -213,6 +223,18 @@ axe touch -x 150 -y 250 --down --up --udid SIMULATOR_UDID
axe touch -x 150 -y 250 --down --up --delay 1.0 --udid SIMULATOR_UDID
```

### **Sliders**

```bash
# Set a slider by accessibility identifier to a verified 0-100 percentage
axe slider --id slider-value-slider --value 75 --udid SIMULATOR_UDID

# Set a slider by label and narrow matching to slider elements
axe slider --label "Volume" --value 40 --element-type Slider --udid SIMULATOR_UDID
```

`slider` resolves the real accessibility slider element, performs one calibrated low-level HID drag from its current AXValue-derived position toward the requested percentage using the same composite touch-move path as `drag`, and re-reads AXValue to verify the result. Since iOS slider controls quantize values to their rendered track resolution, AXe verifies that the observed value is within tolerance rather than retrying correction gestures to chase unreachable decimals. If the observed AXValue remains outside tolerance after that drag, the command fails clearly.

### **Gesture Presets**

```bash
Expand Down Expand Up @@ -367,6 +389,9 @@ axe screenshot --output ~/Desktop/ --udid SIMULATOR_UDID
axe describe-ui --udid SIMULATOR_UDID # Full screen
axe describe-ui --point 100,200 --udid SIMULATOR_UDID # Specific point

# Set slider controls discovered via describe-ui
axe slider --id slider-value-slider --value 75 --udid SIMULATOR_UDID

# List simulators
axe list-simulators
```
Expand Down
21 changes: 13 additions & 8 deletions Skills/CLI/axe/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
---
name: axe
description: Provides agent-ready AXe CLI usage guidance for iOS Simulator automation. Use when asked to "use AXe", "automate a simulator", "tap/swipe/type on simulator", "describe UI", "take a screenshot", "record video", "batch steps", or "interact with an iOS app". Covers all commands including touch, gestures, text input, keyboard, buttons, accessibility, screenshots, video, and batch workflows.
description: Provides agent-ready AXe CLI usage guidance for iOS Simulator automation. Use when asked to "use AXe", "automate a simulator", "tap/swipe/type on simulator", "set a slider", "describe UI", "take a screenshot", "record video", "batch steps", or "interact with an iOS app". Covers all commands including touch, gestures, sliders, text input, keyboard, buttons, accessibility, screenshots, video, and batch workflows.
---

## Step 1: Confirm runtime context
1. Identify simulator UDID target first (`axe list-simulators`).
2. Simulator-interaction AXe commands require `--udid <UDID>`. Commands like `list-simulators` and `init` do not.
3. Run `axe describe-ui --udid <UDID>` to inspect the full current screen. Use `axe describe-ui --point <X,Y> --udid <UDID>` to inspect the element at a specific coordinate. Use the output to discover available `--id` and `--label` values for selector taps, and to confirm coordinates for coordinate-based taps.
4. Prefer selector taps (`tap --id` / `tap --label`) over raw coordinates. Selectors are resilient to layout changes, work across device sizes, and support element waiting (`--wait-timeout`) in batch flows. For UIKit `UISwitch` and SwiftUI `Toggle` rows, selector taps activate the contained switch/toggle when the match contains exactly one such control. Default tap style is `automatic`: switches/toggles use physical touch down/up, while normal taps use simulator `tapAt`.
3. Run `axe describe-ui --udid <UDID>` to inspect the full current screen. Use `axe describe-ui --point <X,Y> --udid <UDID>` to inspect the element at a specific coordinate. Use the output to discover available `--id` and `--label` values for selector taps and slider setting, and to confirm coordinates for coordinate-based taps.
4. Prefer selectors (`tap --id` / `tap --label`, `slider --id` / `slider --label`) over raw coordinates. Selectors are resilient to layout changes, work across device sizes, and support element waiting where documented. For UIKit `UISwitch` and SwiftUI `Toggle` rows, selector taps activate the contained switch/toggle when the match contains exactly one such control. Default tap style is `automatic`: switches/toggles use physical touch down/up, while normal taps use simulator `tapAt`.

## Step 2: Choose the right command

Available commands: `init`, `tap`, `swipe`, `gesture`, `touch`, `type`, `button`, `key`, `key-sequence`, `key-combo`, `batch`, `describe-ui`, `screenshot`, `record-video`, `stream-video`, `list-simulators`. Run `axe --help` or `axe <command> --help` for full options.
Available commands: `init`, `tap`, `slider`, `swipe`, `drag`, `gesture`, `touch`, `type`, `button`, `key`, `key-sequence`, `key-combo`, `batch`, `describe-ui`, `screenshot`, `record-video`, `stream-video`, `list-simulators`. Run `axe --help` or `axe <command> --help` for full options.

Common examples:
```bash
axe tap --id <identifier> --udid <UDID>
axe tap --label <text> --udid <UDID>
axe tap --label 'Weather Alerts' --udid <UDID>
axe slider --id <identifier> --value 75 --udid <UDID>
axe slider --label <text> --value 40 --element-type Slider --udid <UDID>
axe drag --start-x <X1> --start-y <Y1> --end-x <X2> --end-y <Y2> --udid <UDID>
axe tap -x <X> -y <Y> --tap-style physical --udid <UDID>
axe tap -x <X> -y <Y> --udid <UDID>
axe type 'text' --udid <UDID>
Expand All @@ -28,14 +31,15 @@ axe screenshot --udid <UDID> --output screenshot.png

## Step 3: Understand the execution model

HID commands (`tap`, `swipe`, `type`, `key`, etc.) are fire-and-forget — AXe confirms the event was dispatched to the simulator but cannot verify the app actually processed it. A tap may land before a view is interactive, or during a transition. This means:
- Always verify outcomes separately with `describe-ui` or `screenshot`.
- Use `--wait-timeout` in batch to wait for elements to appear, and `sleep` steps or `--pre-delay` / `--post-delay` to allow animations to settle.
Most HID commands (`tap`, `swipe`, `drag`, `type`, `key`, etc.) are fire-and-forget — AXe confirms the event was dispatched to the simulator but cannot verify the app actually processed it. A tap may land before a view is interactive, or during a transition. `slider` is the exception: it performs one selector-resolved low-level HID drag, re-reads the matched slider AXValue, and fails if the observed 0-100 value is outside tolerance. iOS slider controls quantize values to their rendered track resolution, so AXe does not retry correction gestures to chase unreachable decimals. This means:
- Always verify outcomes separately with `describe-ui` or `screenshot` when app behavior matters beyond the direct command result.
- Use `--wait-timeout` in batch to wait for tap elements to appear, and `sleep` steps or `--pre-delay` / `--post-delay` to allow animations to settle.

## Step 4: Apply timing and input best practices
- Use `--pre-delay` / `--post-delay` on tap, swipe, and gesture commands for fixed delays around actions.
- Use `--duration` to control how long a swipe, gesture, button press, or key press lasts.
- Coordinate-based `tap`, `swipe`, and `touch` accept coordinates from `describe-ui` directly; AXe detects rotated landscape simulator orientation and letterboxed landscape-only app layouts automatically.
- Coordinate-based `tap`, `swipe`, `drag`, and `touch` accept coordinates from `describe-ui` directly; AXe detects rotated landscape simulator orientation and letterboxed landscape-only app layouts automatically.
- Use `axe slider --id <identifier> --value <0-100>` for sliders instead of approximating with raw swipe coordinates; it uses one calibrated low-level HID drag from the resolved slider frame/current AXValue, through the same composite touch-move path as `drag`, verifies the result within tolerance, and fails clearly if the observed AXValue remains outside tolerance.
- For text with shell-sensitive characters, prefer `--stdin` or `--file` over inline quotes.
- Use single quotes for inline text arguments to avoid shell expansion issues.

Expand All @@ -48,6 +52,7 @@ HID commands (`tap`, `swipe`, `type`, `key`, etc.) are fire-and-forget — AXe c

**Fall back to discrete commands** when:
- A step's parameters depend on runtime inspection of a previous step's result (e.g. parsing `describe-ui` JSON to choose coordinates dynamically).
- Using `slider`; batch steps do not support slider verification.

**Handling animations and transitions in batch:**
- Use `--wait-timeout <seconds>` so selector taps (`--id` / `--label`) poll the accessibility tree until the element appears or the timeout expires. This is the primary mechanism for multi-screen flows.
Expand Down
29 changes: 25 additions & 4 deletions Skills/CLI/axe/references/cli-quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ axe tap -x 320 -y 780 --tap-style physical --udid <UDID>
axe tap -x 100 -y 200 --pre-delay 1.0 --post-delay 0.5 --udid <UDID>
```

## Slider

```bash
# Value is a percentage from 0 to 100
axe slider --id "volume-slider" --value 75 --udid <UDID>
axe slider --label "Volume" --value 40 --element-type Slider --udid <UDID>
```

`slider` resolves the matched accessibility slider, uses its frame/current AXValue for one calibrated low-level HID drag through the same composite touch-move path as `drag`, and re-reads AXValue. Since iOS slider controls quantize values to their rendered track resolution, AXe verifies that the observed value is within tolerance rather than retrying correction gestures to chase unreachable decimals. If the observed value remains outside tolerance, the command fails clearly.

## Swipe

```bash
Expand All @@ -41,6 +51,15 @@ axe swipe --start-x 50 --start-y 500 --end-x 350 --end-y 500 --duration 2.0 --de
axe swipe --start-x 100 --start-y 300 --end-x 300 --end-y 100 --pre-delay 1.0 --post-delay 0.5 --udid <UDID>
```

## Drag (low-level)

```bash
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --udid <UDID>
axe drag --start-x 100 --start-y 400 --end-x 300 --end-y 400 --duration 0.4 --steps 40 --udid <UDID>
```

`drag` emits one composite low-level HID event: touch down at the start point, a sequence of explicit touch move events, then touch up at the end point.

## Touch (low-level)

```bash
Expand Down Expand Up @@ -215,13 +234,15 @@ axe stream-video --udid <UDID> --fps 30 --format ffmpeg | \

| Parameter | Range | Description | Available on |
|---|---|---|---|
| `--pre-delay` | 0–10s | Delay before action | tap, swipe, gesture |
| `--post-delay` | 0–10s | Delay after action | tap, swipe, gesture |
| `--duration` | 0–10s | Action duration | swipe, gesture, button, key |
| `--pre-delay` | 0–10s | Delay before action | tap, swipe, drag, gesture |
| `--post-delay` | 0–10s | Delay after action | tap, swipe, drag, gesture |
| `--duration` | 0–10s | Action duration | swipe, drag, gesture, button, key |
| `--steps` | 1–1000 | Touch move event count | drag |
| `--value` | 0–100 | Target slider percentage | slider |
| `--delay` | 0–5s | Between-item delay | key-sequence, touch |

## Best practices
- Prefer `--id` / `--label` taps over coordinates for resilience.
- Prefer `--id` / `--label` selectors over coordinates for resilience; use `slider` for selector-resolved low-level HID slider dragging with AXValue tolerance verification instead of raw swipe coordinates, and use `drag` when you specifically need raw point-to-point HID drag behavior.
- Selector taps activate a contained UIKit `UISwitch` or SwiftUI `Toggle` when the matched row or label contains exactly one switch/toggle.
- Default `--tap-style automatic` uses physical touch for matched switches/toggles and simulator `tapAt` for normal taps; use `--tap-style physical|simulator` to override.
- Use single quotes for inline text to avoid shell expansion.
Expand Down
Loading
Loading