@mgcrea/mcp-ios-simulator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-C1TH-p-c.js +1553 -0
- package/dist/config-C1TH-p-c.js.map +1 -0
- package/dist/index.d.ts +475 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/package.json +81 -0
- package/scripts/wda.sh +145 -0
package/scripts/wda.sh
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Build and run WebDriverAgent against an iOS Simulator — the half of
|
|
3
|
+
# mcp-ios-simulator that can read the accessibility tree and touch the screen.
|
|
4
|
+
#
|
|
5
|
+
# Screenshots do NOT need this: `simctl io screenshot` works with nothing
|
|
6
|
+
# installed. Only ios_simulator_ui_tree and the input tools do.
|
|
7
|
+
#
|
|
8
|
+
# Compared with the physical-device version of this script, everything hard is
|
|
9
|
+
# gone: no Apple Developer team, no provisioning profile, no code signing, no
|
|
10
|
+
# untrusted-developer prompt on the device, no tunnel. A simulator build is not
|
|
11
|
+
# signed at all.
|
|
12
|
+
#
|
|
13
|
+
# scripts/wda.sh setup clone + build the runner (once, ~2 minutes)
|
|
14
|
+
# scripts/wda.sh run start it and keep it running (leave this open)
|
|
15
|
+
# scripts/wda.sh status is it answering?
|
|
16
|
+
#
|
|
17
|
+
# Environment:
|
|
18
|
+
# IOS_SIMULATOR_ID UDID or name (default: the only booted simulator)
|
|
19
|
+
# IOS_SIMULATOR_WDA_PORT port to bind (default: 8100)
|
|
20
|
+
# USE_PORT same thing, for people driving xcodebuild by hand
|
|
21
|
+
# NODE node binary (default: node off PATH)
|
|
22
|
+
# WDA_DIR checkout location (default: ~/.cache/mcp-ios-simulator/WebDriverAgent)
|
|
23
|
+
# WDA_REF git tag to pin (default: v16.12.3)
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
|
|
26
|
+
WDA_DIR="${WDA_DIR:-$HOME/.cache/mcp-ios-simulator/WebDriverAgent}"
|
|
27
|
+
WDA_REF="${WDA_REF:-v16.12.3}"
|
|
28
|
+
DERIVED="${WDA_DIR}/.build"
|
|
29
|
+
PORT="${USE_PORT:-${IOS_SIMULATOR_WDA_PORT:-8100}}"
|
|
30
|
+
# Not always on PATH: a host that embeds its own runtime leaves nothing called
|
|
31
|
+
# `node` to find, and every invocation below fails with "command not found".
|
|
32
|
+
NODE="${NODE:-node}"
|
|
33
|
+
|
|
34
|
+
die() { echo "error: $*" >&2; exit 1; }
|
|
35
|
+
|
|
36
|
+
# The simulator record, straight from simctl's own JSON — the same source the
|
|
37
|
+
# server uses, so the script and the server can never disagree about which
|
|
38
|
+
# simulator they mean.
|
|
39
|
+
sim_json() {
|
|
40
|
+
xcrun simctl list devices -j -e | "$NODE" -e '
|
|
41
|
+
let raw = ""; process.stdin.on("data", (d) => (raw += d)).on("end", () => {
|
|
42
|
+
const all = Object.values(JSON.parse(raw).devices ?? {}).flat();
|
|
43
|
+
const want = process.env.IOS_SIMULATOR_ID;
|
|
44
|
+
const usable = all.filter((d) => d.isAvailable !== false);
|
|
45
|
+
const booted = usable.filter((d) => d.state === "Booted");
|
|
46
|
+
const match = want && want !== "booted"
|
|
47
|
+
? usable.find((d) => d.udid.toLowerCase() === want.toLowerCase() || d.name === want)
|
|
48
|
+
: booted.length === 1 ? booted[0] : undefined;
|
|
49
|
+
if (!match) {
|
|
50
|
+
console.error(booted.length > 1
|
|
51
|
+
? "Several simulators are booted. Set IOS_SIMULATOR_ID to one of: " +
|
|
52
|
+
booted.map((d) => `${d.name} = ${d.udid}`).join(", ")
|
|
53
|
+
: "No booted simulator. Boot one in Simulator.app, or `xcrun simctl boot <udid>`.");
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
console.log(JSON.stringify({ udid: match.udid, name: match.name, state: match.state }));
|
|
57
|
+
});
|
|
58
|
+
'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
field() { "$NODE" -e 'const d=JSON.parse(process.argv[1]);process.stdout.write(String(d[process.argv[2]]??""))' "$1" "$2"; }
|
|
62
|
+
|
|
63
|
+
cmd_setup() {
|
|
64
|
+
local sim udid name
|
|
65
|
+
sim="$(sim_json)"; udid="$(field "$sim" udid)"; name="$(field "$sim" name)"
|
|
66
|
+
echo "==> simulator: $name ($udid)"
|
|
67
|
+
|
|
68
|
+
if [ ! -d "$WDA_DIR/.git" ]; then
|
|
69
|
+
echo "==> cloning appium/WebDriverAgent $WDA_REF"
|
|
70
|
+
mkdir -p "$(dirname "$WDA_DIR")"
|
|
71
|
+
git clone --depth 1 --branch "$WDA_REF" https://github.com/appium/WebDriverAgent.git "$WDA_DIR"
|
|
72
|
+
else
|
|
73
|
+
echo "==> reusing $WDA_DIR"
|
|
74
|
+
git -C "$WDA_DIR" fetch --depth 1 origin "refs/tags/$WDA_REF:refs/tags/$WDA_REF" 2>/dev/null || true
|
|
75
|
+
git -C "$WDA_DIR" checkout -q "$WDA_REF"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# A separate checkout from the device server's on purpose. The two could share
|
|
79
|
+
# one — the products land in Debug-iphonesimulator/ rather than Debug-iphoneos/
|
|
80
|
+
# — but they would then share a derivedDataPath two xcodebuild processes can
|
|
81
|
+
# enter at once, and a `git checkout $WDA_REF` in one would yank the ref out
|
|
82
|
+
# from under the other the first time the pins diverge.
|
|
83
|
+
echo "==> building the runner (no signing: a simulator build needs no team)"
|
|
84
|
+
xcodebuild build-for-testing \
|
|
85
|
+
-project "$WDA_DIR/WebDriverAgent.xcodeproj" \
|
|
86
|
+
-scheme WebDriverAgentRunner \
|
|
87
|
+
-destination "platform=iOS Simulator,id=$udid" \
|
|
88
|
+
-derivedDataPath "$DERIVED" \
|
|
89
|
+
CODE_SIGNING_ALLOWED=NO
|
|
90
|
+
|
|
91
|
+
echo
|
|
92
|
+
echo "Built. Now run: scripts/wda.sh run"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
cmd_run() {
|
|
96
|
+
local sim udid name xctestrun patched
|
|
97
|
+
sim="$(sim_json)"; udid="$(field "$sim" udid)"; name="$(field "$sim" name)"
|
|
98
|
+
xctestrun="$(ls "$DERIVED"/Build/Products/WebDriverAgentRunner_iphonesimulator*.xctestrun 2>/dev/null | head -1 || true)"
|
|
99
|
+
[ -n "$xctestrun" ] || die "no build found in $DERIVED — run \`scripts/wda.sh setup\` first"
|
|
100
|
+
|
|
101
|
+
# Pin the port, always. Left unset, WebDriverAgent scans 8100-8199 and binds
|
|
102
|
+
# the first free one (FBConfiguration.m: DefaultStartingPort 8100, range 100),
|
|
103
|
+
# so a second simulator's runner comes up healthy on 8101 and a server
|
|
104
|
+
# configured for 8100 drives the *first* simulator while every tool reports
|
|
105
|
+
# success. With USE_PORT set the range collapses to one and a collision is a
|
|
106
|
+
# loud bind failure instead of a silent wrong-target bug.
|
|
107
|
+
#
|
|
108
|
+
# Patched into a copy of the xctestrun rather than the original, so a second
|
|
109
|
+
# simulator on a different port does not race the first.
|
|
110
|
+
# Beside the original, not in $DERIVED: an xctestrun resolves its product
|
|
111
|
+
# paths against __TESTROOT__, which is its own directory, so a copy one level
|
|
112
|
+
# up looks for the .xctest bundle in a place that does not exist and fails
|
|
113
|
+
# with "Missing test product".
|
|
114
|
+
patched="$(dirname "$xctestrun")/wda-$PORT.xctestrun"
|
|
115
|
+
cp "$xctestrun" "$patched"
|
|
116
|
+
/usr/bin/plutil -replace WebDriverAgentRunner.EnvironmentVariables.USE_PORT \
|
|
117
|
+
-string "$PORT" "$patched" 2>/dev/null \
|
|
118
|
+
|| die "could not set USE_PORT in $patched — check the xctestrun's FormatVersion"
|
|
119
|
+
|
|
120
|
+
echo "==> starting WebDriverAgent on $name ($udid), port $PORT"
|
|
121
|
+
echo " it stays up for as long as this command runs; Ctrl-C stops it"
|
|
122
|
+
# `test-without-building` is what keeps the runner alive: the XCTest session is
|
|
123
|
+
# the process, so the HTTP server dies with it. There is no daemon mode.
|
|
124
|
+
exec env USE_PORT="$PORT" xcodebuild test-without-building \
|
|
125
|
+
-xctestrun "$patched" \
|
|
126
|
+
-destination "platform=iOS Simulator,id=$udid"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
cmd_status() {
|
|
130
|
+
local url; url="http://127.0.0.1:${PORT}/status"
|
|
131
|
+
echo "==> GET $url"
|
|
132
|
+
if curl -fsS --max-time 5 "$url"; then
|
|
133
|
+
echo
|
|
134
|
+
else
|
|
135
|
+
echo "not answering — run \`scripts/wda.sh run\`, or check the port with lsof -iTCP:$PORT" >&2
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
case "${1:-}" in
|
|
141
|
+
setup) cmd_setup ;;
|
|
142
|
+
run) cmd_run ;;
|
|
143
|
+
status) cmd_status ;;
|
|
144
|
+
*) echo "usage: $0 {setup|run|status}" >&2; exit 2 ;;
|
|
145
|
+
esac
|