@riddledc/riddle-proof 0.7.77 → 0.7.79

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.
@@ -47,6 +47,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
47
47
  "session_storage",
48
48
  "clear_storage",
49
49
  "clear_console",
50
+ "dialog_response",
50
51
  "screenshot",
51
52
  "wait",
52
53
  "wait_for_selector",
@@ -308,7 +309,7 @@ function isSupportedCheckType(value) {
308
309
  }
309
310
  function normalizeSetupActionType(value, index) {
310
311
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
311
- 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;
312
+ 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;
312
313
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
313
314
  return normalized;
314
315
  }
@@ -360,6 +361,7 @@ function normalizeSetupActionCoordinateMode(value, index) {
360
361
  function normalizeSetupAction(input, index) {
361
362
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
362
363
  const type = normalizeSetupActionType(stringValue(input.type), index);
364
+ const rawType = String(input.type || "").trim().replace(/-/g, "_").toLowerCase();
363
365
  const selector = stringValue(input.selector);
364
366
  const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
365
367
  const frameIndex = numberValue(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
@@ -401,6 +403,21 @@ function normalizeSetupAction(input, index) {
401
403
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
402
404
  }
403
405
  const key = stringValue(input.key);
406
+ let dialogAccept;
407
+ if (type === "dialog_response") {
408
+ const acceptInput = valueFromOwn(input, "accept", "accepted", "should_accept", "shouldAccept");
409
+ const responseInput = stringFromOwn(input, "response", "dialog_response", "dialogResponse", "mode");
410
+ const response = String(responseInput || "").trim().toLowerCase().replace(/-/g, "_");
411
+ if (acceptInput !== void 0) {
412
+ dialogAccept = acceptInput !== false && String(acceptInput).toLowerCase() !== "false";
413
+ } else if (rawType === "dismiss_dialog" || rawType === "dismiss_dialogs" || rawType === "cancel_dialog") {
414
+ dialogAccept = false;
415
+ } else if (response === "dismiss" || response === "cancel" || response === "reject" || response === "no" || response === "false") {
416
+ dialogAccept = false;
417
+ } else {
418
+ dialogAccept = true;
419
+ }
420
+ }
404
421
  if (type === "press" && !key) {
405
422
  throw new Error(`target.setup_actions[${index}] ${type} requires key.`);
406
423
  }
@@ -462,6 +479,10 @@ function normalizeSetupAction(input, index) {
462
479
  text: stringValue(input.text),
463
480
  pattern: stringValue(input.pattern),
464
481
  flags: stringValue(input.flags),
482
+ accept: dialogAccept,
483
+ prompt_text: stringFromOwn(input, "prompt_text", "promptText", "prompt_value", "promptValue"),
484
+ message_text: stringFromOwn(input, "message_text", "messageText", "dialog_text", "dialogText"),
485
+ message_pattern: stringFromOwn(input, "message_pattern", "messagePattern", "dialog_pattern", "dialogPattern"),
465
486
  index: numberValue(input.index),
466
487
  expected_count: expectedCount,
467
488
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
@@ -927,6 +948,41 @@ function matchesAllowedMessage(input, texts, patterns) {
927
948
  }
928
949
  return false;
929
950
  }
951
+ function consoleEventLocationUrl(input) {
952
+ if (!isRecord(input) || !isRecord(input.location)) return void 0;
953
+ return stringValue(input.location.url);
954
+ }
955
+ function expectedFailedNetworkMockEvents(evidence) {
956
+ return (evidence.network_mocks || []).filter((event) => {
957
+ if (!isRecord(event) || event.ok === false) return false;
958
+ const status = numberValue(event.status);
959
+ return status !== void 0 && status >= 400 && Boolean(stringValue(event.url));
960
+ });
961
+ }
962
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
963
+ const sample = allowedMessageSample(event);
964
+ if (!/Failed to load resource/i.test(sample)) return void 0;
965
+ const eventUrl = consoleEventLocationUrl(event);
966
+ if (!eventUrl) return void 0;
967
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
968
+ const status = numberValue(mockEvent.status);
969
+ return stringValue(mockEvent.url) === eventUrl && status !== void 0 && sample.includes(String(status));
970
+ });
971
+ }
972
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
973
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
974
+ }
975
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
976
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
977
+ const sample = allowedMessageSample(event);
978
+ return {
979
+ url: consoleEventLocationUrl(event) ?? null,
980
+ status: match ? numberValue(match.status) ?? null : null,
981
+ label: match ? stringValue(match.label) ?? null : null,
982
+ response_label: match ? stringValue(match.response_label) ?? null : null,
983
+ text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
984
+ };
985
+ }
930
986
  function normalizeRoutePath(path) {
931
987
  const value = path || "/";
932
988
  if (value === "/") return "/";
@@ -1344,8 +1400,10 @@ function assessCheckFromEvidence(check, evidence) {
1344
1400
  }
1345
1401
  if (check.type === "no_fatal_console_errors") {
1346
1402
  const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
1347
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1348
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1403
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1404
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1405
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) || isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1406
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && !isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1349
1407
  const pageErrors = evidence.page_errors || [];
1350
1408
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1351
1409
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -1360,6 +1418,9 @@ function assessCheckFromEvidence(check, evidence) {
1360
1418
  total_console_fatal_count: fatalConsoleEvents.length,
1361
1419
  total_page_error_count: pageErrors.length,
1362
1420
  allowed_console_fatal_count: allowedConsoleEvents.length,
1421
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
1422
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
1423
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
1363
1424
  allowed_page_error_count: allowedPageErrors.length,
1364
1425
  allowed_console_texts: check.allowed_console_texts || [],
1365
1426
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -1722,6 +1783,44 @@ function matchesAllowedMessage(input, texts, patterns) {
1722
1783
  }
1723
1784
  return false;
1724
1785
  }
1786
+ function consoleEventLocationUrl(input) {
1787
+ if (!input || typeof input !== "object" || Array.isArray(input)) return undefined;
1788
+ if (!input.location || typeof input.location !== "object" || Array.isArray(input.location)) return undefined;
1789
+ return typeof input.location.url === "string" && input.location.url.trim() ? input.location.url.trim() : undefined;
1790
+ }
1791
+ function expectedFailedNetworkMockEvents(evidence) {
1792
+ return ((evidence && evidence.network_mocks) || []).filter((event) => {
1793
+ if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
1794
+ const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
1795
+ const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
1796
+ return status !== undefined && status >= 400 && Boolean(url);
1797
+ });
1798
+ }
1799
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1800
+ const sample = allowedMessageSample(event);
1801
+ if (!/Failed to load resource/i.test(sample)) return undefined;
1802
+ const eventUrl = consoleEventLocationUrl(event);
1803
+ if (!eventUrl) return undefined;
1804
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
1805
+ const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
1806
+ const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
1807
+ return mockUrl === eventUrl && status !== undefined && sample.includes(String(status));
1808
+ });
1809
+ }
1810
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1811
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
1812
+ }
1813
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
1814
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
1815
+ const sample = allowedMessageSample(event);
1816
+ return {
1817
+ url: consoleEventLocationUrl(event) || null,
1818
+ status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
1819
+ label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
1820
+ response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
1821
+ text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
1822
+ };
1823
+ }
1725
1824
  function textSequenceForCheck(viewport, check) {
1726
1825
  const key = check.selector || "";
1727
1826
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -2445,8 +2544,19 @@ function assessProfile(profile, evidence) {
2445
2544
  }
2446
2545
  if (check.type === "no_fatal_console_errors") {
2447
2546
  const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
2448
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2449
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2547
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2548
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => (
2549
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2550
+ && isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2551
+ ));
2552
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => (
2553
+ matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2554
+ || isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2555
+ ));
2556
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => (
2557
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2558
+ && !isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2559
+ ));
2450
2560
  const pageErrors = evidence.page_errors || [];
