@riddledc/riddle-proof 0.7.197 → 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-EYLIXKE2.js → chunk-DL6UB4N6.js} +275 -93
- package/dist/cli.cjs +321 -96
- package/dist/cli.js +47 -4
- package/dist/index.cjs +275 -93
- package/dist/index.js +1 -1
- package/dist/profile.cjs +275 -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);
|
|
@@ -862,6 +888,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
862
888
|
tap_total: tapReceipts.length,
|
|
863
889
|
tap_truncated: tapReceipts.length > sampledTapReceipts.length,
|
|
864
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,
|
|
865
895
|
keyboard_total: keyboardReceipts.length,
|
|
866
896
|
keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
|
|
867
897
|
keyboard: sampledKeyboardReceipts,
|
|
@@ -923,7 +953,7 @@ function isSupportedCheckType(value) {
|
|
|
923
953
|
}
|
|
924
954
|
function normalizeSetupActionType(value, index) {
|
|
925
955
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
926
|
-
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;
|
|
927
957
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
928
958
|
return normalized;
|
|
929
959
|
}
|
|
@@ -1005,8 +1035,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
|
|
|
1005
1035
|
}
|
|
1006
1036
|
function normalizeSetupActionPointerType(value, type, index) {
|
|
1007
1037
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
1008
|
-
if (type !== "drag" && type !== "tap") {
|
|
1009
|
-
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.`);
|
|
1010
1040
|
}
|
|
1011
1041
|
const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
|
|
1012
1042
|
if (normalized === "mouse") return "mouse";
|
|
@@ -1085,11 +1115,11 @@ function normalizeSetupAction(input, index) {
|
|
|
1085
1115
|
if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
|
|
1086
1116
|
throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
|
|
1087
1117
|
}
|
|
1088
|
-
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) {
|
|
1089
1119
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
1090
1120
|
}
|
|
1091
|
-
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"));
|
|
1092
|
-
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"));
|
|
1093
1123
|
const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
|
|
1094
1124
|
const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
|
|
1095
1125
|
const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
|
|
@@ -1114,18 +1144,18 @@ function normalizeSetupAction(input, index) {
|
|
|
1114
1144
|
}
|
|
1115
1145
|
}
|
|
1116
1146
|
}
|
|
1117
|
-
if (type === "tap") {
|
|
1147
|
+
if (type === "tap" || type === "tap_until") {
|
|
1118
1148
|
const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
|
|
1119
1149
|
if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
|
|
1120
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1150
|
+
throw new Error(`target.setup_actions[${index}] ${type} coordinates require both x and y.`);
|
|
1121
1151
|
}
|
|
1122
1152
|
if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
|
|
1123
1153
|
const tapCoordinates = [fromX, fromY];
|
|
1124
1154
|
if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
|
|
1125
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1155
|
+
throw new Error(`target.setup_actions[${index}] ${type} ratio coordinates must be between 0 and 1.`);
|
|
1126
1156
|
}
|
|
1127
1157
|
if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
|
|
1128
|
-
throw new Error(`target.setup_actions[${index}]
|
|
1158
|
+
throw new Error(`target.setup_actions[${index}] ${type} pixel coordinates must be non-negative.`);
|
|
1129
1159
|
}
|
|
1130
1160
|
}
|
|
1131
1161
|
}
|
|
@@ -1231,7 +1261,7 @@ function normalizeSetupAction(input, index) {
|
|
|
1231
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;
|
|
1232
1262
|
const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
|
|
1233
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");
|
|
1234
|
-
if (type === "window_call_until") {
|
|
1264
|
+
if (type === "window_call_until" || type === "tap_until") {
|
|
1235
1265
|
if (!untilPath) {
|
|
1236
1266
|
throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
|
|
1237
1267
|
}
|
|
@@ -1239,12 +1269,12 @@ function normalizeSetupAction(input, index) {
|
|
|
1239
1269
|
throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
|
|
1240
1270
|
}
|
|
1241
1271
|
}
|
|
1242
|
-
const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
|
|
1243
|
-
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)) {
|
|
1244
1274
|
throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
|
|
1245
1275
|
}
|
|
1246
1276
|
const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
|
|
1247
|
-
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)) {
|
|
1248
1278
|
throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
|
|
1249
1279
|
}
|
|
1250
1280
|
const steps = numberValue(input.steps);
|
|
@@ -4510,6 +4540,30 @@ function profileSetupTapReceipts(results) {
|
|
|
4510
4540
|
reason: result.reason || result.error || null,
|
|
4511
4541
|
}));
|
|
4512
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
|
+
}
|
|
4513
4567
|
function profileSetupKeyboardReceipts(results) {
|
|
4514
4568
|
return (results || [])
|
|
4515
4569
|
.filter((result) => result && ["press", "key_down", "key_up"].includes(profileSetupResultAction(result)))
|
|
@@ -4712,6 +4766,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
|
|
|
4712
4766
|
const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
|
|
4713
4767
|
const tapReceipts = profileSetupTapReceipts(results);
|
|
4714
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);
|
|
4715
4774
|
const keyboardReceipts = profileSetupKeyboardReceipts(results);
|
|
4716
4775
|
const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
|
|
4717
4776
|
const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
|
|
@@ -4794,6 +4853,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
|
|
|
4794
4853
|
tap_total: tapReceipts.length,
|
|
4795
4854
|
tap_truncated: tapReceipts.length > sampledTapReceipts.length,
|
|
4796
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,
|
|
4797
4860
|
keyboard_total: keyboardReceipts.length,
|
|
4798
4861
|
keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
|
|
4799
4862
|
keyboard: sampledKeyboardReceipts,
|
|
@@ -5740,6 +5803,108 @@ async function waitForAnyVisibleSelector(context, selector, timeout) {
|
|
|
5740
5803
|
}
|
|
5741
5804
|
throw new Error("No visible match for selector " + selector + ": " + lastReason);
|
|
5742
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
|
+
}
|
|
5743
5908
|
function setupHasOwn(action, key) {
|
|
5744
5909
|
return Boolean(action) && Object.keys(action).includes(key);
|
|
5745
5910
|
}
|
|
@@ -6342,91 +6507,108 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
6342
6507
|
if (type === "tap") {
|
|
6343
6508
|
const scope = await setupActionScope(action, timeout);
|
|
6344
6509
|
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
6345
|
-
const
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
|
|
6354
|
-
const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
|
|
6355
|
-
const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
|
|
6356
|
-
const hasTapPosition = fromX !== undefined || fromY !== undefined;
|
|
6357
|
-
if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
|
|
6358
|
-
const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
|
|
6359
|
-
if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
|
|
6360
|
-
if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
|
|
6361
|
-
const coordinate = (value, size) => mode === "ratio" ? value * size : value;
|
|
6362
|
-
const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
|
|
6363
|
-
const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
|
|
6364
|
-
const point = {
|
|
6365
|
-
x: box.x + coordinate(localX, box.width),
|
|
6366
|
-
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),
|
|
6367
6518
|
};
|
|
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
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
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
|
+
};
|
|
6414
6595
|
}
|
|
6415
|
-
|
|
6416
|
-
await page.mouse.click(point.x, point.y);
|
|
6596
|
+
if (tapCount < maxTaps && intervalMs) await page.waitForTimeout(intervalMs);
|
|
6417
6597
|
}
|
|
6418
6598
|
return {
|
|
6419
6599
|
...base,
|
|
6420
6600
|
...setupScopeEvidence(scope),
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
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,
|
|
6430
6612
|
};
|
|
6431
6613
|
}
|
|
6432
6614
|
if (type === "drag") {
|