@riddledc/riddle-proof 0.7.132 → 0.7.133
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-TA2KLHMX.js} +176 -30
- package/dist/cli.cjs +176 -30
- package/dist/cli.js +1 -1
- package/dist/index.cjs +176 -30
- package/dist/index.js +1 -1
- package/dist/profile.cjs +176 -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",
|
|
@@ -560,7 +561,7 @@ function isSupportedCheckType(value) {
|
|
|
560
561
|
}
|
|
561
562
|
function normalizeSetupActionType(value, index) {
|
|
562
563
|
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;
|
|
564
|
+
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
565
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
565
566
|
return normalized;
|
|
566
567
|
}
|
|
@@ -691,10 +692,10 @@ function normalizeSetupAction(input, index) {
|
|
|
691
692
|
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
692
693
|
}
|
|
693
694
|
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) {
|
|
695
|
+
if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
|
|
695
696
|
throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
|
|
696
697
|
}
|
|
697
|
-
const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
698
|
+
const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
698
699
|
const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
|
|
699
700
|
if (type === "assert_window_value" && !hasExpectedValue) {
|
|
700
701
|
throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
|
|
@@ -711,6 +712,24 @@ function normalizeSetupAction(input, index) {
|
|
|
711
712
|
}
|
|
712
713
|
}
|
|
713
714
|
const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
|
|
715
|
+
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
716
|
+
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");
|
|
717
|
+
if (type === "window_call_until") {
|
|
718
|
+
if (!untilPath) {
|
|
719
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
720
|
+
}
|
|
721
|
+
if (!hasUntilExpectedValue) {
|
|
722
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
726
|
+
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
727
|
+
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
728
|
+
}
|
|
729
|
+
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
730
|
+
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
731
|
+
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
732
|
+
}
|
|
714
733
|
const steps = numberValue(input.steps);
|
|
715
734
|
if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
|
|
716
735
|
throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
|
|
@@ -737,6 +756,10 @@ function normalizeSetupAction(input, index) {
|
|
|
737
756
|
path,
|
|
738
757
|
args,
|
|
739
758
|
expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
|
|
759
|
+
until_path: untilPath,
|
|
760
|
+
until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
|
|
761
|
+
max_calls: maxCalls,
|
|
762
|
+
interval_ms: intervalMs,
|
|
740
763
|
expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
|
|
741
764
|
min_value: minValue,
|
|
742
765
|
max_value: maxValue,
|
|
@@ -4613,6 +4636,34 @@ async function setupReadWindowValue(context, path) {
|
|
|
4613
4636
|
return { ok: true, value: toJsonValue(current) };
|
|
4614
4637
|
}, { path });
|
|
4615
4638
|
}
|
|
4639
|
+
async function setupCallWindowFunction(context, path, args) {
|
|
4640
|
+
return await context.evaluate(async ({ path, args }) => {
|
|
4641
|
+
const toJsonValue = (value) => {
|
|
4642
|
+
if (value === null || value === undefined) return null;
|
|
4643
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
4644
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
4645
|
+
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
4646
|
+
if (typeof value === "object") {
|
|
4647
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
4648
|
+
}
|
|
4649
|
+
return String(value);
|
|
4650
|
+
};
|
|
4651
|
+
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
4652
|
+
let parent = window;
|
|
4653
|
+
let current = window;
|
|
4654
|
+
for (const part of pathParts) {
|
|
4655
|
+
parent = current;
|
|
4656
|
+
current = current?.[part];
|
|
4657
|
+
}
|
|
4658
|
+
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
4659
|
+
try {
|
|
4660
|
+
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
4661
|
+
return { ok: true, returned: toJsonValue(returned) };
|
|
4662
|
+
} catch (error) {
|
|
4663
|
+
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
4664
|
+
}
|
|
4665
|
+
}, { path, args });
|
|
4666
|
+
}
|
|
4616
4667
|
function setupFrameSelector(action) {
|
|
4617
4668
|
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
4618
4669
|
}
|
|
@@ -5130,32 +5181,7 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5130
5181
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5131
5182
|
const scope = await setupActionScope(action, timeout);
|
|
5132
5183
|
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 });
|
|
5184
|
+
const result = await setupCallWindowFunction(scope.context, path, args);
|
|
5159
5185
|
const hasExpectation = setupHasOwn(action, "expect_return")
|
|
5160
5186
|
|| setupHasOwn(action, "expectReturn")
|
|
5161
5187
|
|| setupHasOwn(action, "expected_return")
|
|
@@ -5180,6 +5206,126 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5180
5206
|
error: result.error || undefined,
|
|
5181
5207
|
};
|
|
5182
5208
|
}
|
|
5209
|
+
if (type === "window_call_until") {
|
|
5210
|
+
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
5211
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
5212
|
+
const args = Array.isArray(action.args) ? action.args : [];
|
|
5213
|
+
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5214
|
+
if (!untilPath) return { ...base, path, reason: "missing_until_path" };
|
|
5215
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
5216
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
5217
|
+
|| setupHasOwn(action, "until_expected")
|
|
5218
|
+
|| setupHasOwn(action, "untilExpected")
|
|
5219
|
+
|| setupHasOwn(action, "until_value")
|
|
5220
|
+
|| setupHasOwn(action, "untilValue")
|
|
5221
|
+
|| setupHasOwn(action, "expected_value")
|
|
5222
|
+
|| setupHasOwn(action, "expectedValue")
|
|
5223
|
+
|| setupHasOwn(action, "expected");
|
|
5224
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
5225
|
+
? action.until_expected_value
|
|
5226
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
5227
|
+
? action.untilExpectedValue
|
|
5228
|
+
: setupHasOwn(action, "until_expected")
|
|
5229
|
+
? action.until_expected
|
|
5230
|
+
: setupHasOwn(action, "untilExpected")
|
|
5231
|
+
? action.untilExpected
|
|
5232
|
+
: setupHasOwn(action, "until_value")
|
|
5233
|
+
? action.until_value
|
|
5234
|
+
: setupHasOwn(action, "untilValue")
|
|
5235
|
+
? action.untilValue
|
|
5236
|
+
: setupHasOwn(action, "expected_value")
|
|
5237
|
+
? action.expected_value
|
|
5238
|
+
: setupHasOwn(action, "expectedValue")
|
|
5239
|
+
? action.expectedValue
|
|
5240
|
+
: action.expected;
|
|
5241
|
+
if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
5242
|
+
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)));
|
|
5243
|
+
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)));
|
|
5244
|
+
const hasReturnExpectation = setupHasOwn(action, "expect_return")
|
|
5245
|
+
|| setupHasOwn(action, "expectReturn")
|
|
5246
|
+
|| setupHasOwn(action, "expected_return")
|
|
5247
|
+
|| setupHasOwn(action, "expectedReturn");
|
|
5248
|
+
const expectedReturn = setupHasOwn(action, "expect_return")
|
|
5249
|
+
? action.expect_return
|
|
5250
|
+
: setupHasOwn(action, "expectReturn")
|
|
5251
|
+
? action.expectReturn
|
|
5252
|
+
: setupHasOwn(action, "expected_return")
|
|
5253
|
+
? action.expected_return
|
|
5254
|
+
: action.expectedReturn;
|
|
5255
|
+
const scope = await setupActionScope(action, timeout);
|
|
5256
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
5257
|
+
const startedAt = Date.now();
|
|
5258
|
+
let callCount = 0;
|
|
5259
|
+
let lastCallResult = null;
|
|
5260
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5261
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5262
|
+
return {
|
|
5263
|
+
...base,
|
|
5264
|
+
...setupScopeEvidence(scope),
|
|
5265
|
+
ok: true,
|
|
5266
|
+
path,
|
|
5267
|
+
arg_count: args.length,
|
|
5268
|
+
until_path: untilPath,
|
|
5269
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5270
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5271
|
+
call_count: callCount,
|
|
5272
|
+
max_calls: maxCalls,
|
|
5273
|
+
interval_ms: intervalMs,
|
|
5274
|
+
timeout_ms: timeout,
|
|
5275
|
+
};
|
|
5276
|
+
}
|
|
5277
|
+
while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
|
|
5278
|
+
lastCallResult = await setupCallWindowFunction(scope.context, path, args);
|
|
5279
|
+
callCount += 1;
|
|
5280
|
+
if (!lastCallResult.ok) break;
|
|
5281
|
+
if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
|
|
5282
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5283
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5284
|
+
return {
|
|
5285
|
+
...base,
|
|
5286
|
+
...setupScopeEvidence(scope),
|
|
5287
|
+
ok: true,
|
|
5288
|
+
path,
|
|
5289
|
+
arg_count: args.length,
|
|
5290
|
+
returned: setupJsonValue(lastCallResult.returned),
|
|
5291
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5292
|
+
until_path: untilPath,
|
|
5293
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5294
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5295
|
+
call_count: callCount,
|
|
5296
|
+
max_calls: maxCalls,
|
|
5297
|
+
interval_ms: intervalMs,
|
|
5298
|
+
timeout_ms: timeout,
|
|
5299
|
+
};
|
|
5300
|
+
}
|
|
5301
|
+
if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
|
|
5302
|
+
}
|
|
5303
|
+
const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
|
|
5304
|
+
return {
|
|
5305
|
+
...base,
|
|
5306
|
+
...setupScopeEvidence(scope),
|
|
5307
|
+
path,
|
|
5308
|
+
arg_count: args.length,
|
|
5309
|
+
returned: setupJsonValue(lastCallResult?.returned),
|
|
5310
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5311
|
+
until_path: untilPath,
|
|
5312
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
5313
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5314
|
+
call_count: callCount,
|
|
5315
|
+
max_calls: maxCalls,
|
|
5316
|
+
interval_ms: intervalMs,
|
|
5317
|
+
timeout_ms: timeout,
|
|
5318
|
+
reason: lastCallResult && !lastCallResult.ok
|
|
5319
|
+
? lastCallResult.reason
|
|
5320
|
+
: hasReturnExpectation && !returnExpectationMet
|
|
5321
|
+
? "unexpected_return_value"
|
|
5322
|
+
: Date.now() - startedAt > timeout
|
|
5323
|
+
? "timeout"
|
|
5324
|
+
: "until_condition_not_met",
|
|
5325
|
+
error: lastCallResult?.error || undefined,
|
|
5326
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
5327
|
+
};
|
|
5328
|
+
}
|
|
5183
5329
|
if (type === "assert_window_value") {
|
|
5184
5330
|
const path = String(action.path || action.window_path || action.windowPath || "");
|
|
5185
5331
|
const hasExpected = setupHasOwn(action, "expected_value")
|
package/dist/cli.cjs
CHANGED
|
@@ -6998,7 +6998,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
6998
6998
|
"wait",
|
|
6999
6999
|
"wait_for_selector",
|
|
7000
7000
|
"wait_for_text",
|
|
7001
|
-
"window_call"
|
|
7001
|
+
"window_call",
|
|
7002
|
+
"window_call_until"
|
|
7002
7003
|
];
|
|
7003
7004
|
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
7004
7005
|
"aborted",
|
|
@@ -7497,7 +7498,7 @@ function isSupportedCheckType(value) {
|
|
|
7497
7498
|
}
|
|
7498
7499
|
function normalizeSetupActionType(value, index) {
|
|
7499
7500
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
7500
|
-
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;
|
|
7501
|
+
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;
|
|
7501
7502
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
7502
7503
|
return normalized;
|
|
7503
7504
|
}
|
|
@@ -7628,10 +7629,10 @@ function normalizeSetupAction(input, index) {
|
|
|
7628
7629
|
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
7629
7630
|
}
|
|
7630
7631
|
const path7 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
|
|
7631
|
-
if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path7) {
|
|
7632
|
+
if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path7) {
|
|
7632
7633
|
throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
|
|
7633
7634
|
}
|
|
7634
|
-
const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
7635
|
+
const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
7635
7636
|
const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
|
|
7636
7637
|
if (type === "assert_window_value" && !hasExpectedValue) {
|
|
7637
7638
|
throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
|
|
@@ -7648,6 +7649,24 @@ function normalizeSetupAction(input, index) {
|
|
|
7648
7649
|
}
|
|
7649
7650
|
}
|
|
7650
7651
|
const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
|
|
7652
|
+
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
7653
|
+
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");
|
|
7654
|
+
if (type === "window_call_until") {
|
|
7655
|
+
if (!untilPath) {
|
|
7656
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
7657
|
+
}
|
|
7658
|
+
if (!hasUntilExpectedValue) {
|
|
7659
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
7663
|
+
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
7664
|
+
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
7665
|
+
}
|
|
7666
|
+
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
7667
|
+
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
7668
|
+
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
7669
|
+
}
|
|
7651
7670
|
const steps = numberValue(input.steps);
|
|
7652
7671
|
if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
|
|
7653
7672
|
throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
|
|
@@ -7674,6 +7693,10 @@ function normalizeSetupAction(input, index) {
|
|
|
7674
7693
|
path: path7,
|
|
7675
7694
|
args,
|
|
7676
7695
|
expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
|
|
7696
|
+
until_path: untilPath,
|
|
7697
|
+
until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
|
|
7698
|
+
max_calls: maxCalls,
|
|
7699
|
+
interval_ms: intervalMs,
|
|
7677
7700
|
expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
|
|
7678
7701
|
min_value: minValue,
|
|
7679
7702
|
max_value: maxValue,
|
|
@@ -11534,6 +11557,34 @@ async function setupReadWindowValue(context, path) {
|
|
|
11534
11557
|
return { ok: true, value: toJsonValue(current) };
|
|
11535
11558
|
}, { path });
|
|
11536
11559
|
}
|
|
11560
|
+
async function setupCallWindowFunction(context, path, args) {
|
|
11561
|
+
return await context.evaluate(async ({ path, args }) => {
|
|
11562
|
+
const toJsonValue = (value) => {
|
|
11563
|
+
if (value === null || value === undefined) return null;
|
|
11564
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
11565
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
11566
|
+
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
11567
|
+
if (typeof value === "object") {
|
|
11568
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
11569
|
+
}
|
|
11570
|
+
return String(value);
|
|
11571
|
+
};
|
|
11572
|
+
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
11573
|
+
let parent = window;
|
|
11574
|
+
let current = window;
|
|
11575
|
+
for (const part of pathParts) {
|
|
11576
|
+
parent = current;
|
|
11577
|
+
current = current?.[part];
|
|
11578
|
+
}
|
|
11579
|
+
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
11580
|
+
try {
|
|
11581
|
+
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
11582
|
+
return { ok: true, returned: toJsonValue(returned) };
|
|
11583
|
+
} catch (error) {
|
|
11584
|
+
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
11585
|
+
}
|
|
11586
|
+
}, { path, args });
|
|
11587
|
+
}
|
|
11537
11588
|
function setupFrameSelector(action) {
|
|
11538
11589
|
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
11539
11590
|
}
|
|
@@ -12051,32 +12102,7 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
12051
12102
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
12052
12103
|
const scope = await setupActionScope(action, timeout);
|
|
12053
12104
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
12054
|
-
const result = await scope.context
|
|
12055
|
-
const toJsonValue = (value) => {
|
|
12056
|
-
if (value === null || value === undefined) return null;
|
|
12057
|
-
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
12058
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
12059
|
-
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
12060
|
-
if (typeof value === "object") {
|
|
12061
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
12062
|
-
}
|
|
12063
|
-
return String(value);
|
|
12064
|
-
};
|
|
12065
|
-
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
12066
|
-
let parent = window;
|
|
12067
|
-
let current = window;
|
|
12068
|
-
for (const part of pathParts) {
|
|
12069
|
-
parent = current;
|
|
12070
|
-
current = current?.[part];
|
|
12071
|
-
}
|
|
12072
|
-
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
12073
|
-
try {
|
|
12074
|
-
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
12075
|
-
return { ok: true, returned: toJsonValue(returned) };
|
|
12076
|
-
} catch (error) {
|
|
12077
|
-
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
12078
|
-
}
|
|
12079
|
-
}, { path, args });
|
|
12105
|
+
const result = await setupCallWindowFunction(scope.context, path, args);
|
|
12080
12106
|
const hasExpectation = setupHasOwn(action, "expect_return")
|
|
12081
12107
|
|| setupHasOwn(action, "expectReturn")
|
|
12082
12108
|
|| setupHasOwn(action, "expected_return")
|
|
@@ -12101,6 +12127,126 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
12101
12127
|
error: result.error || undefined,
|
|
12102
12128
|
};
|
|
12103
12129
|
}
|
|
12130
|
+
if (type === "window_call_until") {
|
|
12131
|
+
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
12132
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
12133
|
+
const args = Array.isArray(action.args) ? action.args : [];
|
|
12134
|
+
if (!path) return { ...base, path, reason: "missing_path" };
|
|
12135
|
+
if (!untilPath) return { ...base, path, reason: "missing_until_path" };
|
|
12136
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
12137
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
12138
|
+
|| setupHasOwn(action, "until_expected")
|
|
12139
|
+
|| setupHasOwn(action, "untilExpected")
|
|
12140
|
+
|| setupHasOwn(action, "until_value")
|
|
12141
|
+
|| setupHasOwn(action, "untilValue")
|
|
12142
|
+
|| setupHasOwn(action, "expected_value")
|
|
12143
|
+
|| setupHasOwn(action, "expectedValue")
|
|
12144
|
+
|| setupHasOwn(action, "expected");
|
|
12145
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
12146
|
+
? action.until_expected_value
|
|
12147
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
12148
|
+
? action.untilExpectedValue
|
|
12149
|
+
: setupHasOwn(action, "until_expected")
|
|
12150
|
+
? action.until_expected
|
|
12151
|
+
: setupHasOwn(action, "untilExpected")
|
|
12152
|
+
? action.untilExpected
|
|
12153
|
+
: setupHasOwn(action, "until_value")
|
|
12154
|
+
? action.until_value
|
|
12155
|
+
: setupHasOwn(action, "untilValue")
|
|
12156
|
+
? action.untilValue
|
|
12157
|
+
: setupHasOwn(action, "expected_value")
|
|
12158
|
+
? action.expected_value
|
|
12159
|
+
: setupHasOwn(action, "expectedValue")
|
|
12160
|
+
? action.expectedValue
|
|
12161
|
+
: action.expected;
|
|
12162
|
+
if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
12163
|
+
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)));
|
|
12164
|
+
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)));
|
|
12165
|
+
const hasReturnExpectation = setupHasOwn(action, "expect_return")
|
|
12166
|
+
|| setupHasOwn(action, "expectReturn")
|
|
12167
|
+
|| setupHasOwn(action, "expected_return")
|
|
12168
|
+
|| setupHasOwn(action, "expectedReturn");
|
|
12169
|
+
const expectedReturn = setupHasOwn(action, "expect_return")
|
|
12170
|
+
? action.expect_return
|
|
12171
|
+
: setupHasOwn(action, "expectReturn")
|
|
12172
|
+
? action.expectReturn
|
|
12173
|
+
: setupHasOwn(action, "expected_return")
|
|
12174
|
+
? action.expected_return
|
|
12175
|
+
: action.expectedReturn;
|
|
12176
|
+
const scope = await setupActionScope(action, timeout);
|
|
12177
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
12178
|
+
const startedAt = Date.now();
|
|
12179
|
+
let callCount = 0;
|
|
12180
|
+
let lastCallResult = null;
|
|
12181
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
12182
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
12183
|
+
return {
|
|
12184
|
+
...base,
|
|
12185
|
+
...setupScopeEvidence(scope),
|
|
12186
|
+
ok: true,
|
|
12187
|
+
path,
|
|
12188
|
+
arg_count: args.length,
|
|
12189
|
+
until_path: untilPath,
|
|
12190
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
12191
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
12192
|
+
call_count: callCount,
|
|
12193
|
+
max_calls: maxCalls,
|
|
12194
|
+
interval_ms: intervalMs,
|
|
12195
|
+
timeout_ms: timeout,
|
|
12196
|
+
};
|
|
12197
|
+
}
|
|
12198
|
+
while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
|
|
12199
|
+
lastCallResult = await setupCallWindowFunction(scope.context, path, args);
|
|
12200
|
+
callCount += 1;
|
|
12201
|
+
if (!lastCallResult.ok) break;
|
|
12202
|
+
if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
|
|
12203
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
12204
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
12205
|
+
return {
|
|
12206
|
+
...base,
|
|
12207
|
+
...setupScopeEvidence(scope),
|
|
12208
|
+
ok: true,
|
|
12209
|
+
path,
|
|
12210
|
+
arg_count: args.length,
|
|
12211
|
+
returned: setupJsonValue(lastCallResult.returned),
|
|
12212
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
12213
|
+
until_path: untilPath,
|
|
12214
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
12215
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
12216
|
+
call_count: callCount,
|
|
12217
|
+
max_calls: maxCalls,
|
|
12218
|
+
interval_ms: intervalMs,
|
|
12219
|
+
timeout_ms: timeout,
|
|
12220
|
+
};
|
|
12221
|
+
}
|
|
12222
|
+
if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
|
|
12223
|
+
}
|
|
12224
|
+
const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
|
|
12225
|
+
return {
|
|
12226
|
+
...base,
|
|
12227
|
+
...setupScopeEvidence(scope),
|
|
12228
|
+
path,
|
|
12229
|
+
arg_count: args.length,
|
|
12230
|
+
returned: setupJsonValue(lastCallResult?.returned),
|
|
12231
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
12232
|
+
until_path: untilPath,
|
|
12233
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
12234
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
12235
|
+
call_count: callCount,
|
|
12236
|
+
max_calls: maxCalls,
|
|
12237
|
+
interval_ms: intervalMs,
|
|
12238
|
+
timeout_ms: timeout,
|
|
12239
|
+
reason: lastCallResult && !lastCallResult.ok
|
|
12240
|
+
? lastCallResult.reason
|
|
12241
|
+
: hasReturnExpectation && !returnExpectationMet
|
|
12242
|
+
? "unexpected_return_value"
|
|
12243
|
+
: Date.now() - startedAt > timeout
|
|
12244
|
+
? "timeout"
|
|
12245
|
+
: "until_condition_not_met",
|
|
12246
|
+
error: lastCallResult?.error || undefined,
|
|
12247
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
12248
|
+
};
|
|
12249
|
+
}
|
|
12104
12250
|
if (type === "assert_window_value") {
|
|
12105
12251
|
const path = String(action.path || action.window_path || action.windowPath || "");
|
|
12106
12252
|
const hasExpected = setupHasOwn(action, "expected_value")
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8794,7 +8794,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
8794
8794
|
"wait",
|
|
8795
8795
|
"wait_for_selector",
|
|
8796
8796
|
"wait_for_text",
|
|
8797
|
-
"window_call"
|
|
8797
|
+
"window_call",
|
|
8798
|
+
"window_call_until"
|
|
8798
8799
|
];
|
|
8799
8800
|
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
8800
8801
|
"aborted",
|
|
@@ -9293,7 +9294,7 @@ function isSupportedCheckType(value) {
|
|
|
9293
9294
|
}
|
|
9294
9295
|
function normalizeSetupActionType(value, index) {
|
|
9295
9296
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
9296
|
-
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;
|
|
9297
|
+
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;
|
|
9297
9298
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
9298
9299
|
return normalized;
|
|
9299
9300
|
}
|
|
@@ -9424,10 +9425,10 @@ function normalizeSetupAction(input, index) {
|
|
|
9424
9425
|
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
9425
9426
|
}
|
|
9426
9427
|
const path6 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
|
|
9427
|
-
if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path6) {
|
|
9428
|
+
if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path6) {
|
|
9428
9429
|
throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
|
|
9429
9430
|
}
|
|
9430
|
-
const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
9431
|
+
const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
9431
9432
|
const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
|
|
9432
9433
|
if (type === "assert_window_value" && !hasExpectedValue) {
|
|
9433
9434
|
throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
|
|
@@ -9444,6 +9445,24 @@ function normalizeSetupAction(input, index) {
|
|
|
9444
9445
|
}
|
|
9445
9446
|
}
|
|
9446
9447
|
const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
|
|
9448
|
+
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
9449
|
+
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");
|
|
9450
|
+
if (type === "window_call_until") {
|
|
9451
|
+
if (!untilPath) {
|
|
9452
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
9453
|
+
}
|
|
9454
|
+
if (!hasUntilExpectedValue) {
|
|
9455
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
9456
|
+
}
|
|
9457
|
+
}
|
|
9458
|
+
const maxCalls = numberValue3(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
9459
|
+
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
9460
|
+
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
9461
|
+
}
|
|
9462
|
+
const intervalMs = numberValue3(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
9463
|
+
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
9464
|
+
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
9465
|
+
}
|
|
9447
9466
|
const steps = numberValue3(input.steps);
|
|
9448
9467
|
if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
|
|
9449
9468
|
throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
|
|
@@ -9470,6 +9489,10 @@ function normalizeSetupAction(input, index) {
|
|
|
9470
9489
|
path: path6,
|
|
9471
9490
|
args,
|
|
9472
9491
|
expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
|
|
9492
|
+
until_path: untilPath,
|
|
9493
|
+
until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
|
|
9494
|
+
max_calls: maxCalls,
|
|
9495
|
+
interval_ms: intervalMs,
|
|
9473
9496
|
expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
|
|
9474
9497
|
min_value: minValue,
|
|
9475
9498
|
max_value: maxValue,
|
|
@@ -13346,6 +13369,34 @@ async function setupReadWindowValue(context, path) {
|
|
|
13346
13369
|
return { ok: true, value: toJsonValue(current) };
|
|
13347
13370
|
}, { path });
|
|
13348
13371
|
}
|
|
13372
|
+
async function setupCallWindowFunction(context, path, args) {
|
|
13373
|
+
return await context.evaluate(async ({ path, args }) => {
|
|
13374
|
+
const toJsonValue = (value) => {
|
|
13375
|
+
if (value === null || value === undefined) return null;
|
|
13376
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
13377
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
13378
|
+
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
13379
|
+
if (typeof value === "object") {
|
|
13380
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
13381
|
+
}
|
|
13382
|
+
return String(value);
|
|
13383
|
+
};
|
|
13384
|
+
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
13385
|
+
let parent = window;
|
|
13386
|
+
let current = window;
|
|
13387
|
+
for (const part of pathParts) {
|
|
13388
|
+
parent = current;
|
|
13389
|
+
current = current?.[part];
|
|
13390
|
+
}
|
|
13391
|
+
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
13392
|
+
try {
|
|
13393
|
+
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
13394
|
+
return { ok: true, returned: toJsonValue(returned) };
|
|
13395
|
+
} catch (error) {
|
|
13396
|
+
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
13397
|
+
}
|
|
13398
|
+
}, { path, args });
|
|
13399
|
+
}
|
|
13349
13400
|
function setupFrameSelector(action) {
|
|
13350
13401
|
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
13351
13402
|
}
|
|
@@ -13863,32 +13914,7 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
13863
13914
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
13864
13915
|
const scope = await setupActionScope(action, timeout);
|
|
13865
13916
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
13866
|
-
const result = await scope.context
|
|
13867
|
-
const toJsonValue = (value) => {
|
|
13868
|
-
if (value === null || value === undefined) return null;
|
|
13869
|
-
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
13870
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
13871
|
-
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
13872
|
-
if (typeof value === "object") {
|
|
13873
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
13874
|
-
}
|
|
13875
|
-
return String(value);
|
|
13876
|
-
};
|
|
13877
|
-
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
13878
|
-
let parent = window;
|
|
13879
|
-
let current = window;
|
|
13880
|
-
for (const part of pathParts) {
|
|
13881
|
-
parent = current;
|
|
13882
|
-
current = current?.[part];
|
|
13883
|
-
}
|
|
13884
|
-
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
13885
|
-
try {
|
|
13886
|
-
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
13887
|
-
return { ok: true, returned: toJsonValue(returned) };
|
|
13888
|
-
} catch (error) {
|
|
13889
|
-
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
13890
|
-
}
|
|
13891
|
-
}, { path, args });
|
|
13917
|
+
const result = await setupCallWindowFunction(scope.context, path, args);
|
|
13892
13918
|
const hasExpectation = setupHasOwn(action, "expect_return")
|
|
13893
13919
|
|| setupHasOwn(action, "expectReturn")
|
|
13894
13920
|
|| setupHasOwn(action, "expected_return")
|
|
@@ -13913,6 +13939,126 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
13913
13939
|
error: result.error || undefined,
|
|
13914
13940
|
};
|
|
13915
13941
|
}
|
|
13942
|
+
if (type === "window_call_until") {
|
|
13943
|
+
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
13944
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
13945
|
+
const args = Array.isArray(action.args) ? action.args : [];
|
|
13946
|
+
if (!path) return { ...base, path, reason: "missing_path" };
|
|
13947
|
+
if (!untilPath) return { ...base, path, reason: "missing_until_path" };
|
|
13948
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
13949
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
13950
|
+
|| setupHasOwn(action, "until_expected")
|
|
13951
|
+
|| setupHasOwn(action, "untilExpected")
|
|
13952
|
+
|| setupHasOwn(action, "until_value")
|
|
13953
|
+
|| setupHasOwn(action, "untilValue")
|
|
13954
|
+
|| setupHasOwn(action, "expected_value")
|
|
13955
|
+
|| setupHasOwn(action, "expectedValue")
|
|
13956
|
+
|| setupHasOwn(action, "expected");
|
|
13957
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
13958
|
+
? action.until_expected_value
|
|
13959
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
13960
|
+
? action.untilExpectedValue
|
|
13961
|
+
: setupHasOwn(action, "until_expected")
|
|
13962
|
+
? action.until_expected
|
|
13963
|
+
: setupHasOwn(action, "untilExpected")
|
|
13964
|
+
? action.untilExpected
|
|
13965
|
+
: setupHasOwn(action, "until_value")
|
|
13966
|
+
? action.until_value
|
|
13967
|
+
: setupHasOwn(action, "untilValue")
|
|
13968
|
+
? action.untilValue
|
|
13969
|
+
: setupHasOwn(action, "expected_value")
|
|
13970
|
+
? action.expected_value
|
|
13971
|
+
: setupHasOwn(action, "expectedValue")
|
|
13972
|
+
? action.expectedValue
|
|
13973
|
+
: action.expected;
|
|
13974
|
+
if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
13975
|
+
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)));
|
|
13976
|
+
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)));
|
|
13977
|
+
const hasReturnExpectation = setupHasOwn(action, "expect_return")
|
|
13978
|
+
|| setupHasOwn(action, "expectReturn")
|
|
13979
|
+
|| setupHasOwn(action, "expected_return")
|
|
13980
|
+
|| setupHasOwn(action, "expectedReturn");
|
|
13981
|
+
const expectedReturn = setupHasOwn(action, "expect_return")
|
|
13982
|
+
? action.expect_return
|
|
13983
|
+
: setupHasOwn(action, "expectReturn")
|
|
13984
|
+
? action.expectReturn
|
|
13985
|
+
: setupHasOwn(action, "expected_return")
|
|
13986
|
+
? action.expected_return
|
|
13987
|
+
: action.expectedReturn;
|
|
13988
|
+
const scope = await setupActionScope(action, timeout);
|
|
13989
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
13990
|
+
const startedAt = Date.now();
|
|
13991
|
+
let callCount = 0;
|
|
13992
|
+
let lastCallResult = null;
|
|
13993
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
13994
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
13995
|
+
return {
|
|
13996
|
+
...base,
|
|
13997
|
+
...setupScopeEvidence(scope),
|
|
13998
|
+
ok: true,
|
|
13999
|
+
path,
|
|
14000
|
+
arg_count: args.length,
|
|
14001
|
+
until_path: untilPath,
|
|
14002
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
14003
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
14004
|
+
call_count: callCount,
|
|
14005
|
+
max_calls: maxCalls,
|
|
14006
|
+
interval_ms: intervalMs,
|
|
14007
|
+
timeout_ms: timeout,
|
|
14008
|
+
};
|
|
14009
|
+
}
|
|
14010
|
+
while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
|
|
14011
|
+
lastCallResult = await setupCallWindowFunction(scope.context, path, args);
|
|
14012
|
+
callCount += 1;
|
|
14013
|
+
if (!lastCallResult.ok) break;
|
|
14014
|
+
if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
|
|
14015
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
14016
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
14017
|
+
return {
|
|
14018
|
+
...base,
|
|
14019
|
+
...setupScopeEvidence(scope),
|
|
14020
|
+
ok: true,
|
|
14021
|
+
path,
|
|
14022
|
+
arg_count: args.length,
|
|
14023
|
+
returned: setupJsonValue(lastCallResult.returned),
|
|
14024
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
14025
|
+
until_path: untilPath,
|
|
14026
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
14027
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
14028
|
+
call_count: callCount,
|
|
14029
|
+
max_calls: maxCalls,
|
|
14030
|
+
interval_ms: intervalMs,
|
|
14031
|
+
timeout_ms: timeout,
|
|
14032
|
+
};
|
|
14033
|
+
}
|
|
14034
|
+
if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
|
|
14035
|
+
}
|
|
14036
|
+
const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
|
|
14037
|
+
return {
|
|
14038
|
+
...base,
|
|
14039
|
+
...setupScopeEvidence(scope),
|
|
14040
|
+
path,
|
|
14041
|
+
arg_count: args.length,
|
|
14042
|
+
returned: setupJsonValue(lastCallResult?.returned),
|
|
14043
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
14044
|
+
until_path: untilPath,
|
|
14045
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
14046
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
14047
|
+
call_count: callCount,
|
|
14048
|
+
max_calls: maxCalls,
|
|
14049
|
+
interval_ms: intervalMs,
|
|
14050
|
+
timeout_ms: timeout,
|
|
14051
|
+
reason: lastCallResult && !lastCallResult.ok
|
|
14052
|
+
? lastCallResult.reason
|
|
14053
|
+
: hasReturnExpectation && !returnExpectationMet
|
|
14054
|
+
? "unexpected_return_value"
|
|
14055
|
+
: Date.now() - startedAt > timeout
|
|
14056
|
+
? "timeout"
|
|
14057
|
+
: "until_condition_not_met",
|
|
14058
|
+
error: lastCallResult?.error || undefined,
|
|
14059
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
14060
|
+
};
|
|
14061
|
+
}
|
|
13916
14062
|
if (type === "assert_window_value") {
|
|
13917
14063
|
const path = String(action.path || action.window_path || action.windowPath || "");
|
|
13918
14064
|
const hasExpected = setupHasOwn(action, "expected_value")
|
package/dist/index.js
CHANGED
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
resolveRiddleProofProfileTimeoutSec,
|
|
63
63
|
slugifyRiddleProofProfileName,
|
|
64
64
|
summarizeRiddleProofProfileResult
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-TA2KLHMX.js";
|
|
66
66
|
import {
|
|
67
67
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
68
68
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -108,7 +108,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
108
108
|
"wait",
|
|
109
109
|
"wait_for_selector",
|
|
110
110
|
"wait_for_text",
|
|
111
|
-
"window_call"
|
|
111
|
+
"window_call",
|
|
112
|
+
"window_call_until"
|
|
112
113
|
];
|
|
113
114
|
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
114
115
|
"aborted",
|
|
@@ -607,7 +608,7 @@ function isSupportedCheckType(value) {
|
|
|
607
608
|
}
|
|
608
609
|
function normalizeSetupActionType(value, index) {
|
|
609
610
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
610
|
-
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;
|
|
611
|
+
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;
|
|
611
612
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
612
613
|
return normalized;
|
|
613
614
|
}
|
|
@@ -738,10 +739,10 @@ function normalizeSetupAction(input, index) {
|
|
|
738
739
|
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
739
740
|
}
|
|
740
741
|
const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
|
|
741
|
-
if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path) {
|
|
742
|
+
if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
|
|
742
743
|
throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
|
|
743
744
|
}
|
|
744
|
-
const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
745
|
+
const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
|
|
745
746
|
const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
|
|
746
747
|
if (type === "assert_window_value" && !hasExpectedValue) {
|
|
747
748
|
throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
|
|
@@ -758,6 +759,24 @@ function normalizeSetupAction(input, index) {
|
|
|
758
759
|
}
|
|
759
760
|
}
|
|
760
761
|
const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
|
|
762
|
+
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
763
|
+
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");
|
|
764
|
+
if (type === "window_call_until") {
|
|
765
|
+
if (!untilPath) {
|
|
766
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
767
|
+
}
|
|
768
|
+
if (!hasUntilExpectedValue) {
|
|
769
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
773
|
+
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
774
|
+
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
775
|
+
}
|
|
776
|
+
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
777
|
+
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
778
|
+
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
779
|
+
}
|
|
761
780
|
const steps = numberValue(input.steps);
|
|
762
781
|
if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
|
|
763
782
|
throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
|
|
@@ -784,6 +803,10 @@ function normalizeSetupAction(input, index) {
|
|
|
784
803
|
path,
|
|
785
804
|
args,
|
|
786
805
|
expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
|
|
806
|
+
until_path: untilPath,
|
|
807
|
+
until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
|
|
808
|
+
max_calls: maxCalls,
|
|
809
|
+
interval_ms: intervalMs,
|
|
787
810
|
expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
|
|
788
811
|
min_value: minValue,
|
|
789
812
|
max_value: maxValue,
|
|
@@ -4660,6 +4683,34 @@ async function setupReadWindowValue(context, path) {
|
|
|
4660
4683
|
return { ok: true, value: toJsonValue(current) };
|
|
4661
4684
|
}, { path });
|
|
4662
4685
|
}
|
|
4686
|
+
async function setupCallWindowFunction(context, path, args) {
|
|
4687
|
+
return await context.evaluate(async ({ path, args }) => {
|
|
4688
|
+
const toJsonValue = (value) => {
|
|
4689
|
+
if (value === null || value === undefined) return null;
|
|
4690
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
4691
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
4692
|
+
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
4693
|
+
if (typeof value === "object") {
|
|
4694
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
4695
|
+
}
|
|
4696
|
+
return String(value);
|
|
4697
|
+
};
|
|
4698
|
+
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
4699
|
+
let parent = window;
|
|
4700
|
+
let current = window;
|
|
4701
|
+
for (const part of pathParts) {
|
|
4702
|
+
parent = current;
|
|
4703
|
+
current = current?.[part];
|
|
4704
|
+
}
|
|
4705
|
+
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
4706
|
+
try {
|
|
4707
|
+
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
4708
|
+
return { ok: true, returned: toJsonValue(returned) };
|
|
4709
|
+
} catch (error) {
|
|
4710
|
+
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
4711
|
+
}
|
|
4712
|
+
}, { path, args });
|
|
4713
|
+
}
|
|
4663
4714
|
function setupFrameSelector(action) {
|
|
4664
4715
|
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
4665
4716
|
}
|
|
@@ -5177,32 +5228,7 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5177
5228
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5178
5229
|
const scope = await setupActionScope(action, timeout);
|
|
5179
5230
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
5180
|
-
const result = await scope.context
|
|
5181
|
-
const toJsonValue = (value) => {
|
|
5182
|
-
if (value === null || value === undefined) return null;
|
|
5183
|
-
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
5184
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
5185
|
-
if (Array.isArray(value)) return value.map(toJsonValue);
|
|
5186
|
-
if (typeof value === "object") {
|
|
5187
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
5188
|
-
}
|
|
5189
|
-
return String(value);
|
|
5190
|
-
};
|
|
5191
|
-
const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
5192
|
-
let parent = window;
|
|
5193
|
-
let current = window;
|
|
5194
|
-
for (const part of pathParts) {
|
|
5195
|
-
parent = current;
|
|
5196
|
-
current = current?.[part];
|
|
5197
|
-
}
|
|
5198
|
-
if (typeof current !== "function") return { ok: false, reason: "missing_function" };
|
|
5199
|
-
try {
|
|
5200
|
-
const returned = await current.apply(parent, Array.isArray(args) ? args : []);
|
|
5201
|
-
return { ok: true, returned: toJsonValue(returned) };
|
|
5202
|
-
} catch (error) {
|
|
5203
|
-
return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
|
5204
|
-
}
|
|
5205
|
-
}, { path, args });
|
|
5231
|
+
const result = await setupCallWindowFunction(scope.context, path, args);
|
|
5206
5232
|
const hasExpectation = setupHasOwn(action, "expect_return")
|
|
5207
5233
|
|| setupHasOwn(action, "expectReturn")
|
|
5208
5234
|
|| setupHasOwn(action, "expected_return")
|
|
@@ -5227,6 +5253,126 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
5227
5253
|
error: result.error || undefined,
|
|
5228
5254
|
};
|
|
5229
5255
|
}
|
|
5256
|
+
if (type === "window_call_until") {
|
|
5257
|
+
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
5258
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
5259
|
+
const args = Array.isArray(action.args) ? action.args : [];
|
|
5260
|
+
if (!path) return { ...base, path, reason: "missing_path" };
|
|
5261
|
+
if (!untilPath) return { ...base, path, reason: "missing_until_path" };
|
|
5262
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
5263
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
5264
|
+
|| setupHasOwn(action, "until_expected")
|
|
5265
|
+
|| setupHasOwn(action, "untilExpected")
|
|
5266
|
+
|| setupHasOwn(action, "until_value")
|
|
5267
|
+
|| setupHasOwn(action, "untilValue")
|
|
5268
|
+
|| setupHasOwn(action, "expected_value")
|
|
5269
|
+
|| setupHasOwn(action, "expectedValue")
|
|
5270
|
+
|| setupHasOwn(action, "expected");
|
|
5271
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
5272
|
+
? action.until_expected_value
|
|
5273
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
5274
|
+
? action.untilExpectedValue
|
|
5275
|
+
: setupHasOwn(action, "until_expected")
|
|
5276
|
+
? action.until_expected
|
|
5277
|
+
: setupHasOwn(action, "untilExpected")
|
|
5278
|
+
? action.untilExpected
|
|
5279
|
+
: setupHasOwn(action, "until_value")
|
|
5280
|
+
? action.until_value
|
|
5281
|
+
: setupHasOwn(action, "untilValue")
|
|
5282
|
+
? action.untilValue
|
|
5283
|
+
: setupHasOwn(action, "expected_value")
|
|
5284
|
+
? action.expected_value
|
|
5285
|
+
: setupHasOwn(action, "expectedValue")
|
|
5286
|
+
? action.expectedValue
|
|
5287
|
+
: action.expected;
|
|
5288
|
+
if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
5289
|
+
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)));
|
|
5290
|
+
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)));
|
|
5291
|
+
const hasReturnExpectation = setupHasOwn(action, "expect_return")
|
|
5292
|
+
|| setupHasOwn(action, "expectReturn")
|
|
5293
|
+
|| setupHasOwn(action, "expected_return")
|
|
5294
|
+
|| setupHasOwn(action, "expectedReturn");
|
|
5295
|
+
const expectedReturn = setupHasOwn(action, "expect_return")
|
|
5296
|
+
? action.expect_return
|
|
5297
|
+
: setupHasOwn(action, "expectReturn")
|
|
5298
|
+
? action.expectReturn
|
|
5299
|
+
: setupHasOwn(action, "expected_return")
|
|
5300
|
+
? action.expected_return
|
|
5301
|
+
: action.expectedReturn;
|
|
5302
|
+
const scope = await setupActionScope(action, timeout);
|
|
5303
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
5304
|
+
const startedAt = Date.now();
|
|
5305
|
+
let callCount = 0;
|
|
5306
|
+
let lastCallResult = null;
|
|
5307
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5308
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5309
|
+
return {
|
|
5310
|
+
...base,
|
|
5311
|
+
...setupScopeEvidence(scope),
|
|
5312
|
+
ok: true,
|
|
5313
|
+
path,
|
|
5314
|
+
arg_count: args.length,
|
|
5315
|
+
until_path: untilPath,
|
|
5316
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5317
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5318
|
+
call_count: callCount,
|
|
5319
|
+
max_calls: maxCalls,
|
|
5320
|
+
interval_ms: intervalMs,
|
|
5321
|
+
timeout_ms: timeout,
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5324
|
+
while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
|
|
5325
|
+
lastCallResult = await setupCallWindowFunction(scope.context, path, args);
|
|
5326
|
+
callCount += 1;
|
|
5327
|
+
if (!lastCallResult.ok) break;
|
|
5328
|
+
if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
|
|
5329
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
5330
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
5331
|
+
return {
|
|
5332
|
+
...base,
|
|
5333
|
+
...setupScopeEvidence(scope),
|
|
5334
|
+
ok: true,
|
|
5335
|
+
path,
|
|
5336
|
+
arg_count: args.length,
|
|
5337
|
+
returned: setupJsonValue(lastCallResult.returned),
|
|
5338
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5339
|
+
until_path: untilPath,
|
|
5340
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
5341
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5342
|
+
call_count: callCount,
|
|
5343
|
+
max_calls: maxCalls,
|
|
5344
|
+
interval_ms: intervalMs,
|
|
5345
|
+
timeout_ms: timeout,
|
|
5346
|
+
};
|
|
5347
|
+
}
|
|
5348
|
+
if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
|
|
5349
|
+
}
|
|
5350
|
+
const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
|
|
5351
|
+
return {
|
|
5352
|
+
...base,
|
|
5353
|
+
...setupScopeEvidence(scope),
|
|
5354
|
+
path,
|
|
5355
|
+
arg_count: args.length,
|
|
5356
|
+
returned: setupJsonValue(lastCallResult?.returned),
|
|
5357
|
+
expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
|
|
5358
|
+
until_path: untilPath,
|
|
5359
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
5360
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
5361
|
+
call_count: callCount,
|
|
5362
|
+
max_calls: maxCalls,
|
|
5363
|
+
interval_ms: intervalMs,
|
|
5364
|
+
timeout_ms: timeout,
|
|
5365
|
+
reason: lastCallResult && !lastCallResult.ok
|
|
5366
|
+
? lastCallResult.reason
|
|
5367
|
+
: hasReturnExpectation && !returnExpectationMet
|
|
5368
|
+
? "unexpected_return_value"
|
|
5369
|
+
: Date.now() - startedAt > timeout
|
|
5370
|
+
? "timeout"
|
|
5371
|
+
: "until_condition_not_met",
|
|
5372
|
+
error: lastCallResult?.error || undefined,
|
|
5373
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
5374
|
+
};
|
|
5375
|
+
}
|
|
5230
5376
|
if (type === "assert_window_value") {
|
|
5231
5377
|
const path = String(action.path || action.window_path || action.windowPath || "");
|
|
5232
5378
|
const hasExpected = setupHasOwn(action, "expected_value")
|
package/dist/profile.d.cts
CHANGED
|
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
|
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
7
|
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call", "window_call_until"];
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
|
11
11
|
type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
|
|
@@ -129,6 +129,10 @@ interface RiddleProofProfileSetupAction {
|
|
|
129
129
|
path?: string;
|
|
130
130
|
args?: JsonValue[];
|
|
131
131
|
expect_return?: JsonValue;
|
|
132
|
+
until_path?: string;
|
|
133
|
+
until_expected_value?: JsonValue;
|
|
134
|
+
max_calls?: number;
|
|
135
|
+
interval_ms?: number;
|
|
132
136
|
expected_value?: JsonValue;
|
|
133
137
|
min_value?: number;
|
|
134
138
|
max_value?: number;
|
package/dist/profile.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
|
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
7
|
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call", "window_call_until"];
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
|
11
11
|
type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
|
|
@@ -129,6 +129,10 @@ interface RiddleProofProfileSetupAction {
|
|
|
129
129
|
path?: string;
|
|
130
130
|
args?: JsonValue[];
|
|
131
131
|
expect_return?: JsonValue;
|
|
132
|
+
until_path?: string;
|
|
133
|
+
until_expected_value?: JsonValue;
|
|
134
|
+
max_calls?: number;
|
|
135
|
+
interval_ms?: number;
|
|
132
136
|
expected_value?: JsonValue;
|
|
133
137
|
min_value?: number;
|
|
134
138
|
max_value?: number;
|
package/dist/profile.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
resolveRiddleProofProfileTimeoutSec,
|
|
24
24
|
slugifyRiddleProofProfileName,
|
|
25
25
|
summarizeRiddleProofProfileResult
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-TA2KLHMX.js";
|
|
27
27
|
export {
|
|
28
28
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
29
29
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|