@delacour/warden-e2e 0.1.1 → 0.3.1
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/{chunk-qtkmfjbq.mjs → chunk-8em9kgsk.mjs} +5522 -4247
- package/index.mjs +151 -102
- package/package.json +2 -2
- package/preload.mjs +259 -971
- package/types/core/src/providers/android.d.ts +8 -0
- package/types/core/src/store.d.ts +15 -1
- package/types/core/src/types.d.ts +20 -0
- package/types/e2e/src/app.d.ts +1 -1
- package/types/e2e/src/device.d.ts +9 -1
- package/types/e2e/src/devtools/native-log.d.ts +50 -0
- package/types/e2e/src/driver/android/uiad-backend.d.ts +1 -1
- package/types/e2e/src/driver/driver.types.d.ts +1 -1
- package/types/e2e/src/driver/ios/hid-recovery.d.ts +36 -0
- package/types/e2e/src/driver/ios/simctl.d.ts +15 -0
- package/types/e2e/src/driver/observation-cache.d.ts +1 -1
- package/types/e2e/src/env.d.ts +26 -9
- package/types/e2e/src/errors.d.ts +1 -1
- package/types/e2e/src/fixture-session.d.ts +5 -1
- package/types/e2e/src/index.d.ts +3 -0
- package/types/e2e/src/perf/budgets.d.ts +33 -0
- package/types/e2e/src/perf/device-perf.d.ts +45 -0
- package/types/e2e/src/perf/perf.types.d.ts +59 -0
- package/types/e2e/src/preload.d.ts +2 -2
- package/types/e2e/src/runner/artifacts.d.ts +5 -5
- package/types/e2e/src/runner/failure.d.ts +12 -0
- package/types/e2e/src/runner/fixtures.types.d.ts +1 -1
- package/types/e2e/src/runner/scope.d.ts +5 -3
- package/types/e2e/src/runner/test.d.ts +7 -0
- package/types/e2e/src/screen/actions.d.ts +1 -1
- package/types/e2e/src/session.d.ts +19 -0
package/preload.mjs
CHANGED
|
@@ -1,93 +1,78 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
E2eError2,
|
|
4
|
+
noteSpanDetail,
|
|
5
|
+
addSpanDetail,
|
|
6
|
+
canObserve,
|
|
7
|
+
canDetectAlerts,
|
|
8
|
+
settleDetailOf,
|
|
5
9
|
DEFAULT_SETTLE_QUIET_MS,
|
|
6
10
|
DEFAULT_SETTLE_TIMEOUT_MS,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
settleByHash,
|
|
12
|
+
snapshotHash,
|
|
13
|
+
ok,
|
|
14
|
+
err,
|
|
15
|
+
swipeVector,
|
|
16
|
+
screenRect,
|
|
11
17
|
PINCH_MS,
|
|
12
18
|
ROTATE_MS,
|
|
13
|
-
|
|
14
|
-
WORKSPACE_VERSION,
|
|
15
|
-
addSpanDetail,
|
|
16
|
-
assertDegrees,
|
|
17
|
-
assertScale,
|
|
18
|
-
canDetectAlerts,
|
|
19
|
-
canObserve,
|
|
19
|
+
PATH_MS,
|
|
20
20
|
centreOf,
|
|
21
|
-
err,
|
|
22
|
-
getSession,
|
|
23
|
-
hasDefaultDriverFactory,
|
|
24
|
-
hasDefaultFixtureFactory,
|
|
25
|
-
indexSnapshot,
|
|
26
|
-
isInteractiveRole,
|
|
27
|
-
isLocator,
|
|
28
|
-
locateByTestIdViaReact,
|
|
29
|
-
noteSpanDetail,
|
|
30
|
-
ok,
|
|
31
|
-
onlyWasSeen,
|
|
32
21
|
pinchRadius,
|
|
33
|
-
|
|
34
|
-
renderHeader,
|
|
35
|
-
renderSnapshot,
|
|
22
|
+
rotateRadius,
|
|
36
23
|
requireGesture,
|
|
24
|
+
assertScale,
|
|
25
|
+
assertDegrees,
|
|
26
|
+
isInteractiveRole,
|
|
37
27
|
resolveRole,
|
|
28
|
+
indexSnapshot,
|
|
29
|
+
testIdQuery,
|
|
30
|
+
textQuery,
|
|
38
31
|
roleQuery,
|
|
39
|
-
rotateRadius,
|
|
40
|
-
screenRect,
|
|
41
|
-
screenshotPath,
|
|
42
|
-
scrollUntilVisible,
|
|
43
32
|
selectorExpression,
|
|
33
|
+
renderSnapshot,
|
|
34
|
+
renderHeader,
|
|
35
|
+
locateByTestIdViaReact,
|
|
36
|
+
isLocator,
|
|
37
|
+
Locator,
|
|
38
|
+
scrollUntilVisible,
|
|
39
|
+
bunExec,
|
|
40
|
+
execError,
|
|
41
|
+
driverError,
|
|
42
|
+
driverErr,
|
|
43
|
+
logEventSchema,
|
|
44
|
+
fatalEventSchema,
|
|
45
|
+
responseSchema,
|
|
46
|
+
mapWireError,
|
|
47
|
+
encodeRequest,
|
|
48
|
+
bunSpawn,
|
|
49
|
+
stdioTransport,
|
|
50
|
+
spawnSimd,
|
|
51
|
+
connectSimd,
|
|
52
|
+
ENV_NAMES,
|
|
53
|
+
DEFAULT_ASSERTION_TIMEOUT_MS,
|
|
54
|
+
readEnv,
|
|
55
|
+
setDefaultHidRecovery,
|
|
56
|
+
setDefaultNativeLog,
|
|
44
57
|
setDefaultDriverFactory,
|
|
58
|
+
hasDefaultDriverFactory,
|
|
45
59
|
setDefaultFixtureFactory,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
hasDefaultFixtureFactory,
|
|
61
|
+
getSession,
|
|
62
|
+
parseBudgets,
|
|
63
|
+
createDevicePerf,
|
|
64
|
+
spawnWarden,
|
|
65
|
+
screenshotPath,
|
|
66
|
+
realNativeLogDeps,
|
|
67
|
+
BUN_TIMEOUT_MARGIN_MS2,
|
|
68
|
+
onlyWasSeen,
|
|
69
|
+
WORKSPACE_VERSION,
|
|
70
|
+
WARDEN_E2E_VERSION2
|
|
71
|
+
} from "./chunk-8em9kgsk.mjs";
|
|
53
72
|
|
|
54
73
|
// ../../packages/e2e/src/preload.ts
|
|
55
74
|
import { afterAll, setDefaultTimeout } from "bun:test";
|
|
56
75
|
|
|
57
|
-
// ../../packages/core/src/exec.ts
|
|
58
|
-
import { existsSync } from "fs";
|
|
59
|
-
function spawnFailure(cmd, cwd, error) {
|
|
60
|
-
if (cwd !== undefined && !existsSync(cwd))
|
|
61
|
-
return `cannot run \`${cmd.join(" ")}\`: no such directory ${cwd}`;
|
|
62
|
-
return `cannot run \`${cmd.join(" ")}\`: ${error instanceof Error ? error.message : String(error)}`;
|
|
63
|
-
}
|
|
64
|
-
var bunExec = async (cmd, opts = {}) => {
|
|
65
|
-
try {
|
|
66
|
-
const proc = Bun.spawn([...cmd], {
|
|
67
|
-
cwd: opts.cwd,
|
|
68
|
-
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
69
|
-
stdout: "pipe",
|
|
70
|
-
stderr: "pipe",
|
|
71
|
-
stdin: "ignore",
|
|
72
|
-
timeout: opts.timeoutMs,
|
|
73
|
-
...opts.signal !== undefined ? { signal: opts.signal } : {}
|
|
74
|
-
});
|
|
75
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
76
|
-
new Response(proc.stdout).text(),
|
|
77
|
-
new Response(proc.stderr).text(),
|
|
78
|
-
proc.exited
|
|
79
|
-
]);
|
|
80
|
-
return { exitCode, stdout, stderr };
|
|
81
|
-
} catch (error) {
|
|
82
|
-
return { exitCode: 127, stdout: "", stderr: spawnFailure(cmd, opts.cwd, error) };
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
function execError(cmd, result) {
|
|
86
|
-
const detail = (result.stderr || result.stdout).trim().split(`
|
|
87
|
-
`).slice(-3).join(" | ");
|
|
88
|
-
return `\`${cmd.join(" ")}\` exited ${result.exitCode}${detail ? `: ${detail}` : ""}`;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
76
|
// ../../packages/core/src/providers/android.ts
|
|
92
77
|
import { join as join2 } from "path";
|
|
93
78
|
|
|
@@ -119,26 +104,6 @@ var avdLists = new WeakMap;
|
|
|
119
104
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
120
105
|
import { dirname as dirname2 } from "path";
|
|
121
106
|
|
|
122
|
-
// ../../packages/e2e/src/driver/errors.ts
|
|
123
|
-
var RETRYABLE = new Set([
|
|
124
|
-
"E_TIMEOUT",
|
|
125
|
-
"E_HELPER_CRASHED",
|
|
126
|
-
"E_AX_UNAVAILABLE",
|
|
127
|
-
"E_APP_NOT_RESPONDING",
|
|
128
|
-
"E_STALE_REF"
|
|
129
|
-
]);
|
|
130
|
-
function driverError(code, message, extra = {}) {
|
|
131
|
-
return {
|
|
132
|
-
code,
|
|
133
|
-
message,
|
|
134
|
-
retryable: extra.retryable ?? RETRYABLE.has(code),
|
|
135
|
-
...extra.detail !== undefined ? { detail: extra.detail } : {}
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
function driverErr(code, message, extra) {
|
|
139
|
-
return { success: false, error: driverError(code, message, extra) };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
107
|
// ../../packages/e2e/src/driver/gesture-geometry.ts
|
|
143
108
|
var GESTURE_FRAME_MS = 16;
|
|
144
109
|
var GESTURE_MAX_FRAMES = 1000;
|
|
@@ -331,14 +296,14 @@ function openAdbSession(options) {
|
|
|
331
296
|
function check(l) {
|
|
332
297
|
if (!current)
|
|
333
298
|
return;
|
|
334
|
-
const
|
|
335
|
-
if (
|
|
299
|
+
const start = l.buffer.indexOf(current.prefix);
|
|
300
|
+
if (start < 0)
|
|
336
301
|
return;
|
|
337
|
-
const afterPrefix =
|
|
302
|
+
const afterPrefix = start + current.prefix.length;
|
|
338
303
|
const m = /^(\d+)__(\r?\n)?/.exec(l.buffer.slice(afterPrefix));
|
|
339
304
|
if (!m)
|
|
340
305
|
return;
|
|
341
|
-
const stdout = l.buffer.slice(0,
|
|
306
|
+
const stdout = l.buffer.slice(0, start);
|
|
342
307
|
l.buffer = l.buffer.slice(afterPrefix + m[0].length);
|
|
343
308
|
const settle = current.settle;
|
|
344
309
|
current = undefined;
|
|
@@ -1231,8 +1196,8 @@ function createDumper(deps) {
|
|
|
1231
1196
|
async function fetchRoute(route) {
|
|
1232
1197
|
if (route === "tty") {
|
|
1233
1198
|
try {
|
|
1234
|
-
const
|
|
1235
|
-
return { text:
|
|
1199
|
+
const res = await deps.exec(dumpTtyHostArgv(deps.adb, deps.serial), { timeoutMs: DUMP_TIMEOUT_MS });
|
|
1200
|
+
return { text: res.stdout };
|
|
1236
1201
|
} catch (error) {
|
|
1237
1202
|
return { error: { code: "E_IO", message: String(error), retryable: false } };
|
|
1238
1203
|
}
|
|
@@ -1283,452 +1248,8 @@ function createDumper(deps) {
|
|
|
1283
1248
|
};
|
|
1284
1249
|
}
|
|
1285
1250
|
|
|
1286
|
-
// ../../packages/e2e/src/driver/ios/simd-protocol.ts
|
|
1287
|
-
import { z as z2 } from "zod";
|
|
1288
|
-
var protocolVersion = 1;
|
|
1289
|
-
var rectSchema = z2.object({
|
|
1290
|
-
x: z2.number(),
|
|
1291
|
-
y: z2.number(),
|
|
1292
|
-
width: z2.number(),
|
|
1293
|
-
height: z2.number()
|
|
1294
|
-
});
|
|
1295
|
-
var screenInfoSchema = z2.object({
|
|
1296
|
-
width: z2.number(),
|
|
1297
|
-
height: z2.number(),
|
|
1298
|
-
scale: z2.number(),
|
|
1299
|
-
rotation: z2.number().optional()
|
|
1300
|
-
});
|
|
1301
|
-
var ROLES = [
|
|
1302
|
-
"button",
|
|
1303
|
-
"text",
|
|
1304
|
-
"textfield",
|
|
1305
|
-
"securefield",
|
|
1306
|
-
"searchfield",
|
|
1307
|
-
"image",
|
|
1308
|
-
"switch",
|
|
1309
|
-
"checkbox",
|
|
1310
|
-
"slider",
|
|
1311
|
-
"link",
|
|
1312
|
-
"cell",
|
|
1313
|
-
"list",
|
|
1314
|
-
"scrollview",
|
|
1315
|
-
"tab",
|
|
1316
|
-
"tabbar",
|
|
1317
|
-
"alert",
|
|
1318
|
-
"sheet",
|
|
1319
|
-
"keyboard",
|
|
1320
|
-
"navbar",
|
|
1321
|
-
"toolbar",
|
|
1322
|
-
"window",
|
|
1323
|
-
"application",
|
|
1324
|
-
"other"
|
|
1325
|
-
];
|
|
1326
|
-
var pointSchema = z2.object({ x: z2.number(), y: z2.number() });
|
|
1327
|
-
var wireElementSchema = z2.lazy(() => z2.object({
|
|
1328
|
-
id: z2.string().nullish(),
|
|
1329
|
-
role: z2.enum(ROLES),
|
|
1330
|
-
rawType: z2.string(),
|
|
1331
|
-
label: z2.string().nullish(),
|
|
1332
|
-
identifier: z2.string().nullish(),
|
|
1333
|
-
value: z2.string().nullish(),
|
|
1334
|
-
text: z2.string().nullish(),
|
|
1335
|
-
placeholder: z2.string().nullish(),
|
|
1336
|
-
frame: rectSchema,
|
|
1337
|
-
normFrame: rectSchema.nullish(),
|
|
1338
|
-
traits: z2.array(z2.string()).nullish(),
|
|
1339
|
-
enabled: z2.boolean().nullish(),
|
|
1340
|
-
focused: z2.boolean().nullish(),
|
|
1341
|
-
hidden: z2.boolean().nullish(),
|
|
1342
|
-
selected: z2.boolean().nullish(),
|
|
1343
|
-
checked: z2.boolean().nullish(),
|
|
1344
|
-
hittable: z2.boolean().nullish(),
|
|
1345
|
-
tapPoint: pointSchema.nullish(),
|
|
1346
|
-
pid: z2.number().nullish(),
|
|
1347
|
-
depth: z2.number().nullish(),
|
|
1348
|
-
children: z2.array(wireElementSchema).nullish()
|
|
1349
|
-
}));
|
|
1350
|
-
var ROLE_SET = new Set(ROLES);
|
|
1351
|
-
var isBag = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1352
|
-
var isNum = (value) => typeof value === "number" && Number.isFinite(value);
|
|
1353
|
-
var isNullish = (value) => value === null || value === undefined;
|
|
1354
|
-
function isRect(value) {
|
|
1355
|
-
return isBag(value) && isNum(value.x) && isNum(value.y) && isNum(value.width) && isNum(value.height);
|
|
1356
|
-
}
|
|
1357
|
-
var OPTIONAL_STRINGS = ["id", "label", "identifier", "value", "text", "placeholder"];
|
|
1358
|
-
var OPTIONAL_FLAGS = ["enabled", "focused", "hidden", "selected", "checked", "hittable"];
|
|
1359
|
-
var isString = (value) => typeof value === "string";
|
|
1360
|
-
var isBool = (value) => typeof value === "boolean";
|
|
1361
|
-
var isPoint = (value) => isBag(value) && isNum(value.x) && isNum(value.y);
|
|
1362
|
-
var isStringArray = (value) => Array.isArray(value) && value.every(isString);
|
|
1363
|
-
var orNullish = (value, check) => isNullish(value) || check(value);
|
|
1364
|
-
function hasValidOptionals(node) {
|
|
1365
|
-
return OPTIONAL_STRINGS.every((key) => orNullish(node[key], isString)) && OPTIONAL_FLAGS.every((key) => orNullish(node[key], isBool)) && orNullish(node.normFrame, isRect) && orNullish(node.traits, isStringArray) && orNullish(node.tapPoint, isPoint) && orNullish(node.pid, isNum) && orNullish(node.depth, isNum);
|
|
1366
|
-
}
|
|
1367
|
-
function isWireElement(value) {
|
|
1368
|
-
if (!isBag(value))
|
|
1369
|
-
return false;
|
|
1370
|
-
if (!isString(value.role) || !ROLE_SET.has(value.role))
|
|
1371
|
-
return false;
|
|
1372
|
-
if (!isString(value.rawType) || !isRect(value.frame) || !hasValidOptionals(value))
|
|
1373
|
-
return false;
|
|
1374
|
-
const { children } = value;
|
|
1375
|
-
if (isNullish(children))
|
|
1376
|
-
return true;
|
|
1377
|
-
return Array.isArray(children) && children.every(isWireElement);
|
|
1378
|
-
}
|
|
1379
|
-
function wireElementProblem(value) {
|
|
1380
|
-
const parsed = wireElementSchema.safeParse(value);
|
|
1381
|
-
if (parsed.success)
|
|
1382
|
-
return "invalid element";
|
|
1383
|
-
const issue = parsed.error.issues[0];
|
|
1384
|
-
return issue ? `${issue.path.join(".") || "(element)"}: ${issue.message}` : "invalid element";
|
|
1385
|
-
}
|
|
1386
|
-
var wireErrorSchema = z2.object({
|
|
1387
|
-
code: z2.string(),
|
|
1388
|
-
message: z2.string(),
|
|
1389
|
-
retryable: z2.boolean().optional(),
|
|
1390
|
-
detail: z2.unknown().optional()
|
|
1391
|
-
});
|
|
1392
|
-
var readyEventSchema = z2.object({
|
|
1393
|
-
event: z2.literal("ready"),
|
|
1394
|
-
protocol: z2.number(),
|
|
1395
|
-
version: z2.string(),
|
|
1396
|
-
udid: z2.string(),
|
|
1397
|
-
hid: z2.object({ transport: z2.string() }),
|
|
1398
|
-
ax: z2.object({ default: z2.string(), bridge: z2.string() }),
|
|
1399
|
-
screen: screenInfoSchema
|
|
1400
|
-
});
|
|
1401
|
-
var logEventSchema = z2.object({
|
|
1402
|
-
event: z2.literal("log"),
|
|
1403
|
-
level: z2.enum(["debug", "info", "warn", "error"]),
|
|
1404
|
-
message: z2.string(),
|
|
1405
|
-
op: z2.string().optional(),
|
|
1406
|
-
id: z2.string().optional()
|
|
1407
|
-
});
|
|
1408
|
-
var fatalEventSchema = z2.object({ event: z2.literal("fatal"), error: wireErrorSchema });
|
|
1409
|
-
var eventSchema = z2.discriminatedUnion("event", [readyEventSchema, logEventSchema, fatalEventSchema]);
|
|
1410
|
-
var responseSchema = z2.discriminatedUnion("ok", [
|
|
1411
|
-
z2.object({ id: z2.string(), ok: z2.literal(true), data: z2.unknown().optional() }),
|
|
1412
|
-
z2.object({ id: z2.string(), ok: z2.literal(false), error: wireErrorSchema })
|
|
1413
|
-
]);
|
|
1414
|
-
function parseLine(line) {
|
|
1415
|
-
let json;
|
|
1416
|
-
try {
|
|
1417
|
-
json = JSON.parse(line);
|
|
1418
|
-
} catch {
|
|
1419
|
-
return { success: false, reason: "not JSON" };
|
|
1420
|
-
}
|
|
1421
|
-
if (typeof json === "object" && json !== null && "event" in json) {
|
|
1422
|
-
const event = eventSchema.safeParse(json);
|
|
1423
|
-
return event.success ? { success: true, message: { kind: "event", event: event.data } } : { success: false, reason: `bad event: ${event.error.message}` };
|
|
1424
|
-
}
|
|
1425
|
-
const response = responseSchema.safeParse(json);
|
|
1426
|
-
return response.success ? { success: true, message: { kind: "response", response: response.data } } : { success: false, reason: `bad response: ${response.error.message}` };
|
|
1427
|
-
}
|
|
1428
|
-
var healthDataSchema = z2.looseObject({
|
|
1429
|
-
version: z2.string(),
|
|
1430
|
-
udid: z2.string(),
|
|
1431
|
-
hid: z2.object({ transport: z2.string() }),
|
|
1432
|
-
ax: z2.object({
|
|
1433
|
-
default: z2.string(),
|
|
1434
|
-
bridge: z2.enum(["available", "degraded", "missing", "failed"]),
|
|
1435
|
-
error: z2.string().optional(),
|
|
1436
|
-
lastError: z2.object({ message: z2.string(), agoMs: z2.number() }).optional()
|
|
1437
|
-
}),
|
|
1438
|
-
screen: screenInfoSchema,
|
|
1439
|
-
socket: z2.object({ path: z2.string(), clients: z2.number() }).optional(),
|
|
1440
|
-
idb: z2.string().optional(),
|
|
1441
|
-
xcode: z2.string().optional(),
|
|
1442
|
-
state: z2.string().optional(),
|
|
1443
|
-
uptimeMs: z2.number().optional()
|
|
1444
|
-
});
|
|
1445
|
-
var snapshotDataSchema = z2.looseObject({
|
|
1446
|
-
backend: z2.enum(["axbridge", "ax", "uiautomator"]),
|
|
1447
|
-
screen: screenInfoSchema,
|
|
1448
|
-
modal: z2.object({ pid: z2.number().optional(), description: z2.string().optional() }).nullish(),
|
|
1449
|
-
truncated: z2.boolean(),
|
|
1450
|
-
elements: z2.array(z2.custom(isWireElement, { error: (issue) => wireElementProblem(issue.input) })),
|
|
1451
|
-
ms: z2.number(),
|
|
1452
|
-
fallback: z2.object({ from: z2.string(), to: z2.string(), reason: z2.string() }).optional(),
|
|
1453
|
-
readMs: z2.number().optional(),
|
|
1454
|
-
nodes: z2.number().optional()
|
|
1455
|
-
});
|
|
1456
|
-
var elementAtPointDataSchema = wireElementSchema.nullable();
|
|
1457
|
-
var screenshotDataSchema = z2.looseObject({
|
|
1458
|
-
path: z2.string().optional(),
|
|
1459
|
-
png: z2.string().optional(),
|
|
1460
|
-
width: z2.number().optional(),
|
|
1461
|
-
height: z2.number().optional()
|
|
1462
|
-
});
|
|
1463
|
-
var settleDataSchema = z2.looseObject({
|
|
1464
|
-
quiet: z2.boolean(),
|
|
1465
|
-
waitedMs: z2.number(),
|
|
1466
|
-
via: z2.enum(["stream", "snapshot"]).optional().catch(undefined),
|
|
1467
|
-
reason: z2.string().optional(),
|
|
1468
|
-
frontmostPid: z2.number().optional()
|
|
1469
|
-
});
|
|
1470
|
-
var rebindDataSchema = z2.looseObject({
|
|
1471
|
-
bound: z2.boolean(),
|
|
1472
|
-
waitedMs: z2.number(),
|
|
1473
|
-
pid: z2.number().optional(),
|
|
1474
|
-
restarts: z2.number().optional(),
|
|
1475
|
-
recycled: z2.boolean().optional(),
|
|
1476
|
-
reason: z2.string().optional()
|
|
1477
|
-
});
|
|
1478
|
-
var alertButtonsDataSchema = z2.object({
|
|
1479
|
-
title: z2.string().optional(),
|
|
1480
|
-
message: z2.string().optional(),
|
|
1481
|
-
buttons: z2.array(wireElementSchema)
|
|
1482
|
-
}).nullable();
|
|
1483
|
-
var frontmostDataSchema = z2.looseObject({
|
|
1484
|
-
frontmost: z2.boolean(),
|
|
1485
|
-
pid: z2.number().optional(),
|
|
1486
|
-
frontmostPid: z2.number().optional()
|
|
1487
|
-
});
|
|
1488
|
-
var orientationDataSchema = z2.object({
|
|
1489
|
-
orientation: z2.enum([
|
|
1490
|
-
"portrait",
|
|
1491
|
-
"portraitUpsideDown",
|
|
1492
|
-
"landscapeLeft",
|
|
1493
|
-
"landscapeRight",
|
|
1494
|
-
"faceUp",
|
|
1495
|
-
"faceDown",
|
|
1496
|
-
"unknown"
|
|
1497
|
-
]),
|
|
1498
|
-
source: z2.enum(["device", "written", "assumed"]).optional()
|
|
1499
|
-
});
|
|
1500
|
-
var opSchemas = {
|
|
1501
|
-
health: healthDataSchema,
|
|
1502
|
-
snapshot: snapshotDataSchema,
|
|
1503
|
-
elementAtPoint: elementAtPointDataSchema,
|
|
1504
|
-
screenshot: screenshotDataSchema,
|
|
1505
|
-
settle: settleDataSchema,
|
|
1506
|
-
rebind: rebindDataSchema,
|
|
1507
|
-
alertButtons: alertButtonsDataSchema,
|
|
1508
|
-
frontmost: frontmostDataSchema,
|
|
1509
|
-
orientation: orientationDataSchema
|
|
1510
|
-
};
|
|
1511
|
-
function hasOpSchema(op) {
|
|
1512
|
-
return Object.hasOwn(opSchemas, op);
|
|
1513
|
-
}
|
|
1514
|
-
var DRIVER_CODES = new Set([
|
|
1515
|
-
"E_HELPER_MISSING",
|
|
1516
|
-
"E_HELPER_CRASHED",
|
|
1517
|
-
"E_TIMEOUT",
|
|
1518
|
-
"E_NOT_BOOTED",
|
|
1519
|
-
"E_UNKNOWN_DEVICE",
|
|
1520
|
-
"E_AX_UNAVAILABLE",
|
|
1521
|
-
"E_APP_UNAVAILABLE",
|
|
1522
|
-
"E_APP_NOT_RESPONDING",
|
|
1523
|
-
"E_NO_ELEMENT",
|
|
1524
|
-
"E_STALE_REF",
|
|
1525
|
-
"E_UNSUPPORTED",
|
|
1526
|
-
"E_UNSUPPORTED_TEXT",
|
|
1527
|
-
"E_HID",
|
|
1528
|
-
"E_IO",
|
|
1529
|
-
"E_BAD_REQUEST",
|
|
1530
|
-
"E_INTERNAL"
|
|
1531
|
-
]);
|
|
1532
|
-
function isDriverCode(code) {
|
|
1533
|
-
return DRIVER_CODES.has(code);
|
|
1534
|
-
}
|
|
1535
|
-
function mapWireError(wire) {
|
|
1536
|
-
const retryable = wire.retryable === undefined ? {} : { retryable: wire.retryable };
|
|
1537
|
-
if (wire.code === "E_UNKNOWN_UDID") {
|
|
1538
|
-
return driverError("E_UNKNOWN_DEVICE", wire.message, { ...retryable, detail: wire.detail });
|
|
1539
|
-
}
|
|
1540
|
-
if (isDriverCode(wire.code))
|
|
1541
|
-
return driverError(wire.code, wire.message, { ...retryable, detail: wire.detail });
|
|
1542
|
-
return driverError("E_INTERNAL", wire.message, {
|
|
1543
|
-
...retryable,
|
|
1544
|
-
detail: { wireCode: wire.code, ...wire.detail !== undefined ? { wireDetail: wire.detail } : {} }
|
|
1545
|
-
});
|
|
1546
|
-
}
|
|
1547
|
-
function createLineSplitter() {
|
|
1548
|
-
const decoder = new TextDecoder("utf-8");
|
|
1549
|
-
let buffer = "";
|
|
1550
|
-
return {
|
|
1551
|
-
push(chunk) {
|
|
1552
|
-
buffer += decoder.decode(chunk, { stream: true });
|
|
1553
|
-
const lines = buffer.split(`
|
|
1554
|
-
`);
|
|
1555
|
-
buffer = lines.pop() ?? "";
|
|
1556
|
-
return lines.map((line) => line.endsWith("\r") ? line.slice(0, -1) : line).filter((line) => line.length > 0);
|
|
1557
|
-
},
|
|
1558
|
-
rest: () => buffer
|
|
1559
|
-
};
|
|
1560
|
-
}
|
|
1561
|
-
function encodeRequest(request) {
|
|
1562
|
-
return `${JSON.stringify(request)}
|
|
1563
|
-
`;
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
// ../../packages/e2e/src/driver/ios/simd-transport.ts
|
|
1567
|
-
var bunSpawn = (cmd) => {
|
|
1568
|
-
const proc = Bun.spawn([...cmd], { stdin: "pipe", stdout: "pipe", stderr: "pipe" });
|
|
1569
|
-
return {
|
|
1570
|
-
write(data) {
|
|
1571
|
-
proc.stdin.write(data);
|
|
1572
|
-
proc.stdin.flush();
|
|
1573
|
-
},
|
|
1574
|
-
end() {
|
|
1575
|
-
proc.stdin.end();
|
|
1576
|
-
},
|
|
1577
|
-
kill() {
|
|
1578
|
-
proc.kill();
|
|
1579
|
-
},
|
|
1580
|
-
stdout: proc.stdout,
|
|
1581
|
-
stderr: proc.stderr,
|
|
1582
|
-
exited: proc.exited
|
|
1583
|
-
};
|
|
1584
|
-
};
|
|
1585
|
-
async function pump(stream, onLine) {
|
|
1586
|
-
const splitter = createLineSplitter();
|
|
1587
|
-
const reader = stream.getReader();
|
|
1588
|
-
try {
|
|
1589
|
-
for (;; ) {
|
|
1590
|
-
const { done, value } = await reader.read();
|
|
1591
|
-
if (done)
|
|
1592
|
-
break;
|
|
1593
|
-
for (const line of splitter.push(value))
|
|
1594
|
-
onLine(line);
|
|
1595
|
-
}
|
|
1596
|
-
} catch {}
|
|
1597
|
-
const rest = splitter.rest().trim();
|
|
1598
|
-
if (rest)
|
|
1599
|
-
onLine(rest);
|
|
1600
|
-
}
|
|
1601
|
-
var STDERR_TAIL = 20;
|
|
1602
|
-
var DEFAULT_GRACE_MS = 1500;
|
|
1603
|
-
function stdioTransport(opts) {
|
|
1604
|
-
const spawn = opts.spawn ?? bunSpawn;
|
|
1605
|
-
const graceMs = opts.graceMs ?? DEFAULT_GRACE_MS;
|
|
1606
|
-
return async (handlers) => {
|
|
1607
|
-
let proc;
|
|
1608
|
-
try {
|
|
1609
|
-
proc = spawn(opts.cmd);
|
|
1610
|
-
} catch (error) {
|
|
1611
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
1612
|
-
return {
|
|
1613
|
-
success: false,
|
|
1614
|
-
error: driverError("E_HELPER_MISSING", `cannot start ${opts.cmd[0]}: ${reason}`, {
|
|
1615
|
-
detail: { cmd: opts.cmd }
|
|
1616
|
-
})
|
|
1617
|
-
};
|
|
1618
|
-
}
|
|
1619
|
-
const stderrTail = [];
|
|
1620
|
-
const stdout = pump(proc.stdout, handlers.onLine);
|
|
1621
|
-
const stderr = proc.stderr ? pump(proc.stderr, (line) => {
|
|
1622
|
-
stderrTail.push(line);
|
|
1623
|
-
if (stderrTail.length > STDERR_TAIL)
|
|
1624
|
-
stderrTail.shift();
|
|
1625
|
-
handlers.onDiagnostic(line);
|
|
1626
|
-
}) : Promise.resolve();
|
|
1627
|
-
const exited = proc.exited.catch(() => -1);
|
|
1628
|
-
Promise.all([stdout, stderr, exited]).then(([, , exitCode]) => {
|
|
1629
|
-
handlers.onClose({ exitCode, stderrTail: [...stderrTail] });
|
|
1630
|
-
});
|
|
1631
|
-
return {
|
|
1632
|
-
success: true,
|
|
1633
|
-
data: {
|
|
1634
|
-
send: (data) => proc.write(data),
|
|
1635
|
-
async close() {
|
|
1636
|
-
try {
|
|
1637
|
-
proc.end();
|
|
1638
|
-
} catch {}
|
|
1639
|
-
let timer;
|
|
1640
|
-
const timedOut = new Promise((resolve) => {
|
|
1641
|
-
timer = setTimeout(() => resolve("timeout"), graceMs);
|
|
1642
|
-
});
|
|
1643
|
-
const outcome = await Promise.race([exited.then(() => "exited"), timedOut]);
|
|
1644
|
-
clearTimeout(timer);
|
|
1645
|
-
if (outcome === "timeout") {
|
|
1646
|
-
proc.kill();
|
|
1647
|
-
await exited;
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
};
|
|
1652
|
-
};
|
|
1653
|
-
}
|
|
1654
|
-
function socketTransport(opts) {
|
|
1655
|
-
return async (handlers) => {
|
|
1656
|
-
const splitter = createLineSplitter();
|
|
1657
|
-
const encoder = new TextEncoder;
|
|
1658
|
-
let socket;
|
|
1659
|
-
let queued = new Uint8Array(0);
|
|
1660
|
-
let closedNotified = false;
|
|
1661
|
-
const notifyClosed = () => {
|
|
1662
|
-
if (closedNotified)
|
|
1663
|
-
return;
|
|
1664
|
-
closedNotified = true;
|
|
1665
|
-
handlers.onClose({ exitCode: null, stderrTail: [] });
|
|
1666
|
-
};
|
|
1667
|
-
const flush = () => {
|
|
1668
|
-
if (!socket || queued.length === 0)
|
|
1669
|
-
return;
|
|
1670
|
-
const written = socket.write(queued);
|
|
1671
|
-
queued = written >= queued.length ? new Uint8Array(0) : queued.slice(Math.max(written, 0));
|
|
1672
|
-
};
|
|
1673
|
-
try {
|
|
1674
|
-
const connected = await Bun.connect({
|
|
1675
|
-
unix: opts.socketPath,
|
|
1676
|
-
socket: {
|
|
1677
|
-
open(s) {
|
|
1678
|
-
socket = s;
|
|
1679
|
-
},
|
|
1680
|
-
data(_s, chunk) {
|
|
1681
|
-
for (const line of splitter.push(chunk))
|
|
1682
|
-
handlers.onLine(line);
|
|
1683
|
-
},
|
|
1684
|
-
drain() {
|
|
1685
|
-
flush();
|
|
1686
|
-
},
|
|
1687
|
-
close() {
|
|
1688
|
-
notifyClosed();
|
|
1689
|
-
},
|
|
1690
|
-
error() {
|
|
1691
|
-
notifyClosed();
|
|
1692
|
-
},
|
|
1693
|
-
end() {
|
|
1694
|
-
notifyClosed();
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
});
|
|
1698
|
-
socket = connected;
|
|
1699
|
-
} catch (error) {
|
|
1700
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
1701
|
-
return {
|
|
1702
|
-
success: false,
|
|
1703
|
-
error: driverError("E_HELPER_CRASHED", `cannot connect to warden-simd socket ${opts.socketPath}: ${reason}`, {
|
|
1704
|
-
detail: { socketPath: opts.socketPath }
|
|
1705
|
-
})
|
|
1706
|
-
};
|
|
1707
|
-
}
|
|
1708
|
-
return {
|
|
1709
|
-
success: true,
|
|
1710
|
-
data: {
|
|
1711
|
-
send(data) {
|
|
1712
|
-
const bytes = encoder.encode(data);
|
|
1713
|
-
const merged = new Uint8Array(queued.length + bytes.length);
|
|
1714
|
-
merged.set(queued, 0);
|
|
1715
|
-
merged.set(bytes, queued.length);
|
|
1716
|
-
queued = merged;
|
|
1717
|
-
flush();
|
|
1718
|
-
},
|
|
1719
|
-
async close() {
|
|
1720
|
-
try {
|
|
1721
|
-
socket?.end();
|
|
1722
|
-
} catch {}
|
|
1723
|
-
notifyClosed();
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
};
|
|
1727
|
-
};
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
1251
|
// ../../packages/e2e/src/driver/android/uiad-protocol.ts
|
|
1731
|
-
import { z as
|
|
1252
|
+
import { z as z2 } from "zod";
|
|
1732
1253
|
var UIAD_PROTOCOL = 1;
|
|
1733
1254
|
var UIAD_MAIN_CLASS = "nz.co.delacour.warden.uiad.Main";
|
|
1734
1255
|
var STRING_FIELDS = ["class", "pkg", "id", "text", "desc", "hint"];
|
|
@@ -1786,48 +1307,48 @@ function readNode(value, path = "elements") {
|
|
|
1786
1307
|
node.children = children;
|
|
1787
1308
|
return node;
|
|
1788
1309
|
}
|
|
1789
|
-
var screenSchema =
|
|
1790
|
-
width:
|
|
1791
|
-
height:
|
|
1792
|
-
scale:
|
|
1793
|
-
rotation:
|
|
1310
|
+
var screenSchema = z2.object({
|
|
1311
|
+
width: z2.number(),
|
|
1312
|
+
height: z2.number(),
|
|
1313
|
+
scale: z2.number().optional(),
|
|
1314
|
+
rotation: z2.number().optional()
|
|
1794
1315
|
});
|
|
1795
|
-
var healthSchema =
|
|
1796
|
-
version:
|
|
1797
|
-
protocol:
|
|
1798
|
-
sdk:
|
|
1799
|
-
release:
|
|
1800
|
-
model:
|
|
1801
|
-
uid:
|
|
1802
|
-
pid:
|
|
1803
|
-
uiAutomation:
|
|
1804
|
-
events:
|
|
1805
|
-
uptimeMs:
|
|
1316
|
+
var healthSchema = z2.looseObject({
|
|
1317
|
+
version: z2.string(),
|
|
1318
|
+
protocol: z2.number(),
|
|
1319
|
+
sdk: z2.number(),
|
|
1320
|
+
release: z2.string().optional(),
|
|
1321
|
+
model: z2.string().optional(),
|
|
1322
|
+
uid: z2.number().optional(),
|
|
1323
|
+
pid: z2.number().optional(),
|
|
1324
|
+
uiAutomation: z2.looseObject({ state: z2.string(), connect: z2.string().optional(), connectMs: z2.number().optional() }),
|
|
1325
|
+
events: z2.looseObject({ count: z2.number(), lastAgoMs: z2.number() }).optional(),
|
|
1326
|
+
uptimeMs: z2.number().optional(),
|
|
1806
1327
|
screen: screenSchema.optional(),
|
|
1807
|
-
displayError:
|
|
1328
|
+
displayError: z2.string().optional()
|
|
1808
1329
|
});
|
|
1809
|
-
var
|
|
1810
|
-
quiet:
|
|
1811
|
-
waitedMs:
|
|
1812
|
-
via:
|
|
1813
|
-
events:
|
|
1814
|
-
firstEventMs:
|
|
1815
|
-
reason:
|
|
1330
|
+
var settleDataSchema = z2.looseObject({
|
|
1331
|
+
quiet: z2.boolean(),
|
|
1332
|
+
waitedMs: z2.number(),
|
|
1333
|
+
via: z2.literal("events"),
|
|
1334
|
+
events: z2.number(),
|
|
1335
|
+
firstEventMs: z2.number().optional(),
|
|
1336
|
+
reason: z2.string().optional()
|
|
1816
1337
|
});
|
|
1817
|
-
var textDataSchema =
|
|
1818
|
-
text:
|
|
1819
|
-
caret:
|
|
1820
|
-
caretPlaced:
|
|
1338
|
+
var textDataSchema = z2.looseObject({
|
|
1339
|
+
text: z2.string(),
|
|
1340
|
+
caret: z2.number().optional(),
|
|
1341
|
+
caretPlaced: z2.boolean().optional()
|
|
1821
1342
|
});
|
|
1822
|
-
var snapshotEnvelope =
|
|
1823
|
-
backend:
|
|
1343
|
+
var snapshotEnvelope = z2.looseObject({
|
|
1344
|
+
backend: z2.literal("uiad"),
|
|
1824
1345
|
screen: screenSchema,
|
|
1825
|
-
windows:
|
|
1826
|
-
elements:
|
|
1827
|
-
truncated:
|
|
1828
|
-
nodes:
|
|
1829
|
-
readMs:
|
|
1830
|
-
ms:
|
|
1346
|
+
windows: z2.array(z2.unknown()).optional(),
|
|
1347
|
+
elements: z2.array(z2.unknown()),
|
|
1348
|
+
truncated: z2.boolean(),
|
|
1349
|
+
nodes: z2.number(),
|
|
1350
|
+
readMs: z2.number(),
|
|
1351
|
+
ms: z2.number()
|
|
1831
1352
|
});
|
|
1832
1353
|
function readSnapshotData(data) {
|
|
1833
1354
|
const envelope = snapshotEnvelope.safeParse(data);
|
|
@@ -1844,13 +1365,13 @@ function readSnapshotData(data) {
|
|
|
1844
1365
|
}
|
|
1845
1366
|
return { ...envelope.data, elements };
|
|
1846
1367
|
}
|
|
1847
|
-
var
|
|
1848
|
-
event:
|
|
1849
|
-
protocol:
|
|
1850
|
-
version:
|
|
1368
|
+
var readyEventSchema = z2.object({
|
|
1369
|
+
event: z2.literal("ready"),
|
|
1370
|
+
protocol: z2.number(),
|
|
1371
|
+
version: z2.string(),
|
|
1851
1372
|
data: healthSchema
|
|
1852
1373
|
});
|
|
1853
|
-
var
|
|
1374
|
+
var eventSchema = z2.discriminatedUnion("event", [readyEventSchema, logEventSchema, fatalEventSchema]);
|
|
1854
1375
|
function parseUiadLine(line) {
|
|
1855
1376
|
let json;
|
|
1856
1377
|
try {
|
|
@@ -1859,7 +1380,7 @@ function parseUiadLine(line) {
|
|
|
1859
1380
|
return { success: false, reason: "not JSON" };
|
|
1860
1381
|
}
|
|
1861
1382
|
if (isRecord(json) && "event" in json) {
|
|
1862
|
-
const event =
|
|
1383
|
+
const event = eventSchema.safeParse(json);
|
|
1863
1384
|
return event.success ? { success: true, message: { kind: "event", event: event.data } } : { success: false, reason: `bad event: ${event.error.message}` };
|
|
1864
1385
|
}
|
|
1865
1386
|
const response = responseSchema.safeParse(json);
|
|
@@ -1869,7 +1390,7 @@ function parseUiadLine(line) {
|
|
|
1869
1390
|
// ../../packages/e2e/src/driver/android/uiad-client.ts
|
|
1870
1391
|
var DEFAULT_READY_TIMEOUT_MS2 = 5000;
|
|
1871
1392
|
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
1872
|
-
var
|
|
1393
|
+
var DEFAULT_GRACE_MS = 1000;
|
|
1873
1394
|
var SHUTDOWN_WAIT_MS = 300;
|
|
1874
1395
|
var NOT_SENT = { sent: false };
|
|
1875
1396
|
function schemaReader(schema) {
|
|
@@ -1966,7 +1487,7 @@ async function startUiad(options) {
|
|
|
1966
1487
|
const factory = stdioTransport({
|
|
1967
1488
|
cmd: options.cmd,
|
|
1968
1489
|
...options.spawn ? { spawn: options.spawn } : { spawn: bunSpawn },
|
|
1969
|
-
graceMs: options.graceMs ??
|
|
1490
|
+
graceMs: options.graceMs ?? DEFAULT_GRACE_MS
|
|
1970
1491
|
});
|
|
1971
1492
|
const waiting = new Promise((resolve) => {
|
|
1972
1493
|
settleHandshake = (result) => {
|
|
@@ -2044,7 +1565,7 @@ async function startUiad(options) {
|
|
|
2044
1565
|
return through(await request("snapshot", { ...params }, opts), readSnapshot, "snapshot");
|
|
2045
1566
|
},
|
|
2046
1567
|
async settle(params) {
|
|
2047
|
-
return through(await request("settle", params, { timeoutMs: params.timeoutMs + requestTimeoutMs }), schemaReader(
|
|
1568
|
+
return through(await request("settle", params, { timeoutMs: params.timeoutMs + requestTimeoutMs }), schemaReader(settleDataSchema), "settle");
|
|
2048
1569
|
},
|
|
2049
1570
|
async typeText(text) {
|
|
2050
1571
|
return through(await request("typeText", { text }), schemaReader(textDataSchema), "typeText");
|
|
@@ -2126,12 +1647,12 @@ function uiadPresentCommand(devicePath, bytes) {
|
|
|
2126
1647
|
var bunPushDex = async (argv, bytes) => {
|
|
2127
1648
|
try {
|
|
2128
1649
|
const proc = Bun.spawn([...argv], { stdin: bytes, stdout: "pipe", stderr: "pipe", timeout: 15000 });
|
|
2129
|
-
const [out,
|
|
1650
|
+
const [out, err, exitCode] = await Promise.all([
|
|
2130
1651
|
new Response(proc.stdout).text(),
|
|
2131
1652
|
new Response(proc.stderr).text(),
|
|
2132
1653
|
proc.exited
|
|
2133
1654
|
]);
|
|
2134
|
-
return { exitCode, output: `${out}${
|
|
1655
|
+
return { exitCode, output: `${out}${err}`.trim() };
|
|
2135
1656
|
} catch (error) {
|
|
2136
1657
|
return { exitCode: 127, output: error instanceof Error ? error.message : String(error) };
|
|
2137
1658
|
}
|
|
@@ -3062,9 +2583,9 @@ function buildDriver(options, session, baseScreen, clock, execBinary, facts) {
|
|
|
3062
2583
|
const orientation = async (set) => {
|
|
3063
2584
|
if (set) {
|
|
3064
2585
|
for (const argv of rotationArgvs(orientationToRotation(set))) {
|
|
3065
|
-
const
|
|
3066
|
-
if (!
|
|
3067
|
-
return
|
|
2586
|
+
const res = await input(shellCommand(argv));
|
|
2587
|
+
if (!res.success)
|
|
2588
|
+
return res;
|
|
3068
2589
|
}
|
|
3069
2590
|
return { success: true, data: set };
|
|
3070
2591
|
}
|
|
@@ -3111,8 +2632,8 @@ function buildDriver(options, session, baseScreen, clock, execBinary, facts) {
|
|
|
3111
2632
|
};
|
|
3112
2633
|
const appearance = async (set) => {
|
|
3113
2634
|
if (set) {
|
|
3114
|
-
const
|
|
3115
|
-
return
|
|
2635
|
+
const res = await runChecked(session, shellCommand(uimodeSetArgv(set === "dark")), "E_UNSUPPORTED");
|
|
2636
|
+
return res.success ? { success: true, data: set } : res;
|
|
3116
2637
|
}
|
|
3117
2638
|
const res = await runChecked(session, shellCommand(uimodeGetArgv()), "E_UNSUPPORTED");
|
|
3118
2639
|
if (!res.success)
|
|
@@ -3121,12 +2642,12 @@ function buildDriver(options, session, baseScreen, clock, execBinary, facts) {
|
|
|
3121
2642
|
};
|
|
3122
2643
|
const clipboard = async () => driverErr("E_UNSUPPORTED", "Android has no public shell clipboard access; type ASCII with typeText");
|
|
3123
2644
|
const health = async () => {
|
|
3124
|
-
const [release,
|
|
2645
|
+
const [release, sdk, model] = await Promise.all(["ro.build.version.release", "ro.build.version.sdk", "ro.product.model"].map((k) => session.run(shellCommand(getpropArgv(k)))));
|
|
3125
2646
|
const text = (r) => r?.success ? r.data.stdout.trim() : "";
|
|
3126
2647
|
const info = {
|
|
3127
2648
|
platform: "android",
|
|
3128
2649
|
id: serial,
|
|
3129
|
-
version: `Android ${text(release)} (sdk ${text(
|
|
2650
|
+
version: `Android ${text(release)} (sdk ${text(sdk)})`,
|
|
3130
2651
|
transport: "adb",
|
|
3131
2652
|
screen: baseScreen,
|
|
3132
2653
|
detail: { model: text(model), dumpRoute: dumper.route() ?? null, uiad: uiad?.status() ?? "off" }
|
|
@@ -3159,7 +2680,7 @@ function buildDriver(options, session, baseScreen, clock, execBinary, facts) {
|
|
|
3159
2680
|
orientation,
|
|
3160
2681
|
settle,
|
|
3161
2682
|
alert,
|
|
3162
|
-
alertIn: (
|
|
2683
|
+
alertIn: (snapshot) => detectAlert(snapshot.flat),
|
|
3163
2684
|
appearance,
|
|
3164
2685
|
clipboard,
|
|
3165
2686
|
app: createAppCommands({
|
|
@@ -3180,7 +2701,7 @@ function buildDriver(options, session, baseScreen, clock, execBinary, facts) {
|
|
|
3180
2701
|
}
|
|
3181
2702
|
|
|
3182
2703
|
// ../../packages/e2e/src/driver/ios/ios-driver.ts
|
|
3183
|
-
import { existsSync as
|
|
2704
|
+
import { existsSync as existsSync2 } from "fs";
|
|
3184
2705
|
import { dirname as dirname4, join as join6 } from "path";
|
|
3185
2706
|
|
|
3186
2707
|
// ../../packages/e2e/src/driver/ios/ios-session.ts
|
|
@@ -3235,7 +2756,7 @@ function swappableClient(initial, o) {
|
|
|
3235
2756
|
}
|
|
3236
2757
|
|
|
3237
2758
|
// ../../packages/e2e/src/driver/ios/locate-helper.ts
|
|
3238
|
-
import { existsSync
|
|
2759
|
+
import { existsSync, realpathSync } from "fs";
|
|
3239
2760
|
import { dirname as dirname3, join as join4, resolve } from "path";
|
|
3240
2761
|
var HELPER_NAME = "warden-simd";
|
|
3241
2762
|
var DOCTOR_HINT = "run `warden doctor` to check the iOS driver helper, or set WARDEN_SIMD=/path/to/warden-simd";
|
|
@@ -3286,7 +2807,7 @@ function resolveHelper(o) {
|
|
|
3286
2807
|
execPath: o.execPath ?? process.execPath,
|
|
3287
2808
|
importDir: o.importDir ?? import.meta.dir,
|
|
3288
2809
|
wardenHome: o.wardenHome ?? wardenHome(),
|
|
3289
|
-
exists: o.exists ??
|
|
2810
|
+
exists: o.exists ?? existsSync,
|
|
3290
2811
|
realpath: o.realpath ?? realpathSync,
|
|
3291
2812
|
...o.version ? { version: o.version } : {}
|
|
3292
2813
|
});
|
|
@@ -3554,6 +3075,20 @@ var statusBarClearArgv = (udid) => [...XCRUN, "status_bar", udid, "clear"];
|
|
|
3554
3075
|
function pbcopyArgv(udid, text) {
|
|
3555
3076
|
return ["sh", "-c", 'printf %s "$1" | xcrun simctl pbcopy "$2"', "sh", text, udid];
|
|
3556
3077
|
}
|
|
3078
|
+
function devicectlPbcopyArgv(udid, text) {
|
|
3079
|
+
return [
|
|
3080
|
+
"sh",
|
|
3081
|
+
"-c",
|
|
3082
|
+
'printf %s "$1" | xcrun devicectl device pasteboard copy --quiet --device "$2"',
|
|
3083
|
+
"sh",
|
|
3084
|
+
text,
|
|
3085
|
+
udid
|
|
3086
|
+
];
|
|
3087
|
+
}
|
|
3088
|
+
var PBCOPY_CHANNELS = [
|
|
3089
|
+
{ name: "devicectl pasteboard copy", argv: devicectlPbcopyArgv },
|
|
3090
|
+
{ name: "simctl pbcopy", argv: pbcopyArgv }
|
|
3091
|
+
];
|
|
3557
3092
|
function escapeRegExp(text) {
|
|
3558
3093
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3559
3094
|
}
|
|
@@ -3645,7 +3180,26 @@ function createSimctl(deps) {
|
|
|
3645
3180
|
const code = /is not installed/.test(reset.error) ? "E_APP_UNAVAILABLE" : "E_IO";
|
|
3646
3181
|
return { success: false, error: driverError(code, reset.error) };
|
|
3647
3182
|
},
|
|
3648
|
-
pbcopy
|
|
3183
|
+
async pbcopy(text) {
|
|
3184
|
+
const outcomes = [];
|
|
3185
|
+
for (const channel of PBCOPY_CHANNELS) {
|
|
3186
|
+
const copied = await exec(channel.argv(udid, text), { timeoutMs: SHORT_MS });
|
|
3187
|
+
if (copied.exitCode !== 0) {
|
|
3188
|
+
outcomes.push(`${channel.name} exit ${copied.exitCode}`);
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
3191
|
+
const read = await run(pbpasteArgv(udid), SHORT_MS);
|
|
3192
|
+
if (!read.ok)
|
|
3193
|
+
return { success: false, error: read.error };
|
|
3194
|
+
if (read.res.stdout === text)
|
|
3195
|
+
return ok4(undefined);
|
|
3196
|
+
outcomes.push(`${channel.name} exit 0 but pbpaste reads other text`);
|
|
3197
|
+
}
|
|
3198
|
+
return {
|
|
3199
|
+
success: false,
|
|
3200
|
+
error: driverError("E_IO", `simulator pasteboard did not take the text (${outcomes.join("; ")})`)
|
|
3201
|
+
};
|
|
3202
|
+
},
|
|
3649
3203
|
async pbpaste() {
|
|
3650
3204
|
const result = await run(pbpasteArgv(udid), SHORT_MS);
|
|
3651
3205
|
return result.ok ? ok4(result.res.stdout) : { success: false, error: result.error };
|
|
@@ -3682,299 +3236,6 @@ function createSimctl(deps) {
|
|
|
3682
3236
|
};
|
|
3683
3237
|
}
|
|
3684
3238
|
|
|
3685
|
-
// ../../packages/e2e/src/driver/ios/simd-client.ts
|
|
3686
|
-
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
3687
|
-
var DEFAULT_READY_TIMEOUT_MS3 = 15000;
|
|
3688
|
-
var SHUTDOWN_TIMEOUT_MS2 = 500;
|
|
3689
|
-
var STDERR_TAIL2 = 20;
|
|
3690
|
-
function crashed(info, what) {
|
|
3691
|
-
const exit = info?.exitCode === null || info?.exitCode === undefined ? "" : ` (exit ${info.exitCode})`;
|
|
3692
|
-
const tail = info?.stderrTail.length ? `: ${info.stderrTail.slice(-3).join(" | ")}` : "";
|
|
3693
|
-
return driverError("E_HELPER_CRASHED", `warden-simd ${what}${exit}${tail}`, {
|
|
3694
|
-
detail: info ? { exitCode: info.exitCode, stderrTail: info.stderrTail } : undefined
|
|
3695
|
-
});
|
|
3696
|
-
}
|
|
3697
|
-
async function createSimdClient(factory, options = {}) {
|
|
3698
|
-
const defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
3699
|
-
const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS3;
|
|
3700
|
-
const maxRespawns = options.maxRespawns ?? 0;
|
|
3701
|
-
const shutdownOnClose = options.shutdownOnClose ?? false;
|
|
3702
|
-
const log = options.log;
|
|
3703
|
-
const pending = new Map;
|
|
3704
|
-
const listeners = new Map;
|
|
3705
|
-
let seq = 0;
|
|
3706
|
-
let respawns = 0;
|
|
3707
|
-
let closed = false;
|
|
3708
|
-
let closing = false;
|
|
3709
|
-
let shutdownAcked = false;
|
|
3710
|
-
let current;
|
|
3711
|
-
let opening;
|
|
3712
|
-
let lastCrash;
|
|
3713
|
-
let fatalError;
|
|
3714
|
-
function emit(event, payload) {
|
|
3715
|
-
for (const listener of listeners.get(event) ?? []) {
|
|
3716
|
-
try {
|
|
3717
|
-
listener(payload);
|
|
3718
|
-
} catch (error) {
|
|
3719
|
-
log?.(`[simd] ${event} listener threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
3720
|
-
}
|
|
3721
|
-
}
|
|
3722
|
-
}
|
|
3723
|
-
function failAll(error) {
|
|
3724
|
-
for (const [id, entry] of pending) {
|
|
3725
|
-
clearTimeout(entry.timer);
|
|
3726
|
-
pending.delete(id);
|
|
3727
|
-
entry.resolve({ success: false, error });
|
|
3728
|
-
}
|
|
3729
|
-
}
|
|
3730
|
-
function handleResponse(response) {
|
|
3731
|
-
respawns = 0;
|
|
3732
|
-
const entry = pending.get(response.id);
|
|
3733
|
-
if (!entry) {
|
|
3734
|
-
log?.(`[simd] response for unknown id ${response.id} (timed out?)`);
|
|
3735
|
-
return;
|
|
3736
|
-
}
|
|
3737
|
-
clearTimeout(entry.timer);
|
|
3738
|
-
pending.delete(response.id);
|
|
3739
|
-
entry.resolve(response.ok ? { success: true, data: response.data ?? null } : { success: false, error: mapWireError(response.error) });
|
|
3740
|
-
}
|
|
3741
|
-
function handleFatal(session, event) {
|
|
3742
|
-
const error = mapWireError(event.error);
|
|
3743
|
-
fatalError = error;
|
|
3744
|
-
log?.(`[simd] fatal: ${error.code}: ${error.message}`);
|
|
3745
|
-
emit("fatal", error);
|
|
3746
|
-
if (session.handshaking) {
|
|
3747
|
-
session.handshaking = false;
|
|
3748
|
-
session.handshake({ success: false, error });
|
|
3749
|
-
}
|
|
3750
|
-
failAll(error);
|
|
3751
|
-
}
|
|
3752
|
-
function handleEvent(session, event) {
|
|
3753
|
-
if (event.event === "log") {
|
|
3754
|
-
log?.(`[simd] ${event.level}: ${event.message}`);
|
|
3755
|
-
emit("log", event);
|
|
3756
|
-
} else if (event.event === "fatal") {
|
|
3757
|
-
handleFatal(session, event);
|
|
3758
|
-
} else if (session.handshaking) {
|
|
3759
|
-
session.handshaking = false;
|
|
3760
|
-
session.ready = event;
|
|
3761
|
-
emit("ready", event);
|
|
3762
|
-
session.handshake({ success: true, data: event });
|
|
3763
|
-
}
|
|
3764
|
-
}
|
|
3765
|
-
function handleMessage(session, message) {
|
|
3766
|
-
if (message.kind === "response")
|
|
3767
|
-
handleResponse(message.response);
|
|
3768
|
-
else
|
|
3769
|
-
handleEvent(session, message.event);
|
|
3770
|
-
}
|
|
3771
|
-
function handleLine(session, line) {
|
|
3772
|
-
const parsed = parseLine(line);
|
|
3773
|
-
if (!parsed.success) {
|
|
3774
|
-
log?.(`[simd] ignoring line (${parsed.reason}): ${line.slice(0, 200)}`);
|
|
3775
|
-
return;
|
|
3776
|
-
}
|
|
3777
|
-
handleMessage(session, parsed.message);
|
|
3778
|
-
}
|
|
3779
|
-
function handleClose(session, info) {
|
|
3780
|
-
if (!session.alive)
|
|
3781
|
-
return;
|
|
3782
|
-
session.alive = false;
|
|
3783
|
-
const expected = closed || closing;
|
|
3784
|
-
emit("exit", { exitCode: info.exitCode, expected });
|
|
3785
|
-
if (session.handshaking) {
|
|
3786
|
-
session.handshaking = false;
|
|
3787
|
-
session.handshake({ success: false, error: fatalError ?? crashed(info, "exited before it was ready") });
|
|
3788
|
-
return;
|
|
3789
|
-
}
|
|
3790
|
-
if (fatalError)
|
|
3791
|
-
return;
|
|
3792
|
-
const error = crashed(info, expected ? "stopped" : "exited unexpectedly");
|
|
3793
|
-
if (!expected)
|
|
3794
|
-
lastCrash = error;
|
|
3795
|
-
failAll(expected ? driverError("E_INTERNAL", "client closed", { retryable: false }) : error);
|
|
3796
|
-
}
|
|
3797
|
-
async function openSession() {
|
|
3798
|
-
let resolveHandshake = () => {
|
|
3799
|
-
return;
|
|
3800
|
-
};
|
|
3801
|
-
const handshake = new Promise((resolve2) => {
|
|
3802
|
-
resolveHandshake = resolve2;
|
|
3803
|
-
});
|
|
3804
|
-
const session = { alive: true, handshake: resolveHandshake, handshaking: true };
|
|
3805
|
-
const stderrTail = [];
|
|
3806
|
-
const opened = await factory({
|
|
3807
|
-
onLine: (line) => handleLine(session, line),
|
|
3808
|
-
onDiagnostic: (line) => {
|
|
3809
|
-
stderrTail.push(line);
|
|
3810
|
-
if (stderrTail.length > STDERR_TAIL2)
|
|
3811
|
-
stderrTail.shift();
|
|
3812
|
-
log?.(`[simd:stderr] ${line}`);
|
|
3813
|
-
},
|
|
3814
|
-
onClose: (info) => handleClose(session, { ...info, stderrTail: info.stderrTail.length ? info.stderrTail : [...stderrTail] })
|
|
3815
|
-
});
|
|
3816
|
-
if (!opened.success)
|
|
3817
|
-
return opened;
|
|
3818
|
-
session.transport = opened.data;
|
|
3819
|
-
let timer;
|
|
3820
|
-
const timeout = new Promise((resolve2) => {
|
|
3821
|
-
timer = setTimeout(() => resolve2({
|
|
3822
|
-
success: false,
|
|
3823
|
-
error: driverError("E_TIMEOUT", `warden-simd sent no ready event within ${readyTimeoutMs} ms`)
|
|
3824
|
-
}), readyTimeoutMs);
|
|
3825
|
-
});
|
|
3826
|
-
const ready = await Promise.race([handshake, timeout]);
|
|
3827
|
-
clearTimeout(timer);
|
|
3828
|
-
if (!ready.success) {
|
|
3829
|
-
session.handshaking = false;
|
|
3830
|
-
session.alive = false;
|
|
3831
|
-
await session.transport.close().catch(() => {
|
|
3832
|
-
return;
|
|
3833
|
-
});
|
|
3834
|
-
return ready;
|
|
3835
|
-
}
|
|
3836
|
-
if (ready.data.protocol !== protocolVersion) {
|
|
3837
|
-
session.alive = false;
|
|
3838
|
-
await session.transport.close().catch(() => {
|
|
3839
|
-
return;
|
|
3840
|
-
});
|
|
3841
|
-
return {
|
|
3842
|
-
success: false,
|
|
3843
|
-
error: driverError("E_INTERNAL", `warden-simd speaks protocol ${ready.data.protocol}, this client expects ${protocolVersion}; rebuild or reinstall the helper`, { retryable: false })
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
current = session;
|
|
3847
|
-
return { success: true, data: session };
|
|
3848
|
-
}
|
|
3849
|
-
async function ensureSession() {
|
|
3850
|
-
if (current?.alive)
|
|
3851
|
-
return { success: true, data: current };
|
|
3852
|
-
if (opening)
|
|
3853
|
-
return opening;
|
|
3854
|
-
if (respawns >= maxRespawns) {
|
|
3855
|
-
return {
|
|
3856
|
-
success: false,
|
|
3857
|
-
error: lastCrash ?? driverError("E_HELPER_CRASHED", "warden-simd connection is closed")
|
|
3858
|
-
};
|
|
3859
|
-
}
|
|
3860
|
-
respawns += 1;
|
|
3861
|
-
log?.(`[simd] respawning helper (${respawns}/${maxRespawns})`);
|
|
3862
|
-
opening = openSession().finally(() => {
|
|
3863
|
-
opening = undefined;
|
|
3864
|
-
});
|
|
3865
|
-
return opening;
|
|
3866
|
-
}
|
|
3867
|
-
function validate(op, data) {
|
|
3868
|
-
if (!hasOpSchema(op))
|
|
3869
|
-
return { success: true, data };
|
|
3870
|
-
const parsed = opSchemas[op].safeParse(data);
|
|
3871
|
-
if (parsed.success)
|
|
3872
|
-
return { success: true, data: parsed.data };
|
|
3873
|
-
return {
|
|
3874
|
-
success: false,
|
|
3875
|
-
error: driverError("E_INTERNAL", `warden-simd returned an unexpected \`${op}\` payload: ${parsed.error.message}`, {
|
|
3876
|
-
retryable: false
|
|
3877
|
-
})
|
|
3878
|
-
};
|
|
3879
|
-
}
|
|
3880
|
-
async function request(op, params, opts) {
|
|
3881
|
-
if (closed)
|
|
3882
|
-
return { success: false, error: driverError("E_INTERNAL", "warden-simd client is closed", { retryable: false }) };
|
|
3883
|
-
if (fatalError)
|
|
3884
|
-
return { success: false, error: fatalError };
|
|
3885
|
-
const session = await ensureSession();
|
|
3886
|
-
if (!session.success)
|
|
3887
|
-
return session;
|
|
3888
|
-
const transport = session.data.transport;
|
|
3889
|
-
if (!transport)
|
|
3890
|
-
return { success: false, error: driverError("E_INTERNAL", "warden-simd transport missing") };
|
|
3891
|
-
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
3892
|
-
const id = String(++seq);
|
|
3893
|
-
const result = await new Promise((resolve2) => {
|
|
3894
|
-
const timer = setTimeout(() => {
|
|
3895
|
-
pending.delete(id);
|
|
3896
|
-
resolve2({
|
|
3897
|
-
success: false,
|
|
3898
|
-
error: driverError("E_TIMEOUT", `warden-simd \`${op}\` timed out after ${timeoutMs} ms`, {
|
|
3899
|
-
detail: { op, timeoutMs }
|
|
3900
|
-
})
|
|
3901
|
-
});
|
|
3902
|
-
}, timeoutMs);
|
|
3903
|
-
pending.set(id, { op, resolve: resolve2, timer });
|
|
3904
|
-
try {
|
|
3905
|
-
transport.send(encodeRequest({ timeoutMs, ...params, id, op }));
|
|
3906
|
-
} catch (error) {
|
|
3907
|
-
clearTimeout(timer);
|
|
3908
|
-
pending.delete(id);
|
|
3909
|
-
resolve2({
|
|
3910
|
-
success: false,
|
|
3911
|
-
error: crashed(undefined, `rejected the \`${op}\` request: ${error instanceof Error ? error.message : String(error)}`)
|
|
3912
|
-
});
|
|
3913
|
-
}
|
|
3914
|
-
});
|
|
3915
|
-
if (result.success && op === "shutdown")
|
|
3916
|
-
shutdownAcked = true;
|
|
3917
|
-
return result.success ? validate(op, result.data) : result;
|
|
3918
|
-
}
|
|
3919
|
-
const first = await openSession();
|
|
3920
|
-
if (!first.success)
|
|
3921
|
-
return first;
|
|
3922
|
-
const client = {
|
|
3923
|
-
get ready() {
|
|
3924
|
-
const ready = current?.ready ?? first.data.ready;
|
|
3925
|
-
if (!ready)
|
|
3926
|
-
throw new Error("warden-simd client has no handshake");
|
|
3927
|
-
return ready;
|
|
3928
|
-
},
|
|
3929
|
-
request: (op, params = {}, opts = {}) => request(op, params, opts),
|
|
3930
|
-
on(event, handler) {
|
|
3931
|
-
const stored = handler;
|
|
3932
|
-
const set = listeners.get(event) ?? new Set;
|
|
3933
|
-
set.add(stored);
|
|
3934
|
-
listeners.set(event, set);
|
|
3935
|
-
return () => {
|
|
3936
|
-
set.delete(stored);
|
|
3937
|
-
};
|
|
3938
|
-
},
|
|
3939
|
-
async close() {
|
|
3940
|
-
if (closed)
|
|
3941
|
-
return;
|
|
3942
|
-
closing = true;
|
|
3943
|
-
const session = current;
|
|
3944
|
-
if (shutdownOnClose && session?.alive && !fatalError && !shutdownAcked) {
|
|
3945
|
-
await request("shutdown", {}, { timeoutMs: SHUTDOWN_TIMEOUT_MS2 });
|
|
3946
|
-
}
|
|
3947
|
-
closed = true;
|
|
3948
|
-
failAll(driverError("E_INTERNAL", "warden-simd client closed", { retryable: false }));
|
|
3949
|
-
await session?.transport?.close().catch(() => {
|
|
3950
|
-
return;
|
|
3951
|
-
});
|
|
3952
|
-
}
|
|
3953
|
-
};
|
|
3954
|
-
return { success: true, data: client };
|
|
3955
|
-
}
|
|
3956
|
-
function spawnSimd(options) {
|
|
3957
|
-
const cmd = [
|
|
3958
|
-
options.helperPath,
|
|
3959
|
-
"--udid",
|
|
3960
|
-
options.udid,
|
|
3961
|
-
...options.resources ? ["--resources", options.resources] : [],
|
|
3962
|
-
...options.args ?? []
|
|
3963
|
-
];
|
|
3964
|
-
return createSimdClient(stdioTransport({ cmd, spawn: options.spawn, graceMs: options.graceMs }), {
|
|
3965
|
-
...options,
|
|
3966
|
-
maxRespawns: options.maxRespawns ?? 1,
|
|
3967
|
-
shutdownOnClose: options.shutdownOnClose ?? true
|
|
3968
|
-
});
|
|
3969
|
-
}
|
|
3970
|
-
function connectSimd(options) {
|
|
3971
|
-
return createSimdClient(socketTransport({ socketPath: options.socketPath }), {
|
|
3972
|
-
...options,
|
|
3973
|
-
maxRespawns: options.maxRespawns ?? 0,
|
|
3974
|
-
shutdownOnClose: options.shutdownOnClose ?? false
|
|
3975
|
-
});
|
|
3976
|
-
}
|
|
3977
|
-
|
|
3978
3239
|
// ../../packages/e2e/src/driver/ios/type-budget.ts
|
|
3979
3240
|
var TYPE_BASE_MS = 1e4;
|
|
3980
3241
|
var TYPE_PER_CHAR_MS = 70;
|
|
@@ -4050,6 +3311,25 @@ function nativeDetail(data) {
|
|
|
4050
3311
|
noteSpanDetail("frontmostPid", frontmostPid);
|
|
4051
3312
|
return detail;
|
|
4052
3313
|
}
|
|
3314
|
+
function noteRebind(data) {
|
|
3315
|
+
noteSpanDetail("rebind", data.bound ? "bound" : data.reason ?? "unbound");
|
|
3316
|
+
noteSpanDetail("rebindMs", data.waitedMs);
|
|
3317
|
+
if (data.restarts !== undefined && data.restarts > 0)
|
|
3318
|
+
noteSpanDetail("rebindRestarts", data.restarts);
|
|
3319
|
+
if (data.recycled === true)
|
|
3320
|
+
noteSpanDetail("rebindRecycled", true);
|
|
3321
|
+
}
|
|
3322
|
+
function healthDetail(d) {
|
|
3323
|
+
return {
|
|
3324
|
+
axDefault: d.ax.default,
|
|
3325
|
+
...d.ax.bridge === "degraded" ? { axBridge: "degraded" } : {},
|
|
3326
|
+
...d.ax.lastError ? { axLastError: d.ax.lastError } : {},
|
|
3327
|
+
...d.ax.error !== undefined ? { axError: d.ax.error } : {},
|
|
3328
|
+
...d.socket ? { socket: d.socket } : {},
|
|
3329
|
+
...d.xcode ? { xcode: d.xcode } : {},
|
|
3330
|
+
...d.state ? { state: d.state } : {}
|
|
3331
|
+
};
|
|
3332
|
+
}
|
|
4053
3333
|
|
|
4054
3334
|
class DriverFailure extends Error {
|
|
4055
3335
|
error;
|
|
@@ -4216,36 +3496,37 @@ function createIosDriver(swap, simctl, opts) {
|
|
|
4216
3496
|
opts.log?.(`[ios] rebind after launch failed (${reply.error.code}): ${reply.error.message}`);
|
|
4217
3497
|
return false;
|
|
4218
3498
|
}
|
|
4219
|
-
|
|
4220
|
-
noteSpanDetail("rebindMs", reply.data.waitedMs);
|
|
4221
|
-
if (reply.data.restarts !== undefined && reply.data.restarts > 0)
|
|
4222
|
-
noteSpanDetail("rebindRestarts", reply.data.restarts);
|
|
4223
|
-
if (reply.data.recycled === true)
|
|
4224
|
-
noteSpanDetail("rebindRecycled", true);
|
|
3499
|
+
noteRebind(reply.data);
|
|
4225
3500
|
return reply.data.bound;
|
|
4226
3501
|
}
|
|
3502
|
+
async function settleViaHelper(quietMs, timeoutMs) {
|
|
3503
|
+
const expected = launchedBundle;
|
|
3504
|
+
const native = await request("settle", { quietMs, settleTimeoutMs: timeoutMs, ...expected === undefined ? {} : { bundleId: expected } }, { timeoutMs: timeoutMs + SETTLE_MARGIN_MS });
|
|
3505
|
+
if (native.success) {
|
|
3506
|
+
if (expected !== undefined && native.data.reason !== "frontmost_mismatch")
|
|
3507
|
+
launchedBundle = undefined;
|
|
3508
|
+
return { success: true, data: nativeDetail(native.data) };
|
|
3509
|
+
}
|
|
3510
|
+
if (native.error.code === "E_TIMEOUT") {
|
|
3511
|
+
noteSpanDetail("reason", "helper_timeout");
|
|
3512
|
+
return {
|
|
3513
|
+
success: true,
|
|
3514
|
+
data: { quiet: false, waitedMs: timeoutMs + SETTLE_MARGIN_MS, reason: "helper_timeout" }
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
if (native.error.code !== "E_UNSUPPORTED")
|
|
3518
|
+
return native;
|
|
3519
|
+
settleUnsupported = true;
|
|
3520
|
+
opts.log?.("[ios] native settle unsupported, polling snapshot hashes");
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
4227
3523
|
async function settle(o = {}) {
|
|
4228
3524
|
const quietMs = o.quietMs ?? DEFAULT_QUIET_MS;
|
|
4229
3525
|
const timeoutMs = o.timeoutMs ?? DEFAULT_SETTLE_TIMEOUT_MS2;
|
|
4230
3526
|
if (!settleUnsupported) {
|
|
4231
|
-
const
|
|
4232
|
-
|
|
4233
|
-
if (native.success) {
|
|
4234
|
-
if (expected !== undefined && native.data.reason !== "frontmost_mismatch")
|
|
4235
|
-
launchedBundle = undefined;
|
|
4236
|
-
return { success: true, data: nativeDetail(native.data) };
|
|
4237
|
-
}
|
|
4238
|
-
if (native.error.code === "E_TIMEOUT") {
|
|
4239
|
-
noteSpanDetail("reason", "helper_timeout");
|
|
4240
|
-
return {
|
|
4241
|
-
success: true,
|
|
4242
|
-
data: { quiet: false, waitedMs: timeoutMs + SETTLE_MARGIN_MS, reason: "helper_timeout" }
|
|
4243
|
-
};
|
|
4244
|
-
}
|
|
4245
|
-
if (native.error.code !== "E_UNSUPPORTED")
|
|
3527
|
+
const native = await settleViaHelper(quietMs, timeoutMs);
|
|
3528
|
+
if (native)
|
|
4246
3529
|
return native;
|
|
4247
|
-
settleUnsupported = true;
|
|
4248
|
-
opts.log?.("[ios] native settle unsupported, polling snapshot hashes");
|
|
4249
3530
|
}
|
|
4250
3531
|
return hashSettle({ quietMs, timeoutMs });
|
|
4251
3532
|
}
|
|
@@ -4303,15 +3584,7 @@ function createIosDriver(swap, simctl, opts) {
|
|
|
4303
3584
|
transport: d.hid.transport,
|
|
4304
3585
|
bridge: d.ax.bridge === "degraded" ? "available" : d.ax.bridge,
|
|
4305
3586
|
screen: d.screen,
|
|
4306
|
-
detail:
|
|
4307
|
-
axDefault: d.ax.default,
|
|
4308
|
-
...d.ax.bridge === "degraded" ? { axBridge: "degraded" } : {},
|
|
4309
|
-
...d.ax.lastError ? { axLastError: d.ax.lastError } : {},
|
|
4310
|
-
...d.ax.error !== undefined ? { axError: d.ax.error } : {},
|
|
4311
|
-
...d.socket ? { socket: d.socket } : {},
|
|
4312
|
-
...d.xcode ? { xcode: d.xcode } : {},
|
|
4313
|
-
...d.state ? { state: d.state } : {}
|
|
4314
|
-
}
|
|
3587
|
+
detail: healthDetail(d)
|
|
4315
3588
|
}
|
|
4316
3589
|
};
|
|
4317
3590
|
}
|
|
@@ -4431,7 +3704,7 @@ async function connect(o, log) {
|
|
|
4431
3704
|
helperPath: helper.data,
|
|
4432
3705
|
udid: o.udid,
|
|
4433
3706
|
log,
|
|
4434
|
-
...(o.exists ??
|
|
3707
|
+
...(o.exists ?? existsSync2)(resources) ? { resources } : {},
|
|
4435
3708
|
...o.spawn ? { spawn: o.spawn } : {},
|
|
4436
3709
|
...timeoutOption(o)
|
|
4437
3710
|
});
|
|
@@ -4535,12 +3808,12 @@ function codeFor(code) {
|
|
|
4535
3808
|
return "ACTION_FAILED";
|
|
4536
3809
|
}
|
|
4537
3810
|
function toE2eError(error, action) {
|
|
4538
|
-
return new
|
|
3811
|
+
return new E2eError2(codeFor(error.code), `${action} failed: ${error.code}: ${error.message}`);
|
|
4539
3812
|
}
|
|
4540
3813
|
function aborted(action, signal) {
|
|
4541
3814
|
const reason = signal.reason;
|
|
4542
3815
|
const detail = reason instanceof Error ? `: ${reason.message}` : "";
|
|
4543
|
-
return new
|
|
3816
|
+
return new E2eError2("TIMEOUT", `${action} aborted (test deadline reached or cancelled)${detail}`);
|
|
4544
3817
|
}
|
|
4545
3818
|
async function settled(call, action, signal) {
|
|
4546
3819
|
if (signal === undefined)
|
|
@@ -4569,7 +3842,7 @@ async function unwrap(call, action, signal) {
|
|
|
4569
3842
|
// ../../packages/e2e/src/fixture-session.ts
|
|
4570
3843
|
var systemClock = {
|
|
4571
3844
|
now: () => Date.now(),
|
|
4572
|
-
sleep: (ms) => new Promise((
|
|
3845
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
4573
3846
|
};
|
|
4574
3847
|
|
|
4575
3848
|
// ../../packages/e2e/src/app.ts
|
|
@@ -4606,11 +3879,11 @@ function parseWait(wait) {
|
|
|
4606
3879
|
if (typeof wait === "object" && wait !== null && isLocator(wait.until)) {
|
|
4607
3880
|
const { timeout } = wait;
|
|
4608
3881
|
if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) {
|
|
4609
|
-
throw new
|
|
3882
|
+
throw new E2eError2("INVALID_ARGUMENT", `app.open wait timeout must be a non-negative number, got ${timeout}`);
|
|
4610
3883
|
}
|
|
4611
3884
|
return timeout === undefined ? { kind: "until", until: wait.until } : { kind: "until", until: wait.until, timeout };
|
|
4612
3885
|
}
|
|
4613
|
-
throw new
|
|
3886
|
+
throw new E2eError2("INVALID_ARGUMENT", `app.open wait must be "quiet", "none" or { until: <locator made by screen> }, got ${describeWait(wait)}`);
|
|
4614
3887
|
}
|
|
4615
3888
|
function describeWait(wait) {
|
|
4616
3889
|
if (typeof wait === "string")
|
|
@@ -4689,7 +3962,7 @@ function createApp({ session, driver, env, log = stderrLog2, clock = systemClock
|
|
|
4689
3962
|
async reinstall() {
|
|
4690
3963
|
const path = env.appPath;
|
|
4691
3964
|
if (path === undefined) {
|
|
4692
|
-
throw new
|
|
3965
|
+
throw new E2eError2("INVALID_ARGUMENT", "app.reinstall() needs WARDEN_APP_PATH (the build to install) to be set");
|
|
4693
3966
|
}
|
|
4694
3967
|
const installed = await unwrap(() => driver.app.isInstalled(bundleId), `check ${bundleId}`, session.signal);
|
|
4695
3968
|
if (installed)
|
|
@@ -4762,11 +4035,11 @@ function createAlertReader({ driver, clock, signal }) {
|
|
|
4762
4035
|
|
|
4763
4036
|
// ../../packages/e2e/src/device-devtools.ts
|
|
4764
4037
|
function createDeviceDevtools(source) {
|
|
4765
|
-
const
|
|
4038
|
+
const connect = async () => {
|
|
4766
4039
|
const attached = await source.devtools();
|
|
4767
4040
|
if (attached.success)
|
|
4768
4041
|
return attached.data;
|
|
4769
|
-
throw new
|
|
4042
|
+
throw new E2eError2("SESSION", `devtools unavailable: ${attached.error.message}`);
|
|
4770
4043
|
};
|
|
4771
4044
|
const attach = () => source.devtools();
|
|
4772
4045
|
return {
|
|
@@ -4786,24 +4059,24 @@ function createDeviceDevtools(source) {
|
|
|
4786
4059
|
},
|
|
4787
4060
|
network: {
|
|
4788
4061
|
async entries(query) {
|
|
4789
|
-
return (await
|
|
4062
|
+
return (await connect()).network.entries(query);
|
|
4790
4063
|
},
|
|
4791
4064
|
async clear() {
|
|
4792
|
-
await (await
|
|
4065
|
+
await (await connect()).network.clear();
|
|
4793
4066
|
}
|
|
4794
4067
|
},
|
|
4795
4068
|
console: {
|
|
4796
4069
|
async lines() {
|
|
4797
|
-
return (await
|
|
4070
|
+
return (await connect()).console.lines();
|
|
4798
4071
|
},
|
|
4799
4072
|
async clear() {
|
|
4800
|
-
(await
|
|
4073
|
+
(await connect()).console.clear();
|
|
4801
4074
|
},
|
|
4802
4075
|
async mark(label) {
|
|
4803
|
-
(await
|
|
4076
|
+
(await connect()).console.mark(label);
|
|
4804
4077
|
}
|
|
4805
4078
|
},
|
|
4806
|
-
connect
|
|
4079
|
+
connect
|
|
4807
4080
|
};
|
|
4808
4081
|
}
|
|
4809
4082
|
|
|
@@ -4864,8 +4137,8 @@ async function lookForSheet(deps, plan, watch, started, remembered) {
|
|
|
4864
4137
|
watch.lastSheetAt = now;
|
|
4865
4138
|
watch.sheetSeenAt ??= now;
|
|
4866
4139
|
const since = (at) => at === undefined ? Number.POSITIVE_INFINITY : now - at;
|
|
4867
|
-
const
|
|
4868
|
-
if (!
|
|
4140
|
+
const settled = since(watch.sheetSeenAt) >= SHEET_SETTLE_MS && since(watch.lastPressAt) >= PRESS_GAP_MS;
|
|
4141
|
+
if (!settled)
|
|
4869
4142
|
return { sheetUp: true, confirmed: false, finished: false };
|
|
4870
4143
|
if (watch.presses >= MAX_PRESSES)
|
|
4871
4144
|
return { sheetUp: true, confirmed: false, finished: plan.until === undefined };
|
|
@@ -4954,11 +4227,11 @@ function alertTarget(info, action, platform) {
|
|
|
4954
4227
|
const target = findButton(buttons, action.button);
|
|
4955
4228
|
if (target === undefined) {
|
|
4956
4229
|
const names = buttons.map((b) => nameOf(b) ?? "?").join(", ");
|
|
4957
|
-
throw new
|
|
4230
|
+
throw new E2eError2("ACTION_FAILED", `alert has no "${action.button}" button (buttons: ${names})`);
|
|
4958
4231
|
}
|
|
4959
4232
|
return target;
|
|
4960
4233
|
}
|
|
4961
|
-
function createDevice({ session, driver, env, clock = systemClock }) {
|
|
4234
|
+
function createDevice({ session, driver, env, clock = systemClock, perfExec }) {
|
|
4962
4235
|
const issued = new Map;
|
|
4963
4236
|
const signal = () => session.signal;
|
|
4964
4237
|
const pressAlertButton = async (button, action) => {
|
|
@@ -4980,7 +4253,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
4980
4253
|
return false;
|
|
4981
4254
|
}
|
|
4982
4255
|
};
|
|
4983
|
-
const
|
|
4256
|
+
const readSnapshot = (opts) => unwrap(() => driver.snapshot(opts), "snapshot", signal());
|
|
4984
4257
|
const { devtools: attach, peekDevtools } = session;
|
|
4985
4258
|
let devtools;
|
|
4986
4259
|
const lazyDevtools = () => {
|
|
@@ -4995,10 +4268,19 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
4995
4268
|
}
|
|
4996
4269
|
return devtools;
|
|
4997
4270
|
};
|
|
4271
|
+
const perf = createDevicePerf({
|
|
4272
|
+
exec: perfExec ?? spawnWarden(env.wardenBin),
|
|
4273
|
+
udid: env.udid,
|
|
4274
|
+
budgets: parseBudgets(env.perfBudgets),
|
|
4275
|
+
attemptDir: () => session.attemptDir,
|
|
4276
|
+
addFile: (relative) => session.attempt?.files.add(relative),
|
|
4277
|
+
...env.wardenBin === undefined && perfExec === undefined ? { unavailable: "WARDEN_BIN is not set (run the spec with `warden e2e`)" } : {}
|
|
4278
|
+
});
|
|
4998
4279
|
const device = {
|
|
4999
4280
|
get devtools() {
|
|
5000
4281
|
return lazyDevtools();
|
|
5001
4282
|
},
|
|
4283
|
+
perf,
|
|
5002
4284
|
async alert(action) {
|
|
5003
4285
|
const info = await readAlert("axbridge");
|
|
5004
4286
|
if (info === null || info.buttons.length === 0)
|
|
@@ -5014,7 +4296,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5014
4296
|
async openLink(url, options = {}) {
|
|
5015
4297
|
const waitMs = options.waitMs ?? OPEN_LINK_WAIT_MS;
|
|
5016
4298
|
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
5017
|
-
throw new
|
|
4299
|
+
throw new E2eError2("INVALID_ARGUMENT", `openLink waitMs must be a non-negative number, got ${String(waitMs)}`);
|
|
5018
4300
|
}
|
|
5019
4301
|
await unwrap(() => driver.app.openUrl(url), `open ${url}`, signal());
|
|
5020
4302
|
const answersSheet = options.accept !== false && driver.platform === "ios" && driver.capabilities.alerts;
|
|
@@ -5034,7 +4316,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5034
4316
|
},
|
|
5035
4317
|
async back() {
|
|
5036
4318
|
if (driver.platform === "ios") {
|
|
5037
|
-
throw new
|
|
4319
|
+
throw new E2eError2("INVALID_ARGUMENT", "device.back() is Android only: iOS has no back key");
|
|
5038
4320
|
}
|
|
5039
4321
|
await unwrap(() => driver.pressButton("back"), "press back", signal());
|
|
5040
4322
|
},
|
|
@@ -5051,7 +4333,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5051
4333
|
await unwrap(() => driver.clipboard(text), "set clipboard", signal());
|
|
5052
4334
|
},
|
|
5053
4335
|
async hideKeyboard() {
|
|
5054
|
-
const snapshot = await
|
|
4336
|
+
const snapshot = await readSnapshot();
|
|
5055
4337
|
if (!snapshot.flat.some((element) => element.role === "keyboard"))
|
|
5056
4338
|
return;
|
|
5057
4339
|
if (driver.platform === "ios")
|
|
@@ -5073,7 +4355,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5073
4355
|
},
|
|
5074
4356
|
async snapshot(options = {}) {
|
|
5075
4357
|
const interactiveOnly = options.interactiveOnly ?? false;
|
|
5076
|
-
const snapshot = await
|
|
4358
|
+
const snapshot = await readSnapshot({ interactiveOnly });
|
|
5077
4359
|
const rendered = renderSnapshot(snapshot, { interactiveOnly, refs: new Map });
|
|
5078
4360
|
return [renderHeader({ snapshot, rendered, interactiveOnly }), ...rendered.lines].join(`
|
|
5079
4361
|
`);
|
|
@@ -5086,7 +4368,7 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5086
4368
|
return settleDetailOf(native.data);
|
|
5087
4369
|
if (native.error.code !== "E_UNSUPPORTED")
|
|
5088
4370
|
throw toE2eError(native.error, "settle");
|
|
5089
|
-
const polled = await settleByHash(async () => snapshotHash(await
|
|
4371
|
+
const polled = await settleByHash(async () => snapshotHash(await readSnapshot()), {
|
|
5090
4372
|
quietMs,
|
|
5091
4373
|
timeoutMs,
|
|
5092
4374
|
now: clock.now,
|
|
@@ -5102,16 +4384,16 @@ function createDevice({ session, driver, env, clock = systemClock }) {
|
|
|
5102
4384
|
var systemClock2 = {
|
|
5103
4385
|
now: () => Date.now(),
|
|
5104
4386
|
sleep(ms, signal) {
|
|
5105
|
-
return new Promise((
|
|
4387
|
+
return new Promise((resolve) => {
|
|
5106
4388
|
if (signal?.aborted)
|
|
5107
|
-
return
|
|
4389
|
+
return resolve();
|
|
5108
4390
|
const onAbort = () => {
|
|
5109
4391
|
clearTimeout(timer);
|
|
5110
|
-
|
|
4392
|
+
resolve();
|
|
5111
4393
|
};
|
|
5112
4394
|
const timer = setTimeout(() => {
|
|
5113
4395
|
signal?.removeEventListener("abort", onAbort);
|
|
5114
|
-
|
|
4396
|
+
resolve();
|
|
5115
4397
|
}, ms);
|
|
5116
4398
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5117
4399
|
});
|
|
@@ -5285,13 +4567,13 @@ class Runtime {
|
|
|
5285
4567
|
}
|
|
5286
4568
|
}
|
|
5287
4569
|
function driverFailure(verb, error, code = "DRIVER") {
|
|
5288
|
-
return new
|
|
4570
|
+
return new E2eError2(code, `${verb} failed: ${error.code}: ${error.message}`);
|
|
5289
4571
|
}
|
|
5290
4572
|
function abortError(signal) {
|
|
5291
4573
|
const reason = signal?.reason;
|
|
5292
|
-
if (reason instanceof
|
|
4574
|
+
if (reason instanceof E2eError2)
|
|
5293
4575
|
return reason;
|
|
5294
|
-
return new
|
|
4576
|
+
return new E2eError2("TIMEOUT", "the test was aborted before the action finished");
|
|
5295
4577
|
}
|
|
5296
4578
|
|
|
5297
4579
|
// ../../packages/e2e/src/screen/screen.ts
|
|
@@ -5306,7 +4588,7 @@ function createScreen(host) {
|
|
|
5306
4588
|
const allowed = "direction" in options ? ["direction", "momentum"] : ["from", "to", "durationMs"];
|
|
5307
4589
|
const unknown = keys.filter((key) => !allowed.includes(key));
|
|
5308
4590
|
if (unknown.length > 0 || keys.length === 0 || "direction" in options && "from" in options) {
|
|
5309
|
-
throw new
|
|
4591
|
+
throw new E2eError2("INVALID_ARGUMENT", "swipe takes either { direction, momentum? } or { from, to, durationMs? }, not a mix");
|
|
5310
4592
|
}
|
|
5311
4593
|
return rt.step("swipe", async () => {
|
|
5312
4594
|
if ("direction" in options) {
|
|
@@ -5316,7 +4598,7 @@ function createScreen(host) {
|
|
|
5316
4598
|
return;
|
|
5317
4599
|
}
|
|
5318
4600
|
if (!isFinitePoint(options.from) || !isFinitePoint(options.to)) {
|
|
5319
|
-
throw new
|
|
4601
|
+
throw new E2eError2("INVALID_ARGUMENT", "swipe needs finite coordinates for from and to");
|
|
5320
4602
|
}
|
|
5321
4603
|
const driver = await host.driver();
|
|
5322
4604
|
const opts = options.durationMs === undefined ? undefined : { durationMs: options.durationMs };
|
|
@@ -5333,7 +4615,7 @@ function createScreen(host) {
|
|
|
5333
4615
|
locator: (selector) => new Locator(selectorExpression(selector), rt),
|
|
5334
4616
|
async tapAt(point) {
|
|
5335
4617
|
if (!isFinitePoint(point))
|
|
5336
|
-
throw new
|
|
4618
|
+
throw new E2eError2("INVALID_ARGUMENT", `tapAt needs finite x and y, got ${JSON.stringify(point)}`);
|
|
5337
4619
|
return rt.step(`tapAt (${point.x}, ${point.y})`, async () => {
|
|
5338
4620
|
const driver = await host.driver();
|
|
5339
4621
|
rt.drive("tapAt", await driver.tap(point));
|
|
@@ -5368,10 +4650,10 @@ function createScreen(host) {
|
|
|
5368
4650
|
async path(options) {
|
|
5369
4651
|
const { paths } = options;
|
|
5370
4652
|
if (paths.length < 1 || paths.length > 2) {
|
|
5371
|
-
throw new
|
|
4653
|
+
throw new E2eError2("INVALID_ARGUMENT", `gesture.path takes 1 or 2 paths, got ${paths.length}`);
|
|
5372
4654
|
}
|
|
5373
4655
|
if (paths.some((points) => points.length < 1 || !points.every(isFinitePoint))) {
|
|
5374
|
-
throw new
|
|
4656
|
+
throw new E2eError2("INVALID_ARGUMENT", "gesture.path needs at least one point per path, all with finite x and y");
|
|
5375
4657
|
}
|
|
5376
4658
|
return rt.step(`gesture path (${paths.length} ${paths.length === 1 ? "finger" : "fingers"})`, async () => {
|
|
5377
4659
|
const driver = await host.driver();
|
|
@@ -5393,6 +4675,9 @@ function traceDevice(device, span) {
|
|
|
5393
4675
|
get devtools() {
|
|
5394
4676
|
return device.devtools;
|
|
5395
4677
|
},
|
|
4678
|
+
get perf() {
|
|
4679
|
+
return device.perf;
|
|
4680
|
+
},
|
|
5396
4681
|
alert: (action) => span("device.alert", () => device.alert(action), { detail: (answered) => ({ answered }) }),
|
|
5397
4682
|
openLink: (url, options) => span("device.openLink", () => device.openLink(url, options)),
|
|
5398
4683
|
home: () => span("device.home", () => device.home()),
|
|
@@ -5479,17 +4764,20 @@ ${read.error}
|
|
|
5479
4764
|
deps.exit(2);
|
|
5480
4765
|
return;
|
|
5481
4766
|
}
|
|
5482
|
-
deps.setDefaultTimeout(read.data.timeoutMs +
|
|
4767
|
+
deps.setDefaultTimeout(read.data.timeoutMs + BUN_TIMEOUT_MARGIN_MS2);
|
|
5483
4768
|
const session = deps.createSession({ env: read.data });
|
|
5484
4769
|
deps.afterAll(async () => {
|
|
5485
4770
|
await session.close();
|
|
5486
4771
|
if (isCi(deps.env) && deps.onlySeen()) {
|
|
5487
|
-
throw new
|
|
4772
|
+
throw new E2eError2("INVALID_ARGUMENT", "test.only / test(..., { only: true }) is not allowed in CI");
|
|
5488
4773
|
}
|
|
5489
4774
|
});
|
|
5490
4775
|
}
|
|
5491
|
-
if (!hasDefaultDriverFactory())
|
|
4776
|
+
if (!hasDefaultDriverFactory()) {
|
|
5492
4777
|
setDefaultDriverFactory(defaultDriverFactory);
|
|
4778
|
+
setDefaultNativeLog(realNativeLogDeps(bunExec, androidTools(process.env).adb));
|
|
4779
|
+
setDefaultHidRecovery({ exec: bunExec });
|
|
4780
|
+
}
|
|
5493
4781
|
if (!hasDefaultFixtureFactory())
|
|
5494
4782
|
setDefaultFixtureFactory(defaultFixtureFactory);
|
|
5495
4783
|
installPreload({
|
|
@@ -5497,7 +4785,7 @@ installPreload({
|
|
|
5497
4785
|
setDefaultTimeout,
|
|
5498
4786
|
afterAll,
|
|
5499
4787
|
createSession: getSession,
|
|
5500
|
-
version:
|
|
4788
|
+
version: WARDEN_E2E_VERSION2,
|
|
5501
4789
|
onlySeen: onlyWasSeen,
|
|
5502
4790
|
stderr: (text) => {
|
|
5503
4791
|
process.stderr.write(text);
|
|
@@ -5505,8 +4793,8 @@ installPreload({
|
|
|
5505
4793
|
exit: (code) => process.exit(code)
|
|
5506
4794
|
});
|
|
5507
4795
|
export {
|
|
5508
|
-
|
|
5509
|
-
isCi,
|
|
4796
|
+
BUN_TIMEOUT_MARGIN_MS2 as BUN_TIMEOUT_MARGIN_MS,
|
|
5510
4797
|
installPreload,
|
|
5511
|
-
|
|
4798
|
+
isCi,
|
|
4799
|
+
versionMismatch
|
|
5512
4800
|
};
|