@riddledc/riddle-proof 0.7.196 → 0.7.198
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 +12 -2
- package/dist/{chunk-WUOU5RB4.js → chunk-DL6UB4N6.js} +281 -93
- package/dist/cli.cjs +348 -96
- package/dist/cli.js +68 -4
- package/dist/index.cjs +281 -93
- package/dist/index.js +1 -1
- package/dist/profile.cjs +281 -93
- package/dist/profile.d.cts +1 -1
- package/dist/profile.d.ts +1 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -406,7 +406,7 @@ when body matching overrides sequence order.
|
|
|
406
406
|
`target.setup_actions` is optional. Use it when the meaningful proof surface
|
|
407
407
|
appears only after a picker, tab, login stub, storage seed, form fill,
|
|
408
408
|
transport control, or other bounded interaction. Supported setup actions are
|
|
409
|
-
`click`, `tap`, `drag`, `press`, `key_down`, `key_up`, `fill`, `set_input_value`, `set_range_value`,
|
|
409
|
+
`click`, `tap`, `tap_until`, `drag`, `press`, `key_down`, `key_up`, `fill`, `set_input_value`, `set_range_value`,
|
|
410
410
|
`deterministic_runtime`, `canvas_signature`, `assert_text_visible`, `assert_text_absent`,
|
|
411
411
|
`assert_selector_count`, `assert_window_value`, `assert_window_number`,
|
|
412
412
|
`local_storage`, `session_storage`, `clear_storage`, `clear_console`,
|
|
@@ -436,6 +436,14 @@ It requires `selector`, defaults to a touch tap at the target center, and
|
|
|
436
436
|
accepts `x` / `y` or `from_x` / `from_y` plus `coordinate_mode: "ratio"` for
|
|
437
437
|
element-relative coordinates. Set `pointer_type` to `mouse`, `touch`, or `pen`
|
|
438
438
|
when the proof must distinguish input modality.
|
|
439
|
+
Use `tap_until` for gameplay loops where the proof should tap a visible target
|
|
440
|
+
until a browser-state predicate is satisfied. It accepts the same selector,
|
|
441
|
+
coordinate, and pointer options as `tap`, plus `until_path`,
|
|
442
|
+
`until_expected_value`, `max_taps` / `max_calls` from 1 to 100, and optional
|
|
443
|
+
`interval_ms`. The action stops early when the predicate matches and records one
|
|
444
|
+
compact receipt with `tap_count`, final `until_value`, and input dispatch
|
|
445
|
+
details, so long canvas interaction loops do not need dozens of repeated setup
|
|
446
|
+
actions.
|
|
439
447
|
Use `set_range_value` for HTML range inputs and React-controlled sliders. It
|
|
440
448
|
accepts aliases such as `set-slider-value`, requires `selector` plus `value`,
|
|
441
449
|
uses the native input value setter, dispatches bubbling `input` and `change`
|
|
@@ -531,7 +539,9 @@ actions stay visible. Click actions with `click_count` greater than `1` are
|
|
|
531
539
|
included in clicked-target evidence and rolled up as `click_count_action_total`
|
|
532
540
|
and `click_count_value_total`. Repeated selector runs such as long gameplay
|
|
533
541
|
button loops are also grouped as compact `same-selector` click-sequence
|
|
534
|
-
receipts with click totals and ordinals.
|
|
542
|
+
receipts with click totals and ordinals. `tap_until` actions are summarized as
|
|
543
|
+
one compact receipt with total taps and the final predicate value, which is the
|
|
544
|
+
preferred shape for long canvas gameplay loops. Setup receipt sampling favors both
|
|
535
545
|
first and last per-viewport receipts before filling remaining space, so late
|
|
536
546
|
lifecycle phases such as terminal or restart remain visible in compact
|
|
537
547
|
summaries.
|
|
@@ -45,6 +45,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
45
45
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
46
46
|
"click",
|
|
47
47
|
"tap",
|
|
48
|
+
"tap_until",
|
|
48
49
|
"drag",
|
|
49
50
|
"press",
|
|
50
51
|
"key_down",
|
|
@@ -615,6 +616,28 @@ function profileSetupTapReceipts(results) {
|
|
|
615
616
|
reason: result.reason ?? result.error ?? null
|
|
616
617
|
}));
|
|
617
618
|
}
|
|
619
|
+
function profileSetupTapUntilReceipts(results) {
|
|
620
|
+
return results.filter((result) => profileSetupResultAction(result) === "tap_until").map((result) => ({
|
|
621
|
+
ordinal: result.ordinal ?? null,
|
|
622
|
+
ok: result.ok !== false,
|
|
623
|
+
selector: result.selector ?? null,
|
|
624
|
+
frame_selector: result.frame_selector ?? null,
|
|
625
|
+
pointer_type: result.pointer_type ?? null,
|
|
626
|
+
input_dispatch: result.input_dispatch ?? null,
|
|
627
|
+
coordinate_mode: result.coordinate_mode ?? null,
|
|
628
|
+
x: result.x ?? null,
|
|
629
|
+
y: result.y ?? null,
|
|
630
|
+
duration_ms: result.duration_ms ?? null,
|
|
631
|
+
until_path: result.until_path ?? null,
|
|
632
|
+
until_value: result.until_value ?? null,
|
|
633
|
+
until_expected_value: result.until_expected_value ?? null,
|
|
634
|
+
tap_count: result.tap_count ?? null,
|
|
635
|
+
max_taps: result.max_taps ?? result.max_calls ?? null,
|
|
636
|
+
interval_ms: result.interval_ms ?? null,
|
|
637
|
+
timeout_ms: result.timeout_ms ?? null,
|
|
638
|
+
reason: result.reason ?? result.error ?? null
|
|
639
|
+
}));
|
|
640
|
+
}
|
|
618
641
|
function profileSetupKeyboardReceipts(results) {
|
|
619
642
|
return results.filter((result) => ["press", "key_down", "key_up"].includes(profileSetupResultAction(result))).map((result) => ({
|
|
620
643
|
action: profileSetupResultAction(result),
|
|
@@ -790,6 +813,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
790
813
|
const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
|
|
791
814
|
const tapReceipts = profileSetupTapReceipts(results);
|
|
792
815
|
const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
|
|
816
|
+
const tapUntilReceipts = profileSetupTapUntilReceipts(results);
|
|
817
|
+
const tapUntilTapCounts = tapUntilReceipts.map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : void 0).filter((value) => value !== void 0);
|
|
818
|
+
const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
|
|
793
819
|
const keyboardReceipts = profileSetupKeyboardReceipts(results);
|
|
794
820
|
const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
|
|
795
821
|
const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
|
|
@@ -801,6 +827,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
801
827
|
selector: result.selector ?? null,
|
|
802
828
|
frame_selector: result.frame_selector ?? null,
|
|
803
829
|
text: compactProfileSetupSummaryText(result.text),
|
|
830
|
+
...result.fallback_to_tap === true ? { fallback_to_tap: true } : {},
|
|
831
|
+
...result.input_dispatch ? { input_dispatch: result.input_dispatch } : {},
|
|
832
|
+
...result.click_error ? { click_error: compactProfileSetupSummaryText(result.click_error) } : {},
|
|
804
833
|
...clickCount ? { click_count: clickCount } : {}
|
|
805
834
|
};
|
|
806
835
|
});
|
|
@@ -859,6 +888,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
859
888
|
tap_total: tapReceipts.length,
|
|
860
889
|
tap_truncated: tapReceipts.length > sampledTapReceipts.length,
|
|
861
890
|
tap: sampledTapReceipts,
|
|
891
|
+
tap_until_total: tapUntilReceipts.length,
|
|
892
|
+
tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
|
|
893
|
+
tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
|
|
894
|
+
tap_until: sampledTapUntilReceipts,
|
|
862
895
|
keyboard_total: keyboardReceipts.length,
|
|
863
896
|
keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
|
|
864
897
|
keyboard: sampledKeyboardReceipts,
|
|
@@ -920,7 +953,7 @@ function isSupportedCheckType(value) {
|
|
|
920
953
|
}
|
|
921
954
|
function normalizeSetupActionType(value, index) {
|
|
922
955
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
923
|
-
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 === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : 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 === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
|
|
956
|
+
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 === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "tap_until" || normalizedInput === "pointer_tap_until" || normalizedInput === "touch_tap_until" || normalizedInput === "canvas_tap_until" || normalizedInput === "tap_repeat_until" || normalizedInput === "repeat_tap_until" ? "tap_until" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : 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 === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
|
|
924
957
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
925
958
|
return normalized;
|
|
926
959
|
}
|
|
@@ -1002,8 +1035,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
|
|
|
1002
1035
|
}
|
|
1003
1036
|
function normalizeSetupActionPointerType(value, type, index) {
|
|
1004
1037
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
1005
|
-
if (type !== "drag" && type !== "tap") {
|
|
1006
|
-
throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
|
|
1038
|
+
if (type !== "drag" && type !== "tap" && type !== "tap_until") {
|
|
1039
|
+
throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap/tap_until actions.`);
|
|
1007
1040
|
}
|
|
1008
1041
|
const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
|
|
1009
1042
|
if (normalized === "mouse") return "mouse";
|
|
@@ -1082,11 +1115,11 @@ function normalizeSetupAction(input, index) {
|
|
|
1082
1115
|
if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
|
|
1083
1116
|
throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
|
|
1084
1117
|
}
|
|
1085
|
-
if ((type === "click" || type === "tap" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
|
|
1118
|
+
if ((type === "click" || type === "tap" || type === "tap_until" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
|
|
1086
1119
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
1087
1120
|
}
|
|
1088
|
-
const fromX = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
|
|
1089
|
-
const fromY = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
|
|
1121
|
+
const fromX = type === "click" || type === "tap" || type === "tap_until" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
|
|
1122
|
+
const fromY = type === "click" || type === "tap" || type === "tap_until" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
|
|
1090
1123
|
const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
|
|
1091
1124
|
const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
|
|
1092
1125
|
const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
|
|
@@ -1111,18 +1144,18 @@ function normalizeSetupAction(input, index) {
|
|
|
1111
1144
|
}
|
|
1112
1145
|
}
|
|
1113
1146
|
}
|
|
1114
|
-
if (type === "tap") {
|
|
1147
|
+
if (type === "tap" || type === "tap_until") {
|
|
1115
1148
|
const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
|
|
1116
1149
|
if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
|
|
1117
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1150
|
+
throw new Error(`target.setup_actions[${index}] ${type} coordinates require both x and y.`);
|
|
1118
1151
|
}
|
|
1119
1152
|
if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
|
|
1120
1153
|
const tapCoordinates = [fromX, fromY];
|
|
1121
1154
|
if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
|
|
1122
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1155
|
+
throw new Error(`target.setup_actions[${index}] ${type} ratio coordinates must be between 0 and 1.`);
|
|
1123
1156
|
}
|
|
1124
1157
|
if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
|
|
1125
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1158
|
+
throw new Error(`target.setup_actions[${index}] ${type} pixel coordinates must be non-negative.`);
|
|
1126
1159
|
}
|
|
1127
1160
|
}
|
|
1128
1161
|
}
|
|
@@ -1228,7 +1261,7 @@ function normalizeSetupAction(input, index) {
|
|
|
1228
1261
|
const captureReturn = input.capture_return === false || input.captureReturn === false || input.include_return === false || input.includeReturn === false || input.omit_return === true || input.omitReturn === true ? false : void 0;
|
|
1229
1262
|
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
1230
1263
|
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");
|
|
1231
|
-
if (type === "window_call_until") {
|
|
1264
|
+
if (type === "window_call_until" || type === "tap_until") {
|
|
1232
1265
|
if (!untilPath) {
|
|
1233
1266
|
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
1234
1267
|
}
|
|
@@ -1236,12 +1269,12 @@ function normalizeSetupAction(input, index) {
|
|
|
1236
1269
|
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
1237
1270
|
}
|
|
1238
1271
|
}
|
|
1239
|
-
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
1240
|
-
if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
1272
|
+
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts", "max_taps", "maxTaps", "tap_limit", "tapLimit"));
|
|
1273
|
+
if ((type === "window_call_until" || type === "tap_until") && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
|
|
1241
1274
|
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
1242
1275
|
}
|
|
1243
1276
|
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
1244
|
-
if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
1277
|
+
if ((type === "window_call_until" || type === "tap_until") && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
|
|
1245
1278
|
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
1246
1279
|
}
|
|
1247
1280
|
const steps = numberValue(input.steps);
|
|
@@ -4507,6 +4540,30 @@ function profileSetupTapReceipts(results) {
|
|
|
4507
4540
|
reason: result.reason || result.error || null,
|
|
4508
4541
|
}));
|
|
4509
4542
|
}
|
|
4543
|
+
function profileSetupTapUntilReceipts(results) {
|
|
4544
|
+
return (results || [])
|
|
4545
|
+
.filter((result) => result && profileSetupResultAction(result) === "tap_until")
|
|
4546
|
+
.map((result) => ({
|
|
4547
|
+
ordinal: result.ordinal ?? null,
|
|
4548
|
+
ok: result.ok !== false,
|
|
4549
|
+
selector: result.selector ?? null,
|
|
4550
|
+
frame_selector: result.frame_selector ?? null,
|
|
4551
|
+
pointer_type: result.pointer_type ?? null,
|
|
4552
|
+
input_dispatch: result.input_dispatch ?? null,
|
|
4553
|
+
coordinate_mode: result.coordinate_mode ?? null,
|
|
4554
|
+
x: result.x ?? null,
|
|
4555
|
+
y: result.y ?? null,
|
|
4556
|
+
duration_ms: result.duration_ms ?? null,
|
|
4557
|
+
until_path: result.until_path ?? null,
|
|
4558
|
+
until_value: result.until_value ?? null,
|
|
4559
|
+
until_expected_value: result.until_expected_value ?? null,
|
|
4560
|
+
tap_count: result.tap_count ?? null,
|
|
4561
|
+
max_taps: result.max_taps ?? result.max_calls ?? null,
|
|
4562
|
+
interval_ms: result.interval_ms ?? null,
|
|
4563
|
+
timeout_ms: result.timeout_ms ?? null,
|
|
4564
|
+
reason: result.reason || result.error || null,
|
|
4565
|
+
}));
|
|
4566
|
+
}
|
|
4510
4567
|
function profileSetupKeyboardReceipts(results) {
|
|
4511
4568
|
return (results || [])
|
|
4512
4569
|
.filter((result) => result && ["press", "key_down", "key_up"].includes(profileSetupResultAction(result)))
|
|
@@ -4709,6 +4766,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
|
|
|
4709
4766
|
const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
|
|
4710
4767
|
const tapReceipts = profileSetupTapReceipts(results);
|
|
4711
4768
|
const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
|
|
4769
|
+
const tapUntilReceipts = profileSetupTapUntilReceipts(results);
|
|
4770
|
+
const tapUntilTapCounts = tapUntilReceipts
|
|
4771
|
+
.map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : undefined)
|
|
4772
|
+
.filter((value) => value !== undefined);
|
|
4773
|
+
const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
|
|
4712
4774
|
const keyboardReceipts = profileSetupKeyboardReceipts(results);
|
|
4713
4775
|
const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
|
|
4714
4776
|
const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
|
|
@@ -4722,6 +4784,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
|
|
|
4722
4784
|
selector: result.selector ?? null,
|
|
4723
4785
|
frame_selector: result.frame_selector ?? null,
|
|
4724
4786
|
text: compactProfileSetupSummaryText(result.text),
|
|
4787
|
+
...(result.fallback_to_tap === true ? { fallback_to_tap: true } : {}),
|
|
4788
|
+
...(result.input_dispatch ? { input_dispatch: result.input_dispatch } : {}),
|
|
4789
|
+
...(result.click_error ? { click_error: compactProfileSetupSummaryText(result.click_error) } : {}),
|
|
4725
4790
|
...(clickCount ? { click_count: clickCount } : {}),
|
|
4726
4791
|
};
|
|
4727
4792
|
});
|
|
@@ -4788,6 +4853,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
|
|
|
4788
4853
|
tap_total: tapReceipts.length,
|
|
4789
4854
|
tap_truncated: tapReceipts.length > sampledTapReceipts.length,
|
|
4790
4855
|
tap: sampledTapReceipts,
|
|
4856
|
+
tap_until_total: tapUntilReceipts.length,
|
|
4857
|
+
tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
|
|
4858
|
+
tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
|
|
4859
|
+
tap_until: sampledTapUntilReceipts,
|
|
4791
4860
|
keyboard_total: keyboardReceipts.length,
|
|
4792
4861
|
keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
|
|
4793
4862
|
keyboard: sampledKeyboardReceipts,
|
|
@@ -5734,6 +5803,108 @@ async function waitForAnyVisibleSelector(context, selector, timeout) {
|
|
|
5734
5803
|
}
|
|
5735
5804
|
throw new Error("No visible match for selector " + selector + ": " + lastReason);
|
|
5736
5805
|
}
|
|
5806
|
+
async function dispatchSetupTapPoint(point, pointerType, durationMs) {
|
|
5807
|
+
if (pointerType === "touch" || pointerType === "pen") {
|
|
5808
|
+
const client = await page.context().newCDPSession(page);
|
|
5809
|
+
try {
|
|
5810
|
+
if (pointerType === "touch") {
|
|
5811
|
+
const touchPoint = {
|
|
5812
|
+
x: point.x,
|
|
5813
|
+
y: point.y,
|
|
5814
|
+
radiusX: 1,
|
|
5815
|
+
radiusY: 1,
|
|
5816
|
+
force: 1,
|
|
5817
|
+
id: 11,
|
|
5818
|
+
};
|
|
5819
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
5820
|
+
type: "touchStart",
|
|
5821
|
+
touchPoints: [touchPoint],
|
|
5822
|
+
});
|
|
5823
|
+
if (durationMs) await page.waitForTimeout(durationMs);
|
|
5824
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
5825
|
+
type: "touchEnd",
|
|
5826
|
+
touchPoints: [],
|
|
5827
|
+
});
|
|
5828
|
+
} else {
|
|
5829
|
+
await client.send("Input.dispatchMouseEvent", {
|
|
5830
|
+
type: "mousePressed",
|
|
5831
|
+
x: point.x,
|
|
5832
|
+
y: point.y,
|
|
5833
|
+
button: "left",
|
|
5834
|
+
buttons: 1,
|
|
5835
|
+
clickCount: 1,
|
|
5836
|
+
pointerType: "pen",
|
|
5837
|
+
});
|
|
5838
|
+
if (durationMs) await page.waitForTimeout(durationMs);
|
|
5839
|
+
await client.send("Input.dispatchMouseEvent", {
|
|
5840
|
+
type: "mouseReleased",
|
|
5841
|
+
x: point.x,
|
|
5842
|
+
y: point.y,
|
|
5843
|
+
button: "left",
|
|
5844
|
+
buttons: 0,
|
|
5845
|
+
clickCount: 1,
|
|
5846
|
+
pointerType: "pen",
|
|
5847
|
+
});
|
|
5848
|
+
}
|
|
5849
|
+
} finally {
|
|
5850
|
+
await client.detach().catch(() => {});
|
|
5851
|
+
}
|
|
5852
|
+
} else {
|
|
5853
|
+
await page.mouse.click(point.x, point.y);
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
async function resolveSetupTapTarget(action, base, scope, timeout) {
|
|
5857
|
+
const locator = scope.context.locator(action.selector);
|
|
5858
|
+
const count = await locator.count();
|
|
5859
|
+
if (!count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count } };
|
|
5860
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
5861
|
+
if (targetIndex < 0 || targetIndex >= count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex } };
|
|
5862
|
+
const target = locator.nth(targetIndex);
|
|
5863
|
+
await target.waitFor({ state: "visible", timeout });
|
|
5864
|
+
const box = await target.boundingBox();
|
|
5865
|
+
if (!box) return { result: { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex } };
|
|
5866
|
+
const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
|
|
5867
|
+
const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
|
|
5868
|
+
const hasTapPosition = fromX !== undefined || fromY !== undefined;
|
|
5869
|
+
if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex } };
|
|
5870
|
+
const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
|
|
5871
|
+
if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex } };
|
|
5872
|
+
if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex } };
|
|
5873
|
+
const coordinate = (value, size) => mode === "ratio" ? value * size : value;
|
|
5874
|
+
const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
|
|
5875
|
+
const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
|
|
5876
|
+
const point = {
|
|
5877
|
+
x: box.x + coordinate(localX, box.width),
|
|
5878
|
+
y: box.y + coordinate(localY, box.height),
|
|
5879
|
+
};
|
|
5880
|
+
const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
|
|
5881
|
+
const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
|
|
5882
|
+
return {
|
|
5883
|
+
target: {
|
|
5884
|
+
count,
|
|
5885
|
+
targetIndex,
|
|
5886
|
+
point,
|
|
5887
|
+
mode,
|
|
5888
|
+
fromX,
|
|
5889
|
+
fromY,
|
|
5890
|
+
hasTapPosition,
|
|
5891
|
+
pointerType,
|
|
5892
|
+
durationMs,
|
|
5893
|
+
},
|
|
5894
|
+
};
|
|
5895
|
+
}
|
|
5896
|
+
function setupTapTargetEvidence(tapTarget) {
|
|
5897
|
+
return {
|
|
5898
|
+
count: tapTarget.count,
|
|
5899
|
+
target_index: tapTarget.targetIndex,
|
|
5900
|
+
coordinate_mode: tapTarget.hasTapPosition ? tapTarget.mode : undefined,
|
|
5901
|
+
x: tapTarget.hasTapPosition ? tapTarget.fromX : undefined,
|
|
5902
|
+
y: tapTarget.hasTapPosition ? tapTarget.fromY : undefined,
|
|
5903
|
+
pointer_type: tapTarget.pointerType,
|
|
5904
|
+
input_dispatch: tapTarget.pointerType === "touch" || tapTarget.pointerType === "pen" ? "cdp" : "playwright_mouse",
|
|
5905
|
+
duration_ms: tapTarget.durationMs || undefined,
|
|
5906
|
+
};
|
|
5907
|
+
}
|
|
5737
5908
|
function setupHasOwn(action, key) {
|
|
5738
5909
|
return Boolean(action) && Object.keys(action).includes(key);
|
|
5739
5910
|
}
|
|
@@ -6336,91 +6507,108 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
6336
6507
|
if (type === "tap") {
|
|
6337
6508
|
const scope = await setupActionScope(action, timeout);
|
|
6338
6509
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
6339
|
-
const
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
|
|
6348
|
-
const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
|
|
6349
|
-
const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
|
|
6350
|
-
const hasTapPosition = fromX !== undefined || fromY !== undefined;
|
|
6351
|
-
if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
|
|
6352
|
-
const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
|
|
6353
|
-
if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
|
|
6354
|
-
if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
|
|
6355
|
-
const coordinate = (value, size) => mode === "ratio" ? value * size : value;
|
|
6356
|
-
const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
|
|
6357
|
-
const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
|
|
6358
|
-
const point = {
|
|
6359
|
-
x: box.x + coordinate(localX, box.width),
|
|
6360
|
-
y: box.y + coordinate(localY, box.height),
|
|
6510
|
+
const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
|
|
6511
|
+
if (prepared.result) return prepared.result;
|
|
6512
|
+
await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
|
|
6513
|
+
return {
|
|
6514
|
+
...base,
|
|
6515
|
+
...setupScopeEvidence(scope),
|
|
6516
|
+
ok: true,
|
|
6517
|
+
...setupTapTargetEvidence(prepared.target),
|
|
6361
6518
|
};
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6519
|
+
}
|
|
6520
|
+
if (type === "tap_until") {
|
|
6521
|
+
const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
|
|
6522
|
+
const hasUntilExpected = setupHasOwn(action, "until_expected_value")
|
|
6523
|
+
|| setupHasOwn(action, "untilExpectedValue")
|
|
6524
|
+
|| setupHasOwn(action, "until_expected")
|
|
6525
|
+
|| setupHasOwn(action, "untilExpected")
|
|
6526
|
+
|| setupHasOwn(action, "until_value")
|
|
6527
|
+
|| setupHasOwn(action, "untilValue")
|
|
6528
|
+
|| setupHasOwn(action, "expected_value")
|
|
6529
|
+
|| setupHasOwn(action, "expectedValue")
|
|
6530
|
+
|| setupHasOwn(action, "expected");
|
|
6531
|
+
const untilExpected = setupHasOwn(action, "until_expected_value")
|
|
6532
|
+
? action.until_expected_value
|
|
6533
|
+
: setupHasOwn(action, "untilExpectedValue")
|
|
6534
|
+
? action.untilExpectedValue
|
|
6535
|
+
: setupHasOwn(action, "until_expected")
|
|
6536
|
+
? action.until_expected
|
|
6537
|
+
: setupHasOwn(action, "untilExpected")
|
|
6538
|
+
? action.untilExpected
|
|
6539
|
+
: setupHasOwn(action, "until_value")
|
|
6540
|
+
? action.until_value
|
|
6541
|
+
: setupHasOwn(action, "untilValue")
|
|
6542
|
+
? action.untilValue
|
|
6543
|
+
: setupHasOwn(action, "expected_value")
|
|
6544
|
+
? action.expected_value
|
|
6545
|
+
: setupHasOwn(action, "expectedValue")
|
|
6546
|
+
? action.expectedValue
|
|
6547
|
+
: action.expected;
|
|
6548
|
+
if (!untilPath) return { ...base, reason: "missing_until_path" };
|
|
6549
|
+
if (!hasUntilExpected) return { ...base, until_path: untilPath, reason: "missing_until_expected_value" };
|
|
6550
|
+
const maxTaps = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_taps ?? action.maxTaps ?? action.tap_limit ?? action.tapLimit ?? action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
|
|
6551
|
+
const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.tap_interval_ms ?? action.tapIntervalMs, 100) || 0)));
|
|
6552
|
+
const scope = await setupActionScope(action, timeout);
|
|
6553
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
6554
|
+
const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
|
|
6555
|
+
if (prepared.result) return prepared.result;
|
|
6556
|
+
const startedAt = Date.now();
|
|
6557
|
+
let tapCount = 0;
|
|
6558
|
+
let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
6559
|
+
const targetEvidence = setupTapTargetEvidence(prepared.target);
|
|
6560
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
6561
|
+
return {
|
|
6562
|
+
...base,
|
|
6563
|
+
...setupScopeEvidence(scope),
|
|
6564
|
+
ok: true,
|
|
6565
|
+
...targetEvidence,
|
|
6566
|
+
until_path: untilPath,
|
|
6567
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
6568
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
6569
|
+
tap_count: tapCount,
|
|
6570
|
+
max_taps: maxTaps,
|
|
6571
|
+
max_calls: maxTaps,
|
|
6572
|
+
interval_ms: intervalMs,
|
|
6573
|
+
timeout_ms: timeout,
|
|
6574
|
+
};
|
|
6575
|
+
}
|
|
6576
|
+
while (tapCount < maxTaps && Date.now() - startedAt <= timeout) {
|
|
6577
|
+
await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
|
|
6578
|
+
tapCount += 1;
|
|
6579
|
+
lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
|
|
6580
|
+
if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
|
|
6581
|
+
return {
|
|
6582
|
+
...base,
|
|
6583
|
+
...setupScopeEvidence(scope),
|
|
6584
|
+
ok: true,
|
|
6585
|
+
...targetEvidence,
|
|
6586
|
+
until_path: untilPath,
|
|
6587
|
+
until_value: setupJsonValue(lastPredicateResult.value),
|
|
6588
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
6589
|
+
tap_count: tapCount,
|
|
6590
|
+
max_taps: maxTaps,
|
|
6591
|
+
max_calls: maxTaps,
|
|
6592
|
+
interval_ms: intervalMs,
|
|
6593
|
+
timeout_ms: timeout,
|
|
6594
|
+
};
|
|
6408
6595
|
}
|
|
6409
|
-
|
|
6410
|
-
await page.mouse.click(point.x, point.y);
|
|
6596
|
+
if (tapCount < maxTaps && intervalMs) await page.waitForTimeout(intervalMs);
|
|
6411
6597
|
}
|
|
6412
6598
|
return {
|
|
6413
6599
|
...base,
|
|
6414
6600
|
...setupScopeEvidence(scope),
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6601
|
+
...targetEvidence,
|
|
6602
|
+
until_path: untilPath,
|
|
6603
|
+
until_value: setupJsonValue(lastPredicateResult?.value),
|
|
6604
|
+
until_expected_value: setupJsonValue(untilExpected),
|
|
6605
|
+
tap_count: tapCount,
|
|
6606
|
+
max_taps: maxTaps,
|
|
6607
|
+
max_calls: maxTaps,
|
|
6608
|
+
interval_ms: intervalMs,
|
|
6609
|
+
timeout_ms: timeout,
|
|
6610
|
+
reason: Date.now() - startedAt > timeout ? "timeout" : "until_condition_not_met",
|
|
6611
|
+
missing_part: lastPredicateResult?.missing_part || undefined,
|
|
6424
6612
|
};
|
|
6425
6613
|
}
|
|
6426
6614
|
if (type === "drag") {
|