@unotest/mobile 0.8.1 → 0.8.2
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/CHANGELOG.md +49 -0
- package/README.md +12 -12
- package/dist/mcp/server.js +35 -4
- package/dist/runner/cli.js +34 -3
- package/dist/runner/init.js +5 -0
- package/dist/runner/install.js +37 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,55 @@ All notable changes to `@unotest/mobile` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.8.2] — 2026-05-18
|
|
8
|
+
|
|
9
|
+
### Fixed — `type()` no longer drops 1-3 characters mid-string
|
|
10
|
+
|
|
11
|
+
- **What broke.** `WdaDriver.type` issued `XCUIElement.typeText` at WDA's
|
|
12
|
+
default typing frequency (~60 letters/sec) into the simulator's iOS
|
|
13
|
+
keyboard. Under host contention (Claude Code + WDA build + Simulator
|
|
14
|
+
all running on the same Mac), the iOS keyboard layer couldn't keep
|
|
15
|
+
up and randomly dropped 1-3 characters from the middle of the string
|
|
16
|
+
— observed live as `petr@volkov.io` → `pr@volkov.io`, `Qwerty34##`
|
|
17
|
+
→ `Qwery34##`. P4 / S8 had only addressed the unrelated *wrong-
|
|
18
|
+
keyboard-layout* failure (Cyrillic keyboard eating Latin chars
|
|
19
|
+
wholesale); this race is a separate failure mode that survived.
|
|
20
|
+
- **Fix 1 — `ConnectHardwareKeyboard` pinned OFF on install.**
|
|
21
|
+
The `pinEnglishKeyboard` step (S8) now also writes
|
|
22
|
+
`ConnectHardwareKeyboard = false` into the Simulator.app preferences
|
|
23
|
+
on every install. When the toggle is ON (the default on a freshly
|
|
24
|
+
created sim, controlled by ⌘K inside the sim), iOS suppresses the
|
|
25
|
+
soft keyboard and routes keys through the host's physical keyboard
|
|
26
|
+
path — typeText then races against keyboard presentation. Pinning
|
|
27
|
+
OFF guarantees the soft keyboard renders and stays visible.
|
|
28
|
+
Idempotent. Reuses the existing `pinKeyboard: false` opt-out flag.
|
|
29
|
+
- **Fix 2 — `WDA_TYPING_FREQUENCY` env (default `8`).** `WdaDriver.type`
|
|
30
|
+
now passes `frequency: <env>` in the POST `/element/{id}/value`
|
|
31
|
+
body, which WDA forwards to `fb_typeText:withFrequency:`. 8 cps is
|
|
32
|
+
conservative-but-still-usable: typical credentials (`petr@volkov.io`,
|
|
33
|
+
`Qwerty34##`) type in ~2s instead of the unreliable ~0.3s. Bump
|
|
34
|
+
higher if you trust your host's headroom; lower if you're seeing
|
|
35
|
+
drops in CI under heavy load. Validated as a positive integer at
|
|
36
|
+
`loadEnv` time.
|
|
37
|
+
- **Why not pasteboard / per-char paste.** Researched approaches the
|
|
38
|
+
XCUITest community has tried (`UIPasteboard` + double-tap-menu paste,
|
|
39
|
+
per-char `typeKey:` calls, `setValue` direct-set): pasteboard paste
|
|
40
|
+
is **43% slower and flaky** (per iammike.org / 2022); per-char
|
|
41
|
+
`typeKey:` is only 3% faster than throttled `typeText`, complex to
|
|
42
|
+
wire reliably; `setValue` on native iOS text fields routes back to
|
|
43
|
+
`typeText` internally — there is no Apple-blessed "set text without
|
|
44
|
+
keyboard" API. WDA's own `maxTypingFrequency` is the documented knob.
|
|
45
|
+
- **Tests:** +0 net. Modified 1 existing assertion to verify
|
|
46
|
+
`frequency: 8` lands in the request body. The hardware-keyboard
|
|
47
|
+
flip rides on the same `pinEnglishKeyboard` call site, so existing
|
|
48
|
+
call-sequence assertions still hold. Total 570.
|
|
49
|
+
|
|
50
|
+
### Added — `WDA_TYPING_FREQUENCY` env var
|
|
51
|
+
|
|
52
|
+
- Letters-per-second passed to WDA's `fb_typeText:withFrequency:` on
|
|
53
|
+
every `type(...)` call. Default `8`. See the fix entry above for
|
|
54
|
+
rationale on the conservative default.
|
|
55
|
+
|
|
7
56
|
## [0.8.1] — 2026-05-18
|
|
8
57
|
|
|
9
58
|
### Fixed — `init` pins the exact `@unotest/mobile` version in `.mcp.json`
|
package/README.md
CHANGED
|
@@ -30,18 +30,18 @@ you review the resulting `.js` files in `unotest/e2e/`.
|
|
|
30
30
|
┌─────────────┐ MCP (stdio) ┌──────────────────┐
|
|
31
31
|
│ Claude Code │ ◀────────────▶ │ @unotest/mobile │
|
|
32
32
|
└─────────────┘ tool calls │ (this package) │
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
└────────┬─────────┘
|
|
34
|
+
│ HTTP
|
|
35
|
+
┌────────▼──────────┐
|
|
36
|
+
│ WebDriverAgent │
|
|
37
|
+
│ (Apple's XCUI │
|
|
38
|
+
│ driver, on sim) │
|
|
39
|
+
└────────┬──────────┘
|
|
40
|
+
│
|
|
41
|
+
┌────────▼──────────┐
|
|
42
|
+
│ iOS Simulator │
|
|
43
|
+
│ Your .app │
|
|
44
|
+
└───────────────────┘
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
- **The agent sees the accessibility tree, not screenshots.** WDA
|
package/dist/mcp/server.js
CHANGED
|
@@ -240,6 +240,15 @@ var EnvSchema = z.object({
|
|
|
240
240
|
// Implicit auto-wait on selector-bearing actions (D-18).
|
|
241
241
|
WDA_DEFAULT_ACTION_WAIT_MS: z.string().default("2000").transform((v) => Number.parseInt(v, 10)),
|
|
242
242
|
WDA_DEFAULT_WAITFOR_TIMEOUT_MS: z.string().default("10000").transform((v) => Number.parseInt(v, 10)),
|
|
243
|
+
// Typing frequency (letters/sec) passed through to WDA's
|
|
244
|
+
// `fb_typeText:withFrequency:` on every `type(...)` call. WDA's own
|
|
245
|
+
// default is its `maxTypingFrequency` (typically 60 cps) which under
|
|
246
|
+
// contention from the host (Claude Code + WDA build + sim) races
|
|
247
|
+
// against the iOS keyboard presentation and randomly drops 1-3 chars
|
|
248
|
+
// mid-string. 8 cps is the conservative-but-still-usable value that
|
|
249
|
+
// empirically eliminates drops without making typing visibly slow
|
|
250
|
+
// (`petr@volkov.io` types in ~2s instead of ~0.3s).
|
|
251
|
+
WDA_TYPING_FREQUENCY: z.string().default("8").transform((v) => Number.parseInt(v, 10)),
|
|
243
252
|
// TTL for paused-failed runtimes before auto-abort (D-17). Default 30 min.
|
|
244
253
|
PAUSED_RUNTIME_TTL_MS: z.string().default("1800000").transform((v) => Number.parseInt(v, 10))
|
|
245
254
|
});
|
|
@@ -287,6 +296,11 @@ ${issues}`
|
|
|
287
296
|
);
|
|
288
297
|
}
|
|
289
298
|
}
|
|
299
|
+
if (!Number.isFinite(raw.WDA_TYPING_FREQUENCY) || raw.WDA_TYPING_FREQUENCY <= 0) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
`WDA_TYPING_FREQUENCY must be a positive integer (letters/sec). Got "${process.env.WDA_TYPING_FREQUENCY}".`
|
|
302
|
+
);
|
|
303
|
+
}
|
|
290
304
|
cached = {
|
|
291
305
|
...raw,
|
|
292
306
|
simPool,
|
|
@@ -294,6 +308,7 @@ ${issues}`
|
|
|
294
308
|
wdaPortBySlot,
|
|
295
309
|
defaultActionWaitMs: raw.WDA_DEFAULT_ACTION_WAIT_MS,
|
|
296
310
|
defaultWaitForTimeoutMs: raw.WDA_DEFAULT_WAITFOR_TIMEOUT_MS,
|
|
311
|
+
wdaTypingFrequency: raw.WDA_TYPING_FREQUENCY,
|
|
297
312
|
pausedRuntimeTtlMs: raw.PAUSED_RUNTIME_TTL_MS,
|
|
298
313
|
explorationsDir: raw.EXPLORATIONS_DIR ?? `${raw.ARTIFACTS_DIR}/explorations`
|
|
299
314
|
};
|
|
@@ -636,6 +651,17 @@ async function pinEnglishKeyboardSim(udid) {
|
|
|
636
651
|
"-string",
|
|
637
652
|
"en_US"
|
|
638
653
|
]);
|
|
654
|
+
await exec2("xcrun", [
|
|
655
|
+
"simctl",
|
|
656
|
+
"spawn",
|
|
657
|
+
udid,
|
|
658
|
+
"defaults",
|
|
659
|
+
"write",
|
|
660
|
+
"com.apple.iphonesimulator.SimulatorApp",
|
|
661
|
+
"ConnectHardwareKeyboard",
|
|
662
|
+
"-bool",
|
|
663
|
+
"false"
|
|
664
|
+
]);
|
|
639
665
|
}
|
|
640
666
|
__name(pinEnglishKeyboardSim, "pinEnglishKeyboardSim");
|
|
641
667
|
|
|
@@ -690,8 +716,11 @@ var SimctlAdapter = class {
|
|
|
690
716
|
async privacyGrant(udid, service, bundleId) {
|
|
691
717
|
return privacyGrantSim(udid, service, bundleId);
|
|
692
718
|
}
|
|
693
|
-
/** S8 —
|
|
694
|
-
*
|
|
719
|
+
/** S8 — prepare the sim's keyboard for reliable `typeText`. Pins
|
|
720
|
+
* layout to en_US@QWERTY (otherwise a leftover Cyrillic layout
|
|
721
|
+
* drops Latin chars) and forces "Connect Hardware Keyboard" OFF
|
|
722
|
+
* (otherwise the soft keyboard is suppressed and `typeText` races
|
|
723
|
+
* against keyboard presentation, dropping 1-3 chars mid-string). */
|
|
695
724
|
async pinEnglishKeyboard(udid) {
|
|
696
725
|
return pinEnglishKeyboardSim(udid);
|
|
697
726
|
}
|
|
@@ -1277,7 +1306,8 @@ Install it first: \`npx unotest-mobile install <path-to-.app>\` (or set APP_PATH
|
|
|
1277
1306
|
await this.withFreshSession(slot, async (session) => {
|
|
1278
1307
|
const elementId = await this.resolveElementId(slot, selector);
|
|
1279
1308
|
await session.client.setElementValue(session.getSessionId(), elementId, {
|
|
1280
|
-
value: Array.from(text)
|
|
1309
|
+
value: Array.from(text),
|
|
1310
|
+
frequency: this.deps.typingFrequency
|
|
1281
1311
|
});
|
|
1282
1312
|
});
|
|
1283
1313
|
}
|
|
@@ -1578,6 +1608,7 @@ function createDriver(cfg) {
|
|
|
1578
1608
|
simBySlot: cfg.env.simBySlot,
|
|
1579
1609
|
wdaPortBySlot: cfg.env.wdaPortBySlot,
|
|
1580
1610
|
appBundleId: cfg.env.APP_BUNDLE_ID,
|
|
1611
|
+
typingFrequency: cfg.env.wdaTypingFrequency,
|
|
1581
1612
|
binaryProvider
|
|
1582
1613
|
});
|
|
1583
1614
|
}
|
|
@@ -6819,7 +6850,7 @@ async function installApp2(opts, deps) {
|
|
|
6819
6850
|
}
|
|
6820
6851
|
}
|
|
6821
6852
|
if (opts.pinKeyboard !== false) {
|
|
6822
|
-
deps.logger.info(`[${slot}] pinning keyboard
|
|
6853
|
+
deps.logger.info(`[${slot}] pinning keyboard (en_US@QWERTY, soft only)`);
|
|
6823
6854
|
await deps.simctl.pinEnglishKeyboard(sim.udid);
|
|
6824
6855
|
}
|
|
6825
6856
|
let launched = false;
|
package/dist/runner/cli.js
CHANGED
|
@@ -236,6 +236,15 @@ var EnvSchema = z.object({
|
|
|
236
236
|
// Implicit auto-wait on selector-bearing actions (D-18).
|
|
237
237
|
WDA_DEFAULT_ACTION_WAIT_MS: z.string().default("2000").transform((v) => Number.parseInt(v, 10)),
|
|
238
238
|
WDA_DEFAULT_WAITFOR_TIMEOUT_MS: z.string().default("10000").transform((v) => Number.parseInt(v, 10)),
|
|
239
|
+
// Typing frequency (letters/sec) passed through to WDA's
|
|
240
|
+
// `fb_typeText:withFrequency:` on every `type(...)` call. WDA's own
|
|
241
|
+
// default is its `maxTypingFrequency` (typically 60 cps) which under
|
|
242
|
+
// contention from the host (Claude Code + WDA build + sim) races
|
|
243
|
+
// against the iOS keyboard presentation and randomly drops 1-3 chars
|
|
244
|
+
// mid-string. 8 cps is the conservative-but-still-usable value that
|
|
245
|
+
// empirically eliminates drops without making typing visibly slow
|
|
246
|
+
// (`petr@volkov.io` types in ~2s instead of ~0.3s).
|
|
247
|
+
WDA_TYPING_FREQUENCY: z.string().default("8").transform((v) => Number.parseInt(v, 10)),
|
|
239
248
|
// TTL for paused-failed runtimes before auto-abort (D-17). Default 30 min.
|
|
240
249
|
PAUSED_RUNTIME_TTL_MS: z.string().default("1800000").transform((v) => Number.parseInt(v, 10))
|
|
241
250
|
});
|
|
@@ -283,6 +292,11 @@ ${issues}`
|
|
|
283
292
|
);
|
|
284
293
|
}
|
|
285
294
|
}
|
|
295
|
+
if (!Number.isFinite(raw.WDA_TYPING_FREQUENCY) || raw.WDA_TYPING_FREQUENCY <= 0) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`WDA_TYPING_FREQUENCY must be a positive integer (letters/sec). Got "${process.env.WDA_TYPING_FREQUENCY}".`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
286
300
|
cached = {
|
|
287
301
|
...raw,
|
|
288
302
|
simPool,
|
|
@@ -290,6 +304,7 @@ ${issues}`
|
|
|
290
304
|
wdaPortBySlot,
|
|
291
305
|
defaultActionWaitMs: raw.WDA_DEFAULT_ACTION_WAIT_MS,
|
|
292
306
|
defaultWaitForTimeoutMs: raw.WDA_DEFAULT_WAITFOR_TIMEOUT_MS,
|
|
307
|
+
wdaTypingFrequency: raw.WDA_TYPING_FREQUENCY,
|
|
293
308
|
pausedRuntimeTtlMs: raw.PAUSED_RUNTIME_TTL_MS,
|
|
294
309
|
explorationsDir: raw.EXPLORATIONS_DIR ?? `${raw.ARTIFACTS_DIR}/explorations`
|
|
295
310
|
};
|
|
@@ -632,6 +647,17 @@ async function pinEnglishKeyboardSim(udid) {
|
|
|
632
647
|
"-string",
|
|
633
648
|
"en_US"
|
|
634
649
|
]);
|
|
650
|
+
await exec2("xcrun", [
|
|
651
|
+
"simctl",
|
|
652
|
+
"spawn",
|
|
653
|
+
udid,
|
|
654
|
+
"defaults",
|
|
655
|
+
"write",
|
|
656
|
+
"com.apple.iphonesimulator.SimulatorApp",
|
|
657
|
+
"ConnectHardwareKeyboard",
|
|
658
|
+
"-bool",
|
|
659
|
+
"false"
|
|
660
|
+
]);
|
|
635
661
|
}
|
|
636
662
|
__name(pinEnglishKeyboardSim, "pinEnglishKeyboardSim");
|
|
637
663
|
|
|
@@ -686,8 +712,11 @@ var SimctlAdapter = class {
|
|
|
686
712
|
async privacyGrant(udid, service, bundleId) {
|
|
687
713
|
return privacyGrantSim(udid, service, bundleId);
|
|
688
714
|
}
|
|
689
|
-
/** S8 —
|
|
690
|
-
*
|
|
715
|
+
/** S8 — prepare the sim's keyboard for reliable `typeText`. Pins
|
|
716
|
+
* layout to en_US@QWERTY (otherwise a leftover Cyrillic layout
|
|
717
|
+
* drops Latin chars) and forces "Connect Hardware Keyboard" OFF
|
|
718
|
+
* (otherwise the soft keyboard is suppressed and `typeText` races
|
|
719
|
+
* against keyboard presentation, dropping 1-3 chars mid-string). */
|
|
691
720
|
async pinEnglishKeyboard(udid) {
|
|
692
721
|
return pinEnglishKeyboardSim(udid);
|
|
693
722
|
}
|
|
@@ -1273,7 +1302,8 @@ Install it first: \`npx unotest-mobile install <path-to-.app>\` (or set APP_PATH
|
|
|
1273
1302
|
await this.withFreshSession(slot, async (session) => {
|
|
1274
1303
|
const elementId = await this.resolveElementId(slot, selector);
|
|
1275
1304
|
await session.client.setElementValue(session.getSessionId(), elementId, {
|
|
1276
|
-
value: Array.from(text)
|
|
1305
|
+
value: Array.from(text),
|
|
1306
|
+
frequency: this.deps.typingFrequency
|
|
1277
1307
|
});
|
|
1278
1308
|
});
|
|
1279
1309
|
}
|
|
@@ -1574,6 +1604,7 @@ function createDriver(cfg) {
|
|
|
1574
1604
|
simBySlot: cfg.env.simBySlot,
|
|
1575
1605
|
wdaPortBySlot: cfg.env.wdaPortBySlot,
|
|
1576
1606
|
appBundleId: cfg.env.APP_BUNDLE_ID,
|
|
1607
|
+
typingFrequency: cfg.env.wdaTypingFrequency,
|
|
1577
1608
|
binaryProvider
|
|
1578
1609
|
});
|
|
1579
1610
|
}
|
package/dist/runner/init.js
CHANGED
|
@@ -272,6 +272,11 @@ APP_BUNDLE_ID=com.example.myapp
|
|
|
272
272
|
WDA_PORTS=A=8100,B=8101
|
|
273
273
|
# WDA_DEFAULT_ACTION_WAIT_MS=2000
|
|
274
274
|
# WDA_DEFAULT_WAITFOR_TIMEOUT_MS=10000
|
|
275
|
+
# Letters/sec for type() \u2014 WDA's fb_typeText:withFrequency:. Conservative
|
|
276
|
+
# default avoids char-drop races against the iOS keyboard layer when the
|
|
277
|
+
# host is under load. Bump higher (e.g. 20) on a quiet machine; lower
|
|
278
|
+
# (e.g. 4) if you still see drops in CI.
|
|
279
|
+
# WDA_TYPING_FREQUENCY=8
|
|
275
280
|
|
|
276
281
|
# --- Artifacts / sessions / paused-runtime TTL -----------------------------
|
|
277
282
|
# Defaults are sensible \u2014 uncomment only to override.
|
package/dist/runner/install.js
CHANGED
|
@@ -84,6 +84,15 @@ var EnvSchema = z.object({
|
|
|
84
84
|
// Implicit auto-wait on selector-bearing actions (D-18).
|
|
85
85
|
WDA_DEFAULT_ACTION_WAIT_MS: z.string().default("2000").transform((v) => Number.parseInt(v, 10)),
|
|
86
86
|
WDA_DEFAULT_WAITFOR_TIMEOUT_MS: z.string().default("10000").transform((v) => Number.parseInt(v, 10)),
|
|
87
|
+
// Typing frequency (letters/sec) passed through to WDA's
|
|
88
|
+
// `fb_typeText:withFrequency:` on every `type(...)` call. WDA's own
|
|
89
|
+
// default is its `maxTypingFrequency` (typically 60 cps) which under
|
|
90
|
+
// contention from the host (Claude Code + WDA build + sim) races
|
|
91
|
+
// against the iOS keyboard presentation and randomly drops 1-3 chars
|
|
92
|
+
// mid-string. 8 cps is the conservative-but-still-usable value that
|
|
93
|
+
// empirically eliminates drops without making typing visibly slow
|
|
94
|
+
// (`petr@volkov.io` types in ~2s instead of ~0.3s).
|
|
95
|
+
WDA_TYPING_FREQUENCY: z.string().default("8").transform((v) => Number.parseInt(v, 10)),
|
|
87
96
|
// TTL for paused-failed runtimes before auto-abort (D-17). Default 30 min.
|
|
88
97
|
PAUSED_RUNTIME_TTL_MS: z.string().default("1800000").transform((v) => Number.parseInt(v, 10))
|
|
89
98
|
});
|
|
@@ -131,6 +140,11 @@ ${issues}`
|
|
|
131
140
|
);
|
|
132
141
|
}
|
|
133
142
|
}
|
|
143
|
+
if (!Number.isFinite(raw.WDA_TYPING_FREQUENCY) || raw.WDA_TYPING_FREQUENCY <= 0) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`WDA_TYPING_FREQUENCY must be a positive integer (letters/sec). Got "${process.env.WDA_TYPING_FREQUENCY}".`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
134
148
|
cached = {
|
|
135
149
|
...raw,
|
|
136
150
|
simPool,
|
|
@@ -138,6 +152,7 @@ ${issues}`
|
|
|
138
152
|
wdaPortBySlot,
|
|
139
153
|
defaultActionWaitMs: raw.WDA_DEFAULT_ACTION_WAIT_MS,
|
|
140
154
|
defaultWaitForTimeoutMs: raw.WDA_DEFAULT_WAITFOR_TIMEOUT_MS,
|
|
155
|
+
wdaTypingFrequency: raw.WDA_TYPING_FREQUENCY,
|
|
141
156
|
pausedRuntimeTtlMs: raw.PAUSED_RUNTIME_TTL_MS,
|
|
142
157
|
explorationsDir: raw.EXPLORATIONS_DIR ?? `${raw.ARTIFACTS_DIR}/explorations`
|
|
143
158
|
};
|
|
@@ -364,6 +379,17 @@ async function pinEnglishKeyboardSim(udid) {
|
|
|
364
379
|
"-string",
|
|
365
380
|
"en_US"
|
|
366
381
|
]);
|
|
382
|
+
await exec("xcrun", [
|
|
383
|
+
"simctl",
|
|
384
|
+
"spawn",
|
|
385
|
+
udid,
|
|
386
|
+
"defaults",
|
|
387
|
+
"write",
|
|
388
|
+
"com.apple.iphonesimulator.SimulatorApp",
|
|
389
|
+
"ConnectHardwareKeyboard",
|
|
390
|
+
"-bool",
|
|
391
|
+
"false"
|
|
392
|
+
]);
|
|
367
393
|
}
|
|
368
394
|
__name(pinEnglishKeyboardSim, "pinEnglishKeyboardSim");
|
|
369
395
|
|
|
@@ -418,8 +444,11 @@ var SimctlAdapter = class {
|
|
|
418
444
|
async privacyGrant(udid, service, bundleId) {
|
|
419
445
|
return privacyGrantSim(udid, service, bundleId);
|
|
420
446
|
}
|
|
421
|
-
/** S8 —
|
|
422
|
-
*
|
|
447
|
+
/** S8 — prepare the sim's keyboard for reliable `typeText`. Pins
|
|
448
|
+
* layout to en_US@QWERTY (otherwise a leftover Cyrillic layout
|
|
449
|
+
* drops Latin chars) and forces "Connect Hardware Keyboard" OFF
|
|
450
|
+
* (otherwise the soft keyboard is suppressed and `typeText` races
|
|
451
|
+
* against keyboard presentation, dropping 1-3 chars mid-string). */
|
|
423
452
|
async pinEnglishKeyboard(udid) {
|
|
424
453
|
return pinEnglishKeyboardSim(udid);
|
|
425
454
|
}
|
|
@@ -912,6 +941,11 @@ APP_BUNDLE_ID=com.example.myapp
|
|
|
912
941
|
WDA_PORTS=A=8100,B=8101
|
|
913
942
|
# WDA_DEFAULT_ACTION_WAIT_MS=2000
|
|
914
943
|
# WDA_DEFAULT_WAITFOR_TIMEOUT_MS=10000
|
|
944
|
+
# Letters/sec for type() \u2014 WDA's fb_typeText:withFrequency:. Conservative
|
|
945
|
+
# default avoids char-drop races against the iOS keyboard layer when the
|
|
946
|
+
# host is under load. Bump higher (e.g. 20) on a quiet machine; lower
|
|
947
|
+
# (e.g. 4) if you still see drops in CI.
|
|
948
|
+
# WDA_TYPING_FREQUENCY=8
|
|
915
949
|
|
|
916
950
|
# --- Artifacts / sessions / paused-runtime TTL -----------------------------
|
|
917
951
|
# Defaults are sensible \u2014 uncomment only to override.
|
|
@@ -1324,7 +1358,7 @@ async function installApp2(opts, deps) {
|
|
|
1324
1358
|
}
|
|
1325
1359
|
}
|
|
1326
1360
|
if (opts.pinKeyboard !== false) {
|
|
1327
|
-
deps.logger.info(`[${slot}] pinning keyboard
|
|
1361
|
+
deps.logger.info(`[${slot}] pinning keyboard (en_US@QWERTY, soft only)`);
|
|
1328
1362
|
await deps.simctl.pinEnglishKeyboard(sim.udid);
|
|
1329
1363
|
}
|
|
1330
1364
|
let launched = false;
|