Munyon-Canyon

ios-simslim-fast-qa

基于 SimSlim(精简模拟器)和 MobAI 自动化的 iOS 模拟器快速 QA 循环,用于冒烟测试、应用构建和智能体驱动的点击测试。适用于功能后的快速 iOS QA,而非完整回归或大规模多模拟器测试。

Munyon-Canyon 0 更新于 2周前
GitHub

安装

npx skillscat add munyon-canyon/monaco/ios-simslim-fast-qa

通过 SkillsCat registry 安装。

技能简介

基于 SimSlim(精简模拟器)和 MobAI 自动化的 iOS 模拟器快速 QA 循环,用于冒烟测试、应用构建和智能体驱动的点击测试。适用于功能后的快速 iOS QA,而非完整回归或大规模多模拟器测试。

SKILL.md

iOS SimSlim Fast QA

Repo-agnostic fast smoke loop: one slim simulator, one MobAI claim, tight iterate cycle.

Layer Job Not its job
SimSlim Disable unused sim daemons; verify/doctor Tap UI, build, screenshot
MobAI + mobai-mcp claim, start_bridge, execute_dsl, install_app Compile Swift; slim RAM
xcodebuild / MobileBuildMCP Build, install, optional snapshot-ui Cut sim RAM or manage fleet
Agent discover → profile → build → drive → fix Stock sim forever; drive another lane's sim

Default: 1 sim (~0.9 GB slim vs ~4 GB stock). Rare: 2–3 sims (clone gold after slim-once). No 12-sim farm.


When to use

  • User asks for fast iOS QA, sim smoke, agent tap-through, SimSlim, or MobAI.
  • Day-1 smoke after a feature: launch, primary nav, one critical path — not full regression.
  • Unit tests first (no sim). Expand tiers only after smoke is green.

Skip this skill for web automation (not available on iOS sim). Parallel agents in separate worktrees each run this loop on their own lane simulator: scripted taps go through the XCUITest journeys (scripts/qa/journey.py), ad-hoc taps through an MCP that takes a simulator id per call, with the lane UDID from scripts/gold-sim-udid.sh.


Machine setup (once)

SimSlim

brew install mobai-app/tap/simslim

MobAI desktop

Run MobAI desktop app. API at 127.0.0.1:8686.

MCP (user or repo .cursor/mcp.json)

{
  "mcpServers": {
    "mobai": {
      "command": "npx",
      "args": ["-y", "mobai-mcp"]
    }
  }
}

Add MobileBuildMCP only if the repo already wires it — optional, not required.

Gold simulator (once per machine, slow)

Pick one iOS 18.5+ runtime (slim persist minimum). Boot it, note UDID:

xcrun simctl list devices available

Slim it once with base profile:

simslim on <GOLD_UDID> --profile ci/profiles/base-slim.json --json

Keep gold booted between agent sessions when possible. For 2–3 sims: clone gold after slim-once (clone inherits slim + apps).

Monaco: UDID is per machine. Never copy a UUID from this repo or another laptop. After slim-once, export SIMSLIM_UDID=<udid> (shell rc and/or plain .env). In the primary checkout scripts/gold-sim-udid.sh prints it or exits 1. In a linked worktree it prints the worktree's own lane simulator, Monaco <lane>, created on first use (docs/how-to/local-simulator.md#parallel-agents-one-simulator-per-worktree). just build mobile / just reset mobile / ./scripts/ios-sim use scripts/resolve-ios-sim.sh (stock fallback in primary). scripts/stop-mobile.sh uninstalls com.monaco.app on the lane's sims in a worktree, and on every sim except live lanes' in the primary checkout. MobileBuildMCP: --simulator-id "$(scripts/gold-sim-udid.sh)". Stock Simulator without slim: README Without slim sim.

Every session before driving UI:

simslim verify <UDID> --profile ci/profiles/<profile>.json \
  || simslim on <UDID> --profile ci/profiles/<profile>.json
simslim doctor --requires ci/profiles/<profile>.json

except in profile = KEEP that daemon category ON (less slim, more capability).


Repo discovery

Run before first build. Works on any Swift/UIKit/SwiftUI app.

Target How Why
Scheme xcodebuild -list -json — pick app scheme, not test-only Build target
Bundle ID xcodebuild -showBuildSettings -scheme <SCHEME> | grep PRODUCT_BUNDLE_IDENTIFIER or Info.plist open_app / install_app
Deploy target IPHONEOS_DEPLOYMENT_TARGET in pbxproj or build settings Must fit sim runtime; slim persist needs iOS 18.5+
Entitlements *.entitlements, Signing & Capabilities in pbxproj Profile except/keep map
Info.plist *UsageDescription*, URL schemes, SKAdNetwork Photos, camera, location, tracking
Backends README, .env.example, localhost URLs in code Start sidecar before UI tier
xcodebuild -list -json
xcodebuild -scheme <SCHEME> -showBuildSettings 2>/dev/null | grep -E 'PRODUCT_BUNDLE_IDENTIFIER|IPHONEOS_DEPLOYMENT_TARGET'

