@yoqa/runner 0.3.16 → 0.3.17
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/dist/index.js +98 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16801,7 +16801,7 @@ function getCatalogDb() {
|
|
|
16801
16801
|
// package.json
|
|
16802
16802
|
var package_default = {
|
|
16803
16803
|
name: "@yoqa/runner",
|
|
16804
|
-
version: "0.3.
|
|
16804
|
+
version: "0.3.17",
|
|
16805
16805
|
description: "Yoqa local runner \u2014 Appium + catalog HTTP API (Bun). Start with yoqa serve or the yoqa-runner bin.",
|
|
16806
16806
|
license: "UNLICENSED",
|
|
16807
16807
|
type: "module",
|
|
@@ -17020,8 +17020,11 @@ function mergeCapabilities(appCaps, caseCaps) {
|
|
|
17020
17020
|
function looksLikePhysicalIosUdid(udid) {
|
|
17021
17021
|
return /^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{16}$/.test(udid.trim());
|
|
17022
17022
|
}
|
|
17023
|
+
var PHYSICAL_IOS_SESSION_TIMEOUT_MS = 60000;
|
|
17024
|
+
var SIMULATOR_WDA_SESSION_TIMEOUT_MS = 600000;
|
|
17025
|
+
var SIMULATOR_WDA_DERIVED_DATA = join6(YOQA_ROOT4, "wda-sim");
|
|
17023
17026
|
function iosSessionCreateTimeoutMs(deviceId) {
|
|
17024
|
-
return looksLikePhysicalIosUdid(deviceId) ?
|
|
17027
|
+
return looksLikePhysicalIosUdid(deviceId) ? PHYSICAL_IOS_SESSION_TIMEOUT_MS : SIMULATOR_WDA_SESSION_TIMEOUT_MS;
|
|
17025
17028
|
}
|
|
17026
17029
|
async function buildW3cCapabilities(options, mjpegPort) {
|
|
17027
17030
|
const merged = mergeCapabilities(options.appCaps, options.caseCaps);
|
|
@@ -17071,6 +17074,10 @@ async function buildW3cCapabilities(options, mjpegPort) {
|
|
|
17071
17074
|
if (caps["appium:waitForIdleTimeout"] === undefined) {
|
|
17072
17075
|
caps["appium:waitForIdleTimeout"] = 0;
|
|
17073
17076
|
}
|
|
17077
|
+
if (!physical && caps["appium:derivedDataPath"] === undefined) {
|
|
17078
|
+
await mkdir3(SIMULATOR_WDA_DERIVED_DATA, { recursive: true });
|
|
17079
|
+
caps["appium:derivedDataPath"] = SIMULATOR_WDA_DERIVED_DATA;
|
|
17080
|
+
}
|
|
17074
17081
|
}
|
|
17075
17082
|
return caps;
|
|
17076
17083
|
}
|
|
@@ -23551,13 +23558,24 @@ var caseFlowStepSchema = exports_external.object({
|
|
|
23551
23558
|
flowId: exports_external.string().min(1).nullable().optional()
|
|
23552
23559
|
});
|
|
23553
23560
|
var caseRunStatusSchema = exports_external.union([exports_external.literal("passed"), exports_external.literal("errored")]);
|
|
23554
|
-
var
|
|
23555
|
-
exports_external.
|
|
23556
|
-
|
|
23557
|
-
|
|
23558
|
-
|
|
23559
|
-
|
|
23560
|
-
|
|
23561
|
+
var caseScriptTapSchema = exports_external.object({
|
|
23562
|
+
type: exports_external.literal("tap"),
|
|
23563
|
+
x: exports_external.number().min(0).max(1000).optional(),
|
|
23564
|
+
y: exports_external.number().min(0).max(1000).optional(),
|
|
23565
|
+
label: exports_external.string().min(1).optional(),
|
|
23566
|
+
id: exports_external.string().min(1).optional(),
|
|
23567
|
+
reason: exports_external.string().optional()
|
|
23568
|
+
}).superRefine((value, ctx) => {
|
|
23569
|
+
const hasCoords = value.x != null && value.y != null;
|
|
23570
|
+
if (!hasCoords && !value.label && !value.id) {
|
|
23571
|
+
ctx.addIssue({
|
|
23572
|
+
code: exports_external.ZodIssueCode.custom,
|
|
23573
|
+
message: "tap requires x/y or label or id"
|
|
23574
|
+
});
|
|
23575
|
+
}
|
|
23576
|
+
});
|
|
23577
|
+
var caseScriptActionSchema = exports_external.union([
|
|
23578
|
+
caseScriptTapSchema,
|
|
23561
23579
|
exports_external.object({
|
|
23562
23580
|
type: exports_external.literal("type"),
|
|
23563
23581
|
text: exports_external.string(),
|
|
@@ -23567,6 +23585,13 @@ var caseScriptActionSchema = exports_external.discriminatedUnion("type", [
|
|
|
23567
23585
|
type: exports_external.literal("wait"),
|
|
23568
23586
|
ms: exports_external.number().min(0).max(1e4),
|
|
23569
23587
|
reason: exports_external.string().optional()
|
|
23588
|
+
}),
|
|
23589
|
+
exports_external.object({
|
|
23590
|
+
type: exports_external.literal("assert"),
|
|
23591
|
+
assertion: exports_external.union([exports_external.literal("visible"), exports_external.literal("not-visible")]).default("visible"),
|
|
23592
|
+
text: exports_external.string().min(1),
|
|
23593
|
+
timeoutMs: exports_external.number().min(0).max(120000).optional(),
|
|
23594
|
+
reason: exports_external.string().optional()
|
|
23570
23595
|
})
|
|
23571
23596
|
]);
|
|
23572
23597
|
var caseScriptSchema = exports_external.object({
|
|
@@ -23975,6 +24000,9 @@ var createBuildRequestSchema = exports_external.object({
|
|
|
23975
24000
|
var listBuildsResponseSchema = exports_external.object({
|
|
23976
24001
|
builds: exports_external.array(buildSchema)
|
|
23977
24002
|
});
|
|
24003
|
+
|
|
24004
|
+
// ../../packages/runner-client/src/wait-for-run.ts
|
|
24005
|
+
var DEFAULT_WAIT_FOR_RUN_TIMEOUT_MS = 30 * 60 * 1000;
|
|
23978
24006
|
// ../../packages/runner-client/src/shell-script.ts
|
|
23979
24007
|
var DEFAULT_SHELL_SCRIPT_HEADER = [
|
|
23980
24008
|
"#!/usr/bin/env bash",
|
|
@@ -23984,6 +24012,16 @@ var DEFAULT_SHELL_SCRIPT_HEADER = [
|
|
|
23984
24012
|
""
|
|
23985
24013
|
].join(`
|
|
23986
24014
|
`);
|
|
24015
|
+
function screenHasText(elements, text2) {
|
|
24016
|
+
const needle = text2.trim().toLowerCase();
|
|
24017
|
+
if (!needle)
|
|
24018
|
+
return false;
|
|
24019
|
+
return (elements ?? []).some((el) => {
|
|
24020
|
+
const label = el.label?.toLowerCase() ?? "";
|
|
24021
|
+
const type = el.type?.toLowerCase() ?? "";
|
|
24022
|
+
return label.includes(needle) || type.includes(needle);
|
|
24023
|
+
});
|
|
24024
|
+
}
|
|
23987
24025
|
function findElementByLabel(elements, label) {
|
|
23988
24026
|
const needle = label.trim().toLowerCase();
|
|
23989
24027
|
if (!needle)
|
|
@@ -97429,6 +97467,10 @@ var defaultClock = {
|
|
|
97429
97467
|
};
|
|
97430
97468
|
async function executeScriptCase(deps) {
|
|
97431
97469
|
const perform = deps.performAction ?? performAction;
|
|
97470
|
+
const readScreen = deps.readScreen ?? (async (session) => {
|
|
97471
|
+
const screen = await getScreen(session, { full: false });
|
|
97472
|
+
return { elements: screen.elements };
|
|
97473
|
+
});
|
|
97432
97474
|
const clock = deps.clock ?? defaultClock;
|
|
97433
97475
|
const settleMs = deps.settleMs ?? POST_ACTION_SETTLE_MS;
|
|
97434
97476
|
let stepIdx = 0;
|
|
@@ -97446,7 +97488,16 @@ async function executeScriptCase(deps) {
|
|
|
97446
97488
|
return "cancelled";
|
|
97447
97489
|
}
|
|
97448
97490
|
if (action.type === "tap") {
|
|
97449
|
-
|
|
97491
|
+
const tapBody = { kind: "tap" };
|
|
97492
|
+
if (action.label)
|
|
97493
|
+
tapBody.label = action.label;
|
|
97494
|
+
if (action.id)
|
|
97495
|
+
tapBody.id = action.id;
|
|
97496
|
+
if (action.x != null)
|
|
97497
|
+
tapBody.x = action.x;
|
|
97498
|
+
if (action.y != null)
|
|
97499
|
+
tapBody.y = action.y;
|
|
97500
|
+
await perform(deps.session, tapBody);
|
|
97450
97501
|
await clock.sleep(settleMs);
|
|
97451
97502
|
await deps.appendStep({
|
|
97452
97503
|
idx: stepIdx,
|
|
@@ -97454,13 +97505,15 @@ async function executeScriptCase(deps) {
|
|
|
97454
97505
|
type: "tap",
|
|
97455
97506
|
x: action.x,
|
|
97456
97507
|
y: action.y,
|
|
97508
|
+
label: action.label,
|
|
97509
|
+
id: action.id,
|
|
97457
97510
|
reason: action.reason ?? "Replayed saved script tap",
|
|
97458
97511
|
thoughts: "Replaying the saved script without calling the AI agent."
|
|
97459
97512
|
},
|
|
97460
97513
|
screenshotUri: shot.path,
|
|
97461
97514
|
ok: true,
|
|
97462
97515
|
latencyMs,
|
|
97463
|
-
detail: action.reason ?? null
|
|
97516
|
+
detail: action.reason ?? action.label ?? action.id ?? null
|
|
97464
97517
|
});
|
|
97465
97518
|
} else if (action.type === "type") {
|
|
97466
97519
|
await perform(deps.session, { kind: "input", text: action.text });
|
|
@@ -97478,6 +97531,40 @@ async function executeScriptCase(deps) {
|
|
|
97478
97531
|
latencyMs,
|
|
97479
97532
|
detail: action.reason ?? null
|
|
97480
97533
|
});
|
|
97534
|
+
} else if (action.type === "assert") {
|
|
97535
|
+
const timeoutMs = action.timeoutMs ?? 5000;
|
|
97536
|
+
const assertion = action.assertion;
|
|
97537
|
+
const deadline = clock.now() + timeoutMs;
|
|
97538
|
+
for (;; ) {
|
|
97539
|
+
if (deps.isAborted()) {
|
|
97540
|
+
return "cancelled";
|
|
97541
|
+
}
|
|
97542
|
+
const screen = await readScreen(deps.session);
|
|
97543
|
+
const found = screenHasText(screen.elements, action.text);
|
|
97544
|
+
if (assertion === "visible" && found)
|
|
97545
|
+
break;
|
|
97546
|
+
if (assertion === "not-visible" && !found)
|
|
97547
|
+
break;
|
|
97548
|
+
if (clock.now() >= deadline) {
|
|
97549
|
+
throw new Error(assertion === "visible" ? `Expected visible text not found within ${Math.round(timeoutMs / 1000)}s: ${action.text}` : `Unexpected text still visible after ${Math.round(timeoutMs / 1000)}s: ${action.text}`);
|
|
97550
|
+
}
|
|
97551
|
+
await clock.sleep(400);
|
|
97552
|
+
}
|
|
97553
|
+
await deps.appendStep({
|
|
97554
|
+
idx: stepIdx,
|
|
97555
|
+
action: {
|
|
97556
|
+
type: "assert",
|
|
97557
|
+
assertion,
|
|
97558
|
+
text: action.text,
|
|
97559
|
+
timeoutMs,
|
|
97560
|
+
reason: action.reason ?? `Assert ${assertion}: ${action.text}`,
|
|
97561
|
+
thoughts: "Replaying the saved script without calling the AI agent."
|
|
97562
|
+
},
|
|
97563
|
+
screenshotUri: shot.path,
|
|
97564
|
+
ok: true,
|
|
97565
|
+
latencyMs,
|
|
97566
|
+
detail: action.reason ?? `${assertion}: ${action.text}`
|
|
97567
|
+
});
|
|
97481
97568
|
} else {
|
|
97482
97569
|
const waitMs = Math.min(3000, Math.max(500, action.ms));
|
|
97483
97570
|
await clock.sleep(waitMs);
|
package/package.json
CHANGED