with one click
ai-test-runner
// Run a suite of AI-driven test cases against the WordPress and Jetpack iOS app in a simulator. Use when asked to run a test suite, run AI tests, or execute test cases in a directory.
// Run a suite of AI-driven test cases against the WordPress and Jetpack iOS app in a simulator. Use when asked to run a test suite, run AI tests, or execute test cases in a directory.
General-purpose skill for navigating and interacting with an iOS app running in a Simulator using WebDriverAgent (WDA). Use when the user asks to tap buttons, swipe, scroll, type text, check what's on screen, go to a tab or screen, automate a flow, or verify UI state in a simulator app. Also use when the user wants to take screenshots, inspect the accessibility tree, explore screen hierarchy, or test a UI flow end-to-end on a simulator. Even if the user says something casual like "open settings in the app", "click that button", or "what's showing on the simulator" — this skill applies.
Use when you need to change the active scheme of the running Xcode app (typically before invoking the Xcode MCP BuildProject/RunSomeTests/RunAllTests tools, which always operate on Xcode's currently-selected scheme), or when you need to discover what schemes or run destinations a workspace defines. Listing-only for run destinations — Xcode 26.x's AppleScript cannot persistently change the active destination, so destination switching must be done manually in the Xcode toolbar.
| name | ai-test-runner |
| description | Run a suite of AI-driven test cases against the WordPress and Jetpack iOS app in a simulator. Use when asked to run a test suite, run AI tests, or execute test cases in a directory. |
Run plain-language test cases against the WordPress or Jetpack iOS app on an iOS Simulator. Each test case is a markdown file with Prerequisites, Steps, and Expected Outcome. Claude Code navigates the app UI autonomously using WebDriverAgent.
Before running any tests, ask the user for the following using AskUserQuestion.
https://example.com)Here are the app bundle IDs:
org.wordpresscom.automattic.jetpack*.md files in the directory the user specified.Discovered N test(s) in <dir>:
- view-media-library.md
- view-posts-list.md
- view-site-settings.md
If no .md files are found, tell the user and stop.
Run the WDA start script, which locates at scripts/wda-start.rb in the
ios-sim-navigation skill directory. This may take up to 60 seconds the first time.
Create a WDA session:
curl -s -X POST http://localhost:8100/session \
-H 'Content-Type: application/json' \
-d '{"capabilities":{"alwaysMatch":{}}}'
Extract the session ID from value.sessionId in the response.
Get the booted simulator UDID for screenshots:
xcrun simctl list devices booted -j | jq -r '.devices | to_entries[].value[] | select(.state == "Booted") | .udid'
If WDA fails to start or no simulator is booted, tell the user and stop.
YYYY-MM-DD-HHmm from the current date and time.ui-tests).ai-tests/ui-tests, the base directory is ai-tests/).mkdir -p <base>/results/<timestamp>-<suite>mkdir -p <base>/results/screenshotsRun each test case sequentially. Tests share one simulator so they must not run in parallel.
Track pass/fail/remaining counts in-context (incrementing counters).
Call the Agent tool with subagent_type: general-purpose and a prompt
constructed from the template below.
Build the prompt by filling in the <PLACEHOLDERS> with actual values:
You are running a single test case against the <APP_NAME> iOS app in a simulator
using WebDriverAgent (WDA).
Use the ios-sim-navigation skill for WDA interaction reference.
## Context
- App Bundle ID: <APP_BUNDLE_ID>
- WDA Session ID: <SESSION_ID>
- Simulator UDID: <UDID>
- Test file: <TEST_FILE_PATH> (absolute path)
- Per-test results directory: <PER_TEST_RESULTS_DIR> (absolute path)
- Site URL: <SITE_URL>
- Username: <USERNAME>
- Application Password: <APPLICATION_PASSWORD>
- Screenshots directory: <SCREENSHOTS_DIR> (absolute path)
## Instructions
1. **Read the test file** at `<TEST_FILE_PATH>`. It contains the information
needed to execute the test: prerequisites, steps, expected outcome, etc.
Derive the test filename (without extension) from the file path for use
in result files and screenshots.
2. **Relaunch the app** for a clean state:
```bash
xcrun simctl launch --terminate-running-process <UDID> <APP_BUNDLE_ID> \
-ui-test-site-url <SITE_URL> \
-ui-test-site-user <USERNAME> \
-ui-test-site-pass <APPLICATION_PASSWORD>
```
Wait 2-3 seconds for the app to finish loading.
The app may already be logged in to the site. Check the accessibility tree
to determine if login is required. If the app is already showing the
logged-in state (e.g., My Site screen), skip login.
If the app shows a login/signup screen, log in using these steps:
1. Tap the **"Enter your existing site address"** button.
2. Type the exact site URL value into the site address text field.
3. Tap **Continue**. The app will auto-login after this.
Wait 2-3 seconds for the app to finish loading after login.
3. **Fulfill prerequisites** from the test file.
For REST API prerequisites (e.g., creating tags, categories, or posts),
make the API calls using the site URL, username, and application password.
For UI prerequisites like "Logged in to the app with the test account",
the app relaunch in step 2 handles this automatically.
If a prerequisite cannot be fulfilled, mark the test as FAIL with reason
"Prerequisite not met: <details>" and skip to the result writing step.
4. **Execute the test case** following the steps, expected outcome, and any
verification/cleanup sections in the test file. Use WDA for all UI
interactions (refer to the ios-sim-navigation skill). Perform any REST API
cleanup regardless of pass/fail.
5. **Write per-test result file** at
`<PER_TEST_RESULTS_DIR>/<test-filename>.md`:
On pass — write:
```
### PASS <Test Title>
Passed.
```
On fail — take a failure screenshot, save it, then write:
```bash
xcrun simctl io <UDID> screenshot <SCREENSHOTS_DIR>/<test-filename>-failure.png
```
```
### FAIL <Test Title>
**Failure reason:** <description of what went wrong>
**Screenshot:** screenshots/<test-filename>-failure.png
```
6. **End your response** with exactly one of these lines as the very last line:
```
RESULT: PASS
```
or:
```
RESULT: FAIL: <reason>
```
IMPORTANT: Prefer the accessibility tree over screenshots. After every tap or
swipe, wait 0.5-1 seconds then re-fetch the tree to see the updated UI state.
After the subagent returns, parse its response:
RESULT: PASS or RESULT: FAIL: <reason>.[2/5] PASS: create-blank-page
or:
[2/5] FAIL: create-blank-page — <reason>
Stop WDA:
ruby ~/.claude/skills/ios-sim-navigation/scripts/wda-stop.rb
Assemble the final results file at <base>/results/<timestamp>-<suite>.md:
<base>/results/<timestamp>-<suite>/# Test Results: <suite>
- **Date:** <YYYY-MM-DD HH:mm>
- **Site:** <site_url>
- **Total:** N | **Passed:** P | **Failed:** F
## Results
<contents of per-test result files, concatenated with blank lines between>
Print the final summary to the terminal:
Test run complete.
Total: N | Passed: P | Failed: F
Results: <base>/results/<timestamp>-<suite>.md
(screen_width - 30, screen_height / 2) upward
to avoid accidentally tapping interactive elements in the center.<base>/results/screenshots/).