2451
2561
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
2452
2562
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -2461,6 +2571,9 @@ function assessProfile(profile, evidence) {
2461
2571
  total_console_fatal_count: fatalConsoleEvents.length,
2462
2572
  total_page_error_count: pageErrors.length,
2463
2573
  allowed_console_fatal_count: allowedConsoleEvents.length,
2574
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
2575
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
2576
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
2464
2577
  allowed_page_error_count: allowedPageErrors.length,
2465
2578
  allowed_console_texts: check.allowed_console_texts || [],
2466
2579
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -2520,6 +2633,9 @@ const capturedAt = new Date().toISOString();
2520
2633
  const consoleEvents = [];
2521
2634
  const pageErrors = [];
2522
2635
  const networkMockEvents = [];
2636
+ const dialogEvents = [];
2637
+ let dialogResponseConfig = null;
2638
+ let dialogHandlerInstalled = false;
2523
2639
  page.on("console", (message) => {
2524
2640
  const type = message.type();
2525
2641
  if (type === "error" || type === "warning" || type === "assert") {
@@ -2533,6 +2649,50 @@ page.on("console", (message) => {
2533
2649
  page.on("pageerror", (error) => {
2534
2650
  pageErrors.push({ message: String(error && error.message ? error.message : error).slice(0, 1000) });
2535
2651
  });
2652
+ function setupDialogMessageMatches(message, config) {
2653
+ if (!config) return true;
2654
+ if (config.message_pattern) {
2655
+ try { return new RegExp(config.message_pattern, config.flags || "").test(message || ""); } catch { return false; }
2656
+ }
2657
+ if (config.message_text) return String(message || "").includes(config.message_text);
2658
+ return true;
2659
+ }
2660
+ function ensureDialogHandler() {
2661
+ if (dialogHandlerInstalled) return;
2662
+ dialogHandlerInstalled = true;
2663
+ page.on("dialog", async (dialog) => {
2664
+ const config = dialogResponseConfig || { accept: false };
2665
+ const message = typeof dialog.message === "function" ? dialog.message() : "";
2666
+ const type = typeof dialog.type === "function" ? dialog.type() : "dialog";
2667
+ const defaultValue = typeof dialog.defaultValue === "function" ? dialog.defaultValue() : "";
2668
+ const accept = config.accept !== false;
2669
+ const event = {
2670
+ type,
2671
+ message: String(message || "").slice(0, 1000),
2672
+ default_value: String(defaultValue || "").slice(0, 500),
2673
+ configured: Boolean(dialogResponseConfig),
2674
+ response: accept ? "accept" : "dismiss",
2675
+ message_matches: setupDialogMessageMatches(message, config),
2676
+ expected_message_text: config.message_text || undefined,
2677
+ expected_message_pattern: config.message_pattern || undefined,
2678
+ };
2679
+ try {
2680
+ if (accept) {
2681
+ const promptText = config.prompt_text === undefined ? undefined : String(config.prompt_text);
2682
+ await dialog.accept(promptText);
2683
+ } else {
2684
+ await dialog.dismiss();
2685
+ }
2686
+ dialogEvents.push({ ...event, ok: true });
2687
+ } catch (error) {
2688
+ dialogEvents.push({
2689
+ ...event,
2690
+ ok: false,
2691
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
2692
+ });
2693
+ }
2694
+ });
2695
+ }
2536
2696
  function textKey(check) {
2537
2697
  return check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
2538
2698
  }
@@ -2871,6 +3031,24 @@ async function executeSetupAction(action, ordinal, viewport) {
2871
3031
  pageErrors.length = 0;
2872
3032
  return { ...base, ok: true, cleared_console_event_count, cleared_page_error_count };
2873
3033
  }
3034
+ if (type === "dialog_response") {
3035
+ ensureDialogHandler();
3036
+ dialogResponseConfig = {
3037
+ accept: action.accept !== false,
3038
+ prompt_text: action.prompt_text,
3039
+ message_text: action.message_text,
3040
+ message_pattern: action.message_pattern,
3041
+ flags: action.flags || "",
3042
+ };
3043
+ return {
3044
+ ...base,
3045
+ ok: true,
3046
+ response: dialogResponseConfig.accept ? "accept" : "dismiss",
3047
+ message_text: dialogResponseConfig.message_text || undefined,
3048
+ message_pattern: dialogResponseConfig.message_pattern || undefined,
3049
+ prompt_text_length: dialogResponseConfig.prompt_text === undefined ? undefined : String(dialogResponseConfig.prompt_text).length,
3050
+ };
3051
+ }
2874
3052
  if (type === "wait_for_selector") {
2875
3053
  const scope = await setupActionScope(action, timeout);
2876
3054
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -3971,6 +4149,7 @@ function buildProfileEvidence(currentViewports) {
3971
4149
  fatal_count: consoleEvents.filter((event) => event.type === "error" || event.type === "assert").length,
3972
4150
  },
3973
4151
  page_errors: pageErrors,
4152
+ dialogs: dialogEvents.slice(),
3974
4153
  network_mocks: networkMockEvents.slice(),
3975
4154
  dom_summary: {
3976
4155
  expected_viewport_count: expectedViewportCount,
@@ -4010,6 +4189,9 @@ function buildProfileEvidence(currentViewports) {
4010
4189
  })),
4011
4190
  network_mock_count: (profile.target.network_mocks || []).length,
4012
4191
  network_mock_hit_count: networkMockEvents.filter((event) => event.ok !== false).length,
4192
+ dialog_count: dialogEvents.length,
4193
+ dialog_accept_count: dialogEvents.filter((event) => event.response === "accept" && event.ok !== false).length,
4194
+ dialog_dismiss_count: dialogEvents.filter((event) => event.response === "dismiss" && event.ok !== false).length,
4013
4195
  },
4014
4196
  };
4015
4197
  }
@@ -4018,7 +4200,7 @@ async function saveProfileArtifacts(currentViewports) {
4018
4200
  const result = assessProfile(profile, evidence);
4019
4201
  if (typeof saveJson === "function") {
4020
4202
  await saveJson("proof.json", result);
4021
- await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors });
4203
+ await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors, dialogs: dialogEvents });
4022
4204
  await saveJson("dom-summary.json", evidence.dom_summary);
4023
4205
  }
