@riddledc/riddle-proof 0.7.132 → 0.7.134
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/README.md +6 -1
- package/dist/{chunk-PKE223TX.js → chunk-TALHK3NV.js} +196 -30
- package/dist/cli.cjs +232 -31
- package/dist/cli.js +37 -2
- package/dist/index.cjs +196 -30
- package/dist/index.js +1 -1
- package/dist/profile.cjs +196 -30
- package/dist/profile.d.cts +5 -1
- package/dist/profile.d.ts +5 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -401,7 +401,7 @@ transport control, or other bounded interaction. Supported setup actions are
|
|
|
401
401
|
`assert_text_absent`, `assert_selector_count`, `assert_window_value`,
|
|
402
402
|
`assert_window_number`, `local_storage`, `session_storage`, `clear_storage`,
|
|
403
403
|
`clear_console`, `screenshot`, `wait`, `wait_for_selector`, `wait_for_text`,
|
|
404
|
-
and `
|
|
404
|
+
`window_call`, and `window_call_until`;
|
|
405
405
|
a failed setup action is recorded as a failed `setup_actions_succeeded` check so
|
|
406
406
|
the profile cannot pass without reaching the intended state. Text-matched `click` actions prefer
|
|
407
407
|
visible matching elements, which keeps responsive layouts from selecting hidden
|
|
@@ -447,6 +447,11 @@ errors, but keeps network mock hit evidence intact. Any setup action can include
|
|
|
447
447
|
with `repeat_index` and `repeat_count`, and `after_ms` runs after each
|
|
448
448
|
repetition. Use it for bounded game proof helpers, retry controls, or other
|
|
449
449
|
workflows where one declarative action needs to advance the app several times.
|
|
450
|
+
Use `window_call_until` when a proof helper needs to advance randomized or
|
|
451
|
+
progressive state until a window-state receipt is true. It accepts `path` plus
|
|
452
|
+
optional `args`, `until_path`, `until_expected_value`, `max_calls` from 1 to
|
|
453
|
+
100, and optional `interval_ms`; the action stops early when the predicate is
|
|
454
|
+
met and records `call_count`, final `returned`, and final `until_value`.
|
|
450
455
|
Use `screenshot` with an optional `label` to capture durable Riddle screenshots
|
|
451
456
|
at important setup milestones, such as after a route switch, terminal state, or
|
|
452
457
|
reset. These labels are recorded in setup evidence and included in profile
|
|
@@ -61,7 +61,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
61
61
|
"wait",
|
|
62
62
|
"wait_for_selector",
|
|
63
63
|
"wait_for_text",
|
|
64
|
-
"window_call"
|
|
64
|
+
"window_call",
|
|
65
|
+
"window_call_until"
|
|
65
66
|
];
|
|
66
67
|
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
67
68
|
"aborted",
|
|
@@ -451,6 +452,19 @@ function profileSetupActionCounts(results) {
|
|
|
451
452
|
function profileSetupScreenshotLabels(results) {
|
|
452
453
|
return results.filter((result) => profileSetupResultAction(result) === "screenshot" && result.ok !== false && typeof result.screenshot_label === "string").map((result) => result.screenshot_label).filter(Boolean);
|
|
453
454
|
}
|
|
455
|
+
function profileSetupWindowCallUntilReceipts(results) {
|
|
456
|
+
return results.filter((result) => profileSetupResultAction(result) === "window_call_until").map((result) => ({
|
|
457
|
+
ordinal: result.ordinal ?? null,
|
|
458
|
+
ok: result.ok !== false,
|
|
459
|
+
path: result.path ?? null,
|
|
460
|
+
until_path: result.until_path ?? null,
|
|
461
|
+
until_value: result.until_value ?? null,
|
|
462
|
+
until_expected_value: result.until_expected_value ?? null,
|
|
463
|
+
call_count: result.call_count ?? null,
|
|
464
|
+
max_calls: result.max_calls ?? null,
|
|
465
|
+
reason: result.reason ?? result.error ?? null
|
|
466
|
+
}));
|
|
467
|
+
}
|
|
454
468
|
function sampleProfileSetupSummaryItems(items, limit) {
|
|
455
469
|
if (items.length <= limit) return items;
|
|
456
470
|
const firstCount = Math.floor(limit / 2);
|
|
@@ -476,6 +490,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
476
490
|
const optionalFailed = results.filter((result) => result.ok === false && result.optional === true);
|
|
477
491
|
const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
|
|
478
492
|
const clickCountValues = successfulClicks.map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0).filter((value) => value !== void 0);
|
|
493
|
+
const windowCallUntilReceipts = profileSetupWindowCallUntilReceipts(results);
|
|
494
|
+
const windowCallUntilCallCounts = windowCallUntilReceipts.map((result) => typeof result.call_count === "number" && Number.isFinite(result.call_count) ? result.call_count : void 0).filter((value) => value !== void 0);
|
|
495
|
+
const sampledWindowCallUntilReceipts = sampleProfileSetupSummaryItems(windowCallUntilReceipts, 8);
|
|
479
496
|
const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
|
|
480
497
|
const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
|
|
481
498
|
return {
|
|
@@ -508,6 +525,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
508
525
|
clicked_truncated: clickedItems.length > clicked.length,
|
|
509
526
|
click_count_action_total: clickCountValues.length,
|
|
510
527
|
click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
|
|
528
|
+
window_call_until_total: windowCallUntilReceipts.length,
|
|
529
|
+
window_call_until_call_total: windowCallUntilCallCounts.reduce((sum, value) => sum + value, 0),
|
|
530
|
+
window_call_until_truncated: windowCallUntilReceipts.length > sampledWindowCallUntilReceipts.length,
|
|
531
|
+
window_call_until: sampledWindowCallUntilReceipts,
|
|
511
532
|
clicked,
|
|
512
533
|
text_samples,
|
|
513
534
|
failed: failed.map((result) => ({
|
|
@@ -560,7 +581,7 @@ function isSupportedCheckType(value) {
|
|
|
560
581
|
}
|
|
561
582
|
function normalizeSetupActionType(value, index) {
|
|
562
583
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
563
|
-
const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput;
|
|
584
|
+
const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput;
|
|
564
585
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
565
586
|
return normalized;
|
|
566
587
|
}
|
|
@@ -691,10 +712,10 @@ function normalizeSetupAction(input, index) {
|
|
|
691
712
|
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
692
713
|
}
|
|
693
714
|
const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
|
|
694
|
-
if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path) {
|
|
715
|
+
if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
|
|
695
716
|
throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
|
|
696
717
|
}
|
|
697
|
-
const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
718
|
+
const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
698
719
|
const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
|
|
699
720
|
if (type === "assert_window_value" && !hasExpectedValue) {
|
|
700
721
|
throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
|
|
@@ -711,6 +732,24 @@ function normalizeSetupAction(input, index) {
|
|
|
711
732
|
}
|
|
712
733
|
}
|
|
713
734
|
const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
|
|
735
|
+
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
736
|
+
const hasUntilExpectedValue = hasOwn(input, "until_expected_value") || hasOwn(input, "untilExpectedValue") || hasOwn(input, "until_expected") || hasOwn(input, "untilExpected") || hasOwn(input, "until_value") || hasOwn(input, "untilValue") || hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected");
|
|
737
|
+
if (type === "window_call_until") {
|
|
738
|
+
if (!untilPath) {
|
|
739
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
740
|
+
}
|
|
741
|
+
if (!hasUntilExpectedValue) {
|
|
742
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
746
|
+
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
747
|
+
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
748
|
+
}
|
|
749
|
+
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
750
|
+
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
751
|
+
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
752
|
+
}
|
|
714
753
|
const steps = numberValue(input.steps);
|
|
715
754
|
if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
|
|
716
755
|
throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
|
|
@@ -737,6 +776,10 @@ function normalizeSetupAction(input, index) {
|
|
|
737
776
|
path,
|
|
738
777
|
args,
|
|
739
778
|
expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
|
|
779
|
+
until_path: untilPath,
|
|
780
|
+
until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
|
|
781
|
+
max_calls: maxCalls,
|
|
782
|
+
interval_ms: intervalMs,
|
|
740
783
|
expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
|
|
741
784
|
min_value: minValue,
|
|
742
785
|
max_value: maxValue,
|
|
@@ -4613,6 +4656,34 @@ async function setupReadWindowValue(context, path) {
|
|
|
4613
4656
|
return { ok: true, value: toJsonValue(current) };
|
|
4614
4657
|
}, { path });
|
|
4615
4658
|
}
|
|
4659
|
+
async function setupCallWindowFunction(context, path, args) {
|
|
4660
|
+
return await context.evaluate(async ({ path, args }) => {
|
|
4661
|
+
const toJsonValue = (value) => {
|
|
4662
|
+
if (value === null || value === undefined) return null;
|
|
4663
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
4664
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
4665
|
+
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
4666
|
+
if (typeof value === "object") {
|
|
4667
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
4668
|
+
}
|
|
4669
|
+
return String(value);
|
|
4670
|
+
};
|
|
4671
|
+
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
4672
|
+
let parent = window;
|
|
4673
|
+
let current = window;
|
|
4674
|
+
for (const part of pathParts) {
|
|
4675
|
+
parent = current;
|
|
4676
|
+
current = current?.[part];
|
|
4677
|
+
}
|
|
4678
|
+
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
4679
|
+
try {
|
|
4680
|
+
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
4681
|
+
return { ok: true, returned: toJsonValue(returned) };
|
|
4682
|
+
} catch (error) {
|
|
4683
|
+
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
4684
|
+
}
|
|
4685
|
+
}, { path, args });
|
|
4686
|
+
}
|
|
4616
4687
|
function setupFrameSelector(action) {
|
|
4617
4688
|
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
4618
4689
|
}
|
|
@@ -5130,32 +5201,7 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5130
5201
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5131
5202
|
const scope = await setupActionScope(action, timeout);
|
|
5132
5203
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
5133
|
-
const result = await scope.context
|
|
5134
|
-
const toJsonValue = (value) => {
|
|
5135
|
-
if (value === null || value === undefined) return null;
|
|
5136
|
-
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
5137
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
5138
|
-
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
5139
|
-
if (typeof value === "object") {
|
|
5140
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
5141
|
-
}
|
|
5142
|
-
return String(value);
|
|
5143
|
-
};
|
|
5144
|
-
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
5145
|
-
let parent = window;
|
|
5146
|
-
let current = window;
|
|
5147
|
-
for (const part of pathParts) {
|
|
5148
|
-
parent = current;
|
|
5149
|
-
current = current?.[part];
|
|
5150
|
-
}
|
|
5151
|
-
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
5152
|
-
try {
|
|
5153
|
-
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
5154
|
-
return { ok: true, returned: toJsonValue(returned) };
|
|
5155
|
-
} catch (error) {
|
|
5156
|
-
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
5157
|
-
}
|
|
5158
|
-
}, { path, args });
|
|
5204
|
+
const result = await setupCallWindowFunction(scope.context, path, args);
|
|
5159
5205
|
const hasExpectation = setupHasOwn(action, "expect_return")
|
|
5160
5206
|
|| setupHasOwn(action, "expectReturn")
|
|
5161
5207
|
|| setupHasOwn(action, "expected_return")
|
|
@@ -5180,6 +5226,126 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5180
5226
|
error: result.error || undefined,
|
|
5181
5227
|
};
|
|
5182
5228
|
}
|
|
5229
|
+
if (type === "window_call_until") {
|
|
5230
|
+
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
5231
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
5232
|
+
const args = Array.isArray(action.args) ? action.args : [];
|
|
5233
|
+
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5234
|
+
if (!untilPath) return { ...base, path, reason: "missing_until_path" };
|
|
5235
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
5236
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
5237
|
+
|| setupHasOwn(action, "until_expected")
|
|
5238
|
+
|| setupHasOwn(action, "untilExpected")
|
|
5239
|
+
|| setupHasOwn(action, "until_value")
|
|
5240
|
+
|| setupHasOwn(action, "untilValue")
|
|
5241
|
+
|| setupHasOwn(action, "expected_value")
|
|
5242
|
+
|| setupHasOwn(action, "expectedValue")
|
|
5243
|
+
|| setupHasOwn(action, "expected");
|
|
5244
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
5245
|
+
? action.until_expected_value
|
|
5246
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
5247
|
+
? action.untilExpectedValue
|
|
5248
|
+
: setupHasOwn(action, "until_expected")
|
|
5249
|
+
? action.until_expected
|
|
5250
|
+
: setupHasOwn(action, "untilExpected")
|
|
5251
|
+
? action.untilExpected
|
|
5252
|
+
: setupHasOwn(action, "until_value")
|
|
5253
|
+
? action.until_value
|
|
5254
|
+
: setupHasOwn(action, "untilValue")
|
|
5255
|
+
? action.untilValue
|
|
5256
|
+
: setupHasOwn(action, "expected_value")
|
|
5257
|
+
? action.expected_value
|
|
5258
|
+
: setupHasOwn(action, "expectedValue")
|
|
5259
|
+
? action.expectedValue
|
|
5260
|
+
: action.expected;
|
|
5261
|
+
if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
5262
|
+
const maxCalls = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
|
|
5263
|
+
const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.call_interval_ms ?? action.callIntervalMs, 100) || 0)));
|
|
5264
|
+
const hasReturnExpectation = setupHasOwn(action, "expect_return")
|
|
5265
|
+
|| setupHasOwn(action, "expectReturn")
|
|
5266
|
+
|| setupHasOwn(action, "expected_return")
|
|
5267
|
+
|| setupHasOwn(action, "expectedReturn");
|
|
5268
|
+
const expectedReturn = setupHasOwn(action, "expect_return")
|
|
5269
|
+
? action.expect_return
|
|
5270
|
+
: setupHasOwn(action, "expectReturn")
|
|
5271
|
+
? action.expectReturn
|
|
5272
|
+
: setupHasOwn(action, "expected_return")
|
|
5273
|
+
? action.expected_return
|
|
5274
|
+
: action.expectedReturn;
|
|
5275
|
+
const scope = await setupActionScope(action, timeout);
|
|
5276
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
5277
|
+
const startedAt = Date.now();
|
|
5278
|
+
let callCount = 0;
|
|
5279
|
+
let lastCallResult = null;
|
|
5280
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5281
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5282
|
+
return {
|
|
5283
|
+
...base,
|
|
5284
|
+
...setupScopeEvidence(scope),
|
|
5285
|
+
ok: true,
|
|
5286
|
+
path,
|
|
5287
|
+
arg_count: args.length,
|
|
5288
|
+
until_path: untilPath,
|
|
5289
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5290
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5291
|
+
call_count: callCount,
|
|
5292
|
+
max_calls: maxCalls,
|
|
5293
|
+
interval_ms: intervalMs,
|
|
5294
|
+
timeout_ms: timeout,
|
|
5295
|
+
};
|
|
5296
|
+
}
|
|
5297
|
+
while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
|
|
5298
|
+
lastCallResult = await setupCallWindowFunction(scope.context, path, args);
|
|
5299
|
+
callCount += 1;
|
|
5300
|
+
if (!lastCallResult.ok) break;
|
|
5301
|
+
if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
|
|
5302
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5303
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5304
|
+
return {
|
|
5305
|
+
...base,
|
|
5306
|
+
...setupScopeEvidence(scope),
|
|
5307
|
+
ok: true,
|
|
5308
|
+
path,
|
|
5309
|
+
arg_count: args.length,
|
|
5310
|
+
returned: setupJsonValue(lastCallResult.returned),
|
|
5311
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5312
|
+
until_path: untilPath,
|
|
5313
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5314
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5315
|
+
call_count: callCount,
|
|
5316
|
+
max_calls: maxCalls,
|
|
5317
|
+
interval_ms: intervalMs,
|
|
5318
|
+
timeout_ms: timeout,
|
|
5319
|
+
};
|
|
5320
|
+
}
|
|
5321
|
+
if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
|
|
5322
|
+
}
|
|
5323
|
+
const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
|
|
5324
|
+
return {
|
|
5325
|
+
...base,
|
|
5326
|
+
...setupScopeEvidence(scope),
|
|
5327
|
+
path,
|
|
5328
|
+
arg_count: args.length,
|
|
5329
|
+
returned: setupJsonValue(lastCallResult?.returned),
|
|
5330
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5331
|
+
until_path: untilPath,
|
|
5332
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
5333
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5334
|
+
call_count: callCount,
|
|
5335
|
+
max_calls: maxCalls,
|
|
5336
|
+
interval_ms: intervalMs,
|
|
5337
|
+
timeout_ms: timeout,
|
|
5338
|
+
reason: lastCallResult && !lastCallResult.ok
|
|
5339
|
+
? lastCallResult.reason
|
|
5340
|
+
: hasReturnExpectation && !returnExpectationMet
|
|
5341
|
+
? "unexpected_return_value"
|
|
5342
|
+
: Date.now() - startedAt > timeout
|
|
5343
|
+
? "timeout"
|
|
5344
|
+
: "until_condition_not_met",
|
|
5345
|
+
error: lastCallResult?.error || undefined,
|
|
5346
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
5347
|
+
};
|
|
5348
|
+
}
|
|
5183
5349
|
if (type === "assert_window_value") {
|
|
5184
5350
|
const path = String(action.path || action.window_path || action.windowPath || "");
|
|
5185
5351
|
const hasExpected = setupHasOwn(action, "expected_value")
|