Capability → profile map

Start from base-slim (maximum cut). Add except / keep only for QA paths that touch that subsystem.

Rule: except: ["photos"] means keep the photos category ON.

Signal in repo Profile tweak Category
SwiftUI tabs only, no system pickers except: [] Full slim
PHPicker / Photos / camera except: ["photos"] photos
Push notifications QA keep: ["apsd"] or except: ["push"] push
StoreKit / IAP keep: ["storekitd"] storekit
Universal links / handoff keep: ["swcd"] links
HealthKit except: ["health"] health
Location / maps except: ["location"] location
iCloud / CloudKit except: ["icloud"] icloud

Example ci/profiles/base-slim.json (keeps siri: slimmed away, the keyboard's dictation handler spins the app's main thread):

{
  "except": ["siri"]
}

Example ci/profiles/photos-qa.json:

{
  "except": ["photos"]
}

Re-pick profile when entitlements or smoke scope changes.


Inner loop

discover → profile → verify||on → build → install → claim → start_bridge → drive → report → (fix) → loop

Checklist (copy per iteration)

- [ ] Discover scheme, bundle ID, entitlements, deploy target
- [ ] Pick slim profile; verify || on; doctor
- [ ] Build .app
- [ ] Install on claimed sim UDID
- [ ] MobAI: claim → start_bridge → open_app → execute_dsl
- [ ] On fail: save_screenshot + ui_tree; fix code; loop
- [ ] release_device when done

Build + install (xcodebuild — always available)

xcodebuild -scheme <SCHEME> \
  -destination 'platform=iOS Simulator,id=<UDID>' \
  -derivedDataPath /tmp/dd-<SCHEME> \
  build

xcrun simctl install <UDID> \
  /tmp/dd-<SCHEME>/Build/Products/Debug-iphonesimulator/<App>.app

Build + install (MobileBuildMCP — if present)

Use same UDID MobAI will claim. build-and-run, snapshot-ui, screenshot — optional shortcuts, not assumed.


MobAI protocol

Read first: fetch MCP resource mobai://reference/device-automation (and testing docs if driving flows).

Step Action
Reserve list_devices → claim_device(holder=<task-id>)
Bridge start_bridge — iOS cold start ~60s; wait for ready
Fresh launch open_app with bundleId, fresh=true
Drive execute_dsl batch or replay mobai/flows/*.mob if repo has them
Fail save_screenshot + ui_tree; debug_attach if crash
Done release_device

Concurrency: MobAI Free = 1 concurrent device — enough for one agent's loop. Parallel agents in separate worktrees do not share MobAI: each drives its own lane simulator with the XCUITest journeys or an MCP that takes a simulator id per call.

Example DSL sketch (adapt to actual MobAI schema):

{
  "steps": [
    { "action": "tap", "label": "Home" },
    { "action": "wait", "ms": 500 },
    { "action": "assert_visible", "label": "Settings" }
  ]
}

Day-1 smoke (not full suite)

Three checks on the one slim sim:

Check Pass
Launch App opens, splash dismisses, no crash
Primary nav Tabs / sidebar / root flows reachable
One critical path Single highest-risk user flow end-to-end

Write or replay flows under mobai/flows/*.mob only when the repo already uses them — do not require per-repo artifacts to run this skill.


Per-repo artifacts (optional)

Path Purpose
ci/profiles/*.json Capability-specific slim profiles
.cursor/mcp.json mobai-mcp (+ optional MobileBuildMCP)
mobai/flows/*.mob Replayable smokes for this app
.cursor/skills/<app>-qa/SKILL.md App-specific scheme, bundle, backends, smoke tiers

Skill is global. Per-repo files speed repeat runs; absence is fine — discover each time.


Gotchas

Issue Mitigation
simslim erase / recreate sim Wipes slim; re-run simslim on on gold
Runtime below iOS 18.5 Slim does not persist across reboot
start_bridge cold Budget ~60s before first tap
No launch args for test state Seed data via backend or debug menu; document blocker
Missing accessibility ids Add ids or use label/text taps; fragile
PHPicker / system pickers Use except: ["photos"]; PhotosPicker hard to automate
Backend not running Start sidecar before UI smoke
Web automation on iOS sim Not supported — native MobAI DSL only

Agent output format

After a smoke pass, report:

## iOS fast QA — <scheme>

- Sim: <name> (<UDID>), profile: <profile>.json
- Build: pass | fail
- Smoke: launch / nav / critical path — pass | fail | blocked
- Blockers: [list or none]
- Screenshot: [MobAI save path or upload if user needs link]

On fail: screenshot + ui_tree summary, one concrete fix, then re-loop — do not claim a second sim on Free tier.