4024
4206
  return result;
package/dist/cli.cjs CHANGED
@@ -6920,6 +6920,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
6920
6920
  "session_storage",
6921
6921
  "clear_storage",
6922
6922
  "clear_console",
6923
+ "dialog_response",
6923
6924
  "screenshot",
6924
6925
  "wait",
6925
6926
  "wait_for_selector",
@@ -7181,7 +7182,7 @@ function isSupportedCheckType(value) {
7181
7182
  }
7182
7183
  function normalizeSetupActionType(value, index) {
7183
7184
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
7184
- 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;
7185
+ 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;
7185
7186
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
7186
7187
  return normalized;
7187
7188
  }
@@ -7233,6 +7234,7 @@ function normalizeSetupActionCoordinateMode(value, index) {
7233
7234
  function normalizeSetupAction(input, index) {
7234
7235
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
7235
7236
  const type = normalizeSetupActionType(stringValue2(input.type), index);
7237
+ const rawType = String(input.type || "").trim().replace(/-/g, "_").toLowerCase();
7236
7238
  const selector = stringValue2(input.selector);
7237
7239
  const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
7238
7240
  const frameIndex = numberValue(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
@@ -7274,6 +7276,21 @@ function normalizeSetupAction(input, index) {
7274
7276
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
7275
7277
  }
7276
7278
  const key = stringValue2(input.key);
7279
+ let dialogAccept;
7280
+ if (type === "dialog_response") {
7281
+ const acceptInput = valueFromOwn(input, "accept", "accepted", "should_accept", "shouldAccept");
7282
+ const responseInput = stringFromOwn(input, "response", "dialog_response", "dialogResponse", "mode");
7283
+ const response = String(responseInput || "").trim().toLowerCase().replace(/-/g, "_");
7284
+ if (acceptInput !== void 0) {
7285
+ dialogAccept = acceptInput !== false && String(acceptInput).toLowerCase() !== "false";
7286
+ } else if (rawType === "dismiss_dialog" || rawType === "dismiss_dialogs" || rawType === "cancel_dialog") {
7287
+ dialogAccept = false;
7288
+ } else if (response === "dismiss" || response === "cancel" || response === "reject" || response === "no" || response === "false") {
7289
+ dialogAccept = false;
7290
+ } else {
7291
+ dialogAccept = true;
7292
+ }
7293
+ }
7277
7294
  if (type === "press" && !key) {
7278
7295
  throw new Error(`target.setup_actions[${index}] ${type} requires key.`);
7279
7296
  }
@@ -7335,6 +7352,10 @@ function normalizeSetupAction(input, index) {
7335
7352
  text: stringValue2(input.text),
7336
7353
  pattern: stringValue2(input.pattern),
7337
7354
  flags: stringValue2(input.flags),
7355
+ accept: dialogAccept,
7356
+ prompt_text: stringFromOwn(input, "prompt_text", "promptText", "prompt_value", "promptValue"),
7357
+ message_text: stringFromOwn(input, "message_text", "messageText", "dialog_text", "dialogText"),
7358
+ message_pattern: stringFromOwn(input, "message_pattern", "messagePattern", "dialog_pattern", "dialogPattern"),
7338
7359
  index: numberValue(input.index),
7339
7360
  expected_count: expectedCount,
7340
7361
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
@@ -7800,6 +7821,41 @@ function matchesAllowedMessage(input, texts, patterns) {
7800
7821
  }
7801
7822
  return false;
7802
7823
  }
7824
+ function consoleEventLocationUrl(input) {
7825
+ if (!isRecord(input) || !isRecord(input.location)) return void 0;
7826
+ return stringValue2(input.location.url);
7827
+ }
7828
+ function expectedFailedNetworkMockEvents(evidence) {
7829
+ return (evidence.network_mocks || []).filter((event) => {
7830
+ if (!isRecord(event) || event.ok === false) return false;
7831
+ const status = numberValue(event.status);
7832
+ return status !== void 0 && status >= 400 && Boolean(stringValue2(event.url));
7833
+ });
7834
+ }
7835
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
7836
+ const sample = allowedMessageSample(event);
7837
+ if (!/Failed to load resource/i.test(sample)) return void 0;
7838
+ const eventUrl = consoleEventLocationUrl(event);
7839
+ if (!eventUrl) return void 0;
7840
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
7841
+ const status = numberValue(mockEvent.status);
7842
+ return stringValue2(mockEvent.url) === eventUrl && status !== void 0 && sample.includes(String(status));
7843
+ });
7844
+ }
7845
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
7846
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
7847
+ }
7848
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
7849
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
7850
+ const sample = allowedMessageSample(event);
7851
+ return {
7852
+ url: consoleEventLocationUrl(event) ?? null,
7853
+ status: match ? numberValue(match.status) ?? null : null,
7854
+ label: match ? stringValue2(match.label) ?? null : null,
7855
+ response_label: match ? stringValue2(match.response_label) ?? null : null,
7856
+ text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
7857
+ };
7858
+ }
7803
7859
  function normalizeRoutePath(path7) {
7804
7860
  const value = path7 || "/";
7805
7861
  if (value === "/") return "/";
@@ -8217,8 +8273,10 @@ function assessCheckFromEvidence(check, evidence) {
8217
8273
  }
8218
8274
  if (check.type === "no_fatal_console_errors") {
8219
8275
  const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
8220
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
8221
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
8276
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
8277
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && isExpectedFailedNetworkMockConsoleEvent(event, evidence));
8278
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) || isExpectedFailedNetworkMockConsoleEvent(event, evidence));
8279
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && !isExpectedFailedNetworkMockConsoleEvent(event, evidence));
8222
8280
  const pageErrors = evidence.page_errors || [];
