@yoqa/runner 0.3.15 → 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 +126 -30
- 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,6 +17020,12 @@ 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");
|
|
17026
|
+
function iosSessionCreateTimeoutMs(deviceId) {
|
|
17027
|
+
return looksLikePhysicalIosUdid(deviceId) ? PHYSICAL_IOS_SESSION_TIMEOUT_MS : SIMULATOR_WDA_SESSION_TIMEOUT_MS;
|
|
17028
|
+
}
|
|
17023
17029
|
async function buildW3cCapabilities(options, mjpegPort) {
|
|
17024
17030
|
const merged = mergeCapabilities(options.appCaps, options.caseCaps);
|
|
17025
17031
|
const platformName = options.platform === "ios" ? "iOS" : "Android";
|
|
@@ -17038,32 +17044,40 @@ async function buildW3cCapabilities(options, mjpegPort) {
|
|
|
17038
17044
|
if (options.platform === "android" && options.appPackage && !caps["appium:appPackage"]) {
|
|
17039
17045
|
caps["appium:appPackage"] = options.appPackage;
|
|
17040
17046
|
}
|
|
17041
|
-
if (options.platform === "ios"
|
|
17042
|
-
const
|
|
17043
|
-
if (
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17047
|
+
if (options.platform === "ios") {
|
|
17048
|
+
const physical = looksLikePhysicalIosUdid(options.deviceId);
|
|
17049
|
+
if (physical) {
|
|
17050
|
+
const prep = await loadDevicePrep(options.deviceId);
|
|
17051
|
+
if (!prep) {
|
|
17052
|
+
throw new Error(`iOS device ${options.deviceId} is not prepared. Run device setup so WebDriverAgent is installed before starting a run.`);
|
|
17053
|
+
}
|
|
17054
|
+
if (caps["appium:usePreinstalledWDA"] === undefined) {
|
|
17055
|
+
caps["appium:usePreinstalledWDA"] = true;
|
|
17056
|
+
}
|
|
17057
|
+
if (!caps["appium:updatedWDABundleId"]) {
|
|
17058
|
+
caps["appium:updatedWDABundleId"] = prep.bundleId;
|
|
17059
|
+
}
|
|
17060
|
+
if (!caps["appium:xcodeOrgId"]) {
|
|
17061
|
+
caps["appium:xcodeOrgId"] = prep.developmentTeam;
|
|
17062
|
+
}
|
|
17063
|
+
if (!caps["appium:xcodeSigningId"]) {
|
|
17064
|
+
caps["appium:xcodeSigningId"] = "Apple Development";
|
|
17065
|
+
}
|
|
17057
17066
|
}
|
|
17067
|
+
const wdaTimeoutMs = iosSessionCreateTimeoutMs(options.deviceId);
|
|
17058
17068
|
if (caps["appium:wdaLaunchTimeout"] === undefined) {
|
|
17059
|
-
caps["appium:wdaLaunchTimeout"] =
|
|
17069
|
+
caps["appium:wdaLaunchTimeout"] = wdaTimeoutMs;
|
|
17060
17070
|
}
|
|
17061
17071
|
if (caps["appium:wdaConnectionTimeout"] === undefined) {
|
|
17062
|
-
caps["appium:wdaConnectionTimeout"] =
|
|
17072
|
+
caps["appium:wdaConnectionTimeout"] = wdaTimeoutMs;
|
|
17063
17073
|
}
|
|
17064
17074
|
if (caps["appium:waitForIdleTimeout"] === undefined) {
|
|
17065
17075
|
caps["appium:waitForIdleTimeout"] = 0;
|
|
17066
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
|
+
}
|
|
17067
17081
|
}
|
|
17068
17082
|
return caps;
|
|
17069
17083
|
}
|
|
@@ -17285,14 +17299,16 @@ async function createDeviceSession(options) {
|
|
|
17285
17299
|
const port = await ensureAppiumServer();
|
|
17286
17300
|
const mjpegPort = await pickMjpegPort();
|
|
17287
17301
|
const capabilities = await buildW3cCapabilities(options, mjpegPort);
|
|
17302
|
+
const simulatorIos = options.platform === "ios" && !looksLikePhysicalIosUdid(options.deviceId);
|
|
17303
|
+
const sessionCreateTimeoutMs = simulatorIos ? iosSessionCreateTimeoutMs(options.deviceId) : 60000;
|
|
17288
17304
|
const browser = await remote({
|
|
17289
17305
|
hostname: APPIUM_HOST,
|
|
17290
17306
|
port,
|
|
17291
17307
|
path: "/",
|
|
17292
17308
|
capabilities,
|
|
17293
17309
|
logLevel: "silent",
|
|
17294
|
-
connectionRetryCount: 2,
|
|
17295
|
-
connectionRetryTimeout:
|
|
17310
|
+
connectionRetryCount: simulatorIos ? 0 : 2,
|
|
17311
|
+
connectionRetryTimeout: sessionCreateTimeoutMs
|
|
17296
17312
|
});
|
|
17297
17313
|
await applyMjpegSettings(browser, {
|
|
17298
17314
|
platform: options.platform,
|
|
@@ -23542,13 +23558,24 @@ var caseFlowStepSchema = exports_external.object({
|
|
|
23542
23558
|
flowId: exports_external.string().min(1).nullable().optional()
|
|
23543
23559
|
});
|
|
23544
23560
|
var caseRunStatusSchema = exports_external.union([exports_external.literal("passed"), exports_external.literal("errored")]);
|
|
23545
|
-
var
|
|
23546
|
-
exports_external.
|
|
23547
|
-
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23551
|
-
|
|
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,
|
|
23552
23579
|
exports_external.object({
|
|
23553
23580
|
type: exports_external.literal("type"),
|
|
23554
23581
|
text: exports_external.string(),
|
|
@@ -23558,6 +23585,13 @@ var caseScriptActionSchema = exports_external.discriminatedUnion("type", [
|
|
|
23558
23585
|
type: exports_external.literal("wait"),
|
|
23559
23586
|
ms: exports_external.number().min(0).max(1e4),
|
|
23560
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()
|
|
23561
23595
|
})
|
|
23562
23596
|
]);
|
|
23563
23597
|
var caseScriptSchema = exports_external.object({
|
|
@@ -23966,6 +24000,9 @@ var createBuildRequestSchema = exports_external.object({
|
|
|
23966
24000
|
var listBuildsResponseSchema = exports_external.object({
|
|
23967
24001
|
builds: exports_external.array(buildSchema)
|
|
23968
24002
|
});
|
|
24003
|
+
|
|
24004
|
+
// ../../packages/runner-client/src/wait-for-run.ts
|
|
24005
|
+
var DEFAULT_WAIT_FOR_RUN_TIMEOUT_MS = 30 * 60 * 1000;
|
|
23969
24006
|
// ../../packages/runner-client/src/shell-script.ts
|
|
23970
24007
|
var DEFAULT_SHELL_SCRIPT_HEADER = [
|
|
23971
24008
|
"#!/usr/bin/env bash",
|
|
@@ -23975,6 +24012,16 @@ var DEFAULT_SHELL_SCRIPT_HEADER = [
|
|
|
23975
24012
|
""
|
|
23976
24013
|
].join(`
|
|
23977
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
|
+
}
|
|
23978
24025
|
function findElementByLabel(elements, label) {
|
|
23979
24026
|
const needle = label.trim().toLowerCase();
|
|
23980
24027
|
if (!needle)
|
|
@@ -97420,6 +97467,10 @@ var defaultClock = {
|
|
|
97420
97467
|
};
|
|
97421
97468
|
async function executeScriptCase(deps) {
|
|
97422
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
|
+
});
|
|
97423
97474
|
const clock = deps.clock ?? defaultClock;
|
|
97424
97475
|
const settleMs = deps.settleMs ?? POST_ACTION_SETTLE_MS;
|
|
97425
97476
|
let stepIdx = 0;
|
|
@@ -97437,7 +97488,16 @@ async function executeScriptCase(deps) {
|
|
|
97437
97488
|
return "cancelled";
|
|
97438
97489
|
}
|
|
97439
97490
|
if (action.type === "tap") {
|
|
97440
|
-
|
|
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);
|
|
97441
97501
|
await clock.sleep(settleMs);
|
|
97442
97502
|
await deps.appendStep({
|
|
97443
97503
|
idx: stepIdx,
|
|
@@ -97445,13 +97505,15 @@ async function executeScriptCase(deps) {
|
|
|
97445
97505
|
type: "tap",
|
|
97446
97506
|
x: action.x,
|
|
97447
97507
|
y: action.y,
|
|
97508
|
+
label: action.label,
|
|
97509
|
+
id: action.id,
|
|
97448
97510
|
reason: action.reason ?? "Replayed saved script tap",
|
|
97449
97511
|
thoughts: "Replaying the saved script without calling the AI agent."
|
|
97450
97512
|
},
|
|
97451
97513
|
screenshotUri: shot.path,
|
|
97452
97514
|
ok: true,
|
|
97453
97515
|
latencyMs,
|
|
97454
|
-
detail: action.reason ?? null
|
|
97516
|
+
detail: action.reason ?? action.label ?? action.id ?? null
|
|
97455
97517
|
});
|
|
97456
97518
|
} else if (action.type === "type") {
|
|
97457
97519
|
await perform(deps.session, { kind: "input", text: action.text });
|
|
@@ -97469,6 +97531,40 @@ async function executeScriptCase(deps) {
|
|
|
97469
97531
|
latencyMs,
|
|
97470
97532
|
detail: action.reason ?? null
|
|
97471
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
|
+
});
|
|
97472
97568
|
} else {
|
|
97473
97569
|
const waitMs = Math.min(3000, Math.max(500, action.ms));
|
|
97474
97570
|
await clock.sleep(waitMs);
|
package/package.json
CHANGED