8223
8281
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
8224
8282
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -8233,6 +8291,9 @@ function assessCheckFromEvidence(check, evidence) {
8233
8291
  total_console_fatal_count: fatalConsoleEvents.length,
8234
8292
  total_page_error_count: pageErrors.length,
8235
8293
  allowed_console_fatal_count: allowedConsoleEvents.length,
8294
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
8295
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
8296
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
8236
8297
  allowed_page_error_count: allowedPageErrors.length,
8237
8298
  allowed_console_texts: check.allowed_console_texts || [],
8238
8299
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -8579,6 +8640,44 @@ function matchesAllowedMessage(input, texts, patterns) {
8579
8640
  }
8580
8641
  return false;
8581
8642
  }
8643
+ function consoleEventLocationUrl(input) {
8644
+ if (!input || typeof input !== "object" || Array.isArray(input)) return undefined;
8645
+ if (!input.location || typeof input.location !== "object" || Array.isArray(input.location)) return undefined;
8646
+ return typeof input.location.url === "string" && input.location.url.trim() ? input.location.url.trim() : undefined;
8647
+ }
8648
+ function expectedFailedNetworkMockEvents(evidence) {
8649
+ return ((evidence && evidence.network_mocks) || []).filter((event) => {
8650
+ if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
8651
+ const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
8652
+ const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
8653
+ return status !== undefined && status >= 400 && Boolean(url);
8654
+ });
8655
+ }
8656
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
8657
+ const sample = allowedMessageSample(event);
8658
+ if (!/Failed to load resource/i.test(sample)) return undefined;
8659
+ const eventUrl = consoleEventLocationUrl(event);
8660
+ if (!eventUrl) return undefined;
8661
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
8662
+ const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
8663
+ const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
8664
+ return mockUrl === eventUrl && status !== undefined && sample.includes(String(status));
8665
+ });
8666
+ }
8667
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
8668
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
8669
+ }
8670
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
8671
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
8672
+ const sample = allowedMessageSample(event);
8673
+ return {
8674
+ url: consoleEventLocationUrl(event) || null,
8675
+ status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
8676
+ label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
8677
+ response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
8678
+ text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
8679
+ };
8680
+ }
8582
8681
  function textSequenceForCheck(viewport, check) {
8583
8682
  const key = check.selector || "";
8584
8683
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -9302,8 +9401,19 @@ function assessProfile(profile, evidence) {
9302
9401
  }
9303
9402
  if (check.type === "no_fatal_console_errors") {
9304
9403
  const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
9305
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
9306
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
9404
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
9405
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => (
9406
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
9407
+ && isExpectedFailedNetworkMockConsoleEvent(event, evidence)
9408
+ ));
9409
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => (
9410
+ matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
9411
+ || isExpectedFailedNetworkMockConsoleEvent(event, evidence)
9412
+ ));
9413
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => (
9414
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
9415
+ && !isExpectedFailedNetworkMockConsoleEvent(event, evidence)
9416
+ ));
9307
9417
  const pageErrors = evidence.page_errors || [];
9308
9418
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
9309
9419
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -9318,6 +9428,9 @@ function assessProfile(profile, evidence) {
9318
9428
  total_console_fatal_count: fatalConsoleEvents.length,
9319
9429
  total_page_error_count: pageErrors.length,
9320
9430
  allowed_console_fatal_count: allowedConsoleEvents.length,
9431
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
9432
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
9433
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
9321
9434
  allowed_page_error_count: allowedPageErrors.length,
9322
9435
  allowed_console_texts: check.allowed_console_texts || [],
9323
9436
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -9377,6 +9490,9 @@ const capturedAt = new Date().toISOString();
9377
9490
  const consoleEvents = [];
9378
9491
  const pageErrors = [];
9379
9492
  const networkMockEvents = [];
9493
+ const dialogEvents = [];
9494
+ let dialogResponseConfig = null;
9495
+ let dialogHandlerInstalled = false;
9380
9496
  page.on("console", (message) => {
9381
9497
  const type = message.type();
9382
9498
  if (type === "error" || type === "warning" || type === "assert") {
@@ -9390,6 +9506,50 @@ page.on("console", (message) => {
9390
9506
  page.on("pageerror", (error) => {
9391
9507
  pageErrors.push({ message: String(error && error.message ? error.message : error).slice(0, 1000) });
9392
9508
  });
9509
+ function setupDialogMessageMatches(message, config) {
9510
+ if (!config) return true;
9511
+ if (config.message_pattern) {
9512
+ try { return new RegExp(config.message_pattern, config.flags || "").test(message || ""); } catch { return false; }
9513
+ }
9514
+ if (config.message_text) return String(message || "").includes(config.message_text);
9515
+ return true;
9516
+ }
9517
+ function ensureDialogHandler() {
9518
+ if (dialogHandlerInstalled) return;
9519
+ dialogHandlerInstalled = true;
9520
+ page.on("dialog", async (dialog) => {
9521
+ const config = dialogResponseConfig || { accept: false };
9522
+ const message = typeof dialog.message === "function" ? dialog.message() : "";
9523
+ const type = typeof dialog.type === "function" ? dialog.type() : "dialog";
9524
+ const defaultValue = typeof dialog.defaultValue === "function" ? dialog.defaultValue() : "";
9525
+ const accept = config.accept !== false;
9526
+ const event = {
9527
+ type,
9528
+ message: String(message || "").slice(0, 1000),
9529
+ default_value: String(defaultValue || "").slice(0, 500),
9530
+ configured: Boolean(dialogResponseConfig),
9531
+ response: accept ? "accept" : "dismiss",
9532
+ message_matches: setupDialogMessageMatches(message, config),
9533
+ expected_message_text: config.message_text || undefined,
9534
+ expected_message_pattern: config.message_pattern || undefined,
9535
+ };
9536
+ try {
9537
+ if (accept) {
9538
+ const promptText = config.prompt_text === undefined ? undefined : String(config.prompt_text);
9539
+ await dialog.accept(promptText);
9540
+ } else {
9541
+ await dialog.dismiss();
9542
+ }
9543
+ dialogEvents.push({ ...event, ok: true });
9544
+ } catch (error) {
9545
+ dialogEvents.push({
9546
+ ...event,
9547
+ ok: false,
9548
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
9549
+ });
9550
+ }
9551
+ });
9552
+ }
9393
9553
  function textKey(check) {
9394
9554
  return check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
9395
9555
  }
@@ -9728,6 +9888,24 @@ async function executeSetupAction(action, ordinal, viewport) {
9728
9888
  pageErrors.length = 0;
9729
9889
  return { ...base, ok: true, cleared_console_event_count, cleared_page_error_count };
9730
9890
  }
9891
+ if (type === "dialog_response") {
9892
+ ensureDialogHandler();
9893
+ dialogResponseConfig = {
9894
+ accept: action.accept !== false,
9895
+ prompt_text: action.prompt_text,
9896
+ message_text: action.message_text,
9897
+ message_pattern: action.message_pattern,
9898
+ flags: action.flags || "",
9899
+ };
9900
+ return {
9901
+ ...base,
9902
+ ok: true,
9903
+ response: dialogResponseConfig.accept ? "accept" : "dismiss",
9904
+ message_text: dialogResponseConfig.message_text || undefined,
9905
+ message_pattern: dialogResponseConfig.message_pattern || undefined,
9906
+ prompt_text_length: dialogResponseConfig.prompt_text === undefined ? undefined : String(dialogResponseConfig.prompt_text).length,
9907
+ };
9908
+ }
9731
9909
  if (type === "wait_for_selector") {
9732
9910
  const scope = await setupActionScope(action, timeout);
9733
9911
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -10828,6 +11006,7 @@ function buildProfileEvidence(currentViewports) {
10828
11006
  fatal_count: consoleEvents.filter((event) => event.type === "error" || event.type === "assert").length,
10829
11007
  },
10830
11008
  page_errors: pageErrors,
11009
+ dialogs: dialogEvents.slice(),
10831
11010
  network_mocks: networkMockEvents.slice(),
10832
11011
  dom_summary: {
10833
11012
  expected_viewport_count: expectedViewportCount,
@@ -10867,6 +11046,9 @@ function buildProfileEvidence(currentViewports) {
10867
11046
  })),
10868
11047
  network_mock_count: (profile.target.network_mocks || []).length,
10869
11048
  network_mock_hit_count: networkMockEvents.filter((event) => event.ok !== false).length,
11049
+ dialog_count: dialogEvents.length,
11050
+ dialog_accept_count: dialogEvents.filter((event) => event.response === "accept" && event.ok !== false).length,
11051
+ dialog_dismiss_count: dialogEvents.filter((event) => event.response === "dismiss" && event.ok !== false).length,
10870
11052
  },
10871
11053
  };
10872
11054
  }
@@ -10875,7 +11057,7 @@ async function saveProfileArtifacts(currentViewports) {
10875
11057
  const result = assessProfile(profile, evidence);
10876
11058
  if (typeof saveJson === "function") {
10877
11059
  await saveJson("proof.json", result);
10878
- await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors });
11060
+ await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors, dialogs: dialogEvents });
10879
11061
  await saveJson("dom-summary.json", evidence.dom_summary);
10880
11062
  }
10881
11063
  return result;
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-RBZ4A5M4.js";
13
+ } from "./chunk-3RUIKF4C.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport