@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.
package/dist/index.cjs CHANGED
@@ -8761,6 +8761,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8761
8761
  "session_storage",
8762
8762
  "clear_storage",
8763
8763
  "clear_console",
8764
+ "dialog_response",
8764
8765
  "screenshot",
8765
8766
  "wait",
8766
8767
  "wait_for_selector",
@@ -9022,7 +9023,7 @@ function isSupportedCheckType(value) {
9022
9023
  }
9023
9024
  function normalizeSetupActionType(value, index) {
9024
9025
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
9025
- 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;
9026
+ 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;
9026
9027
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
9027
9028
  return normalized;
9028
9029
  }
@@ -9074,6 +9075,7 @@ function normalizeSetupActionCoordinateMode(value, index) {
9074
9075
  function normalizeSetupAction(input, index) {
9075
9076
  if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
9076
9077
  const type = normalizeSetupActionType(stringValue5(input.type), index);
9078
+ const rawType = String(input.type || "").trim().replace(/-/g, "_").toLowerCase();
9077
9079
  const selector = stringValue5(input.selector);
9078
9080
  const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
9079
9081
  const frameIndex = numberValue3(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
@@ -9115,6 +9117,21 @@ function normalizeSetupAction(input, index) {
9115
9117
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
9116
9118
  }
9117
9119
  const key = stringValue5(input.key);
9120
+ let dialogAccept;
9121
+ if (type === "dialog_response") {
9122
+ const acceptInput = valueFromOwn(input, "accept", "accepted", "should_accept", "shouldAccept");
9123
+ const responseInput = stringFromOwn(input, "response", "dialog_response", "dialogResponse", "mode");
9124
+ const response = String(responseInput || "").trim().toLowerCase().replace(/-/g, "_");
9125
+ if (acceptInput !== void 0) {
9126
+ dialogAccept = acceptInput !== false && String(acceptInput).toLowerCase() !== "false";
9127
+ } else if (rawType === "dismiss_dialog" || rawType === "dismiss_dialogs" || rawType === "cancel_dialog") {
9128
+ dialogAccept = false;
9129
+ } else if (response === "dismiss" || response === "cancel" || response === "reject" || response === "no" || response === "false") {
9130
+ dialogAccept = false;
9131
+ } else {
9132
+ dialogAccept = true;
9133
+ }
9134
+ }
9118
9135
  if (type === "press" && !key) {
9119
9136
  throw new Error(`target.setup_actions[${index}] ${type} requires key.`);
9120
9137
  }
@@ -9176,6 +9193,10 @@ function normalizeSetupAction(input, index) {
9176
9193
  text: stringValue5(input.text),
9177
9194
  pattern: stringValue5(input.pattern),
9178
9195
  flags: stringValue5(input.flags),
9196
+ accept: dialogAccept,
9197
+ prompt_text: stringFromOwn(input, "prompt_text", "promptText", "prompt_value", "promptValue"),
9198
+ message_text: stringFromOwn(input, "message_text", "messageText", "dialog_text", "dialogText"),
9199
+ message_pattern: stringFromOwn(input, "message_pattern", "messagePattern", "dialog_pattern", "dialogPattern"),
9179
9200
  index: numberValue3(input.index),
9180
9201
  expected_count: expectedCount,
9181
9202
  ms: numberValue3(input.ms) ?? numberValue3(input.wait_ms) ?? numberValue3(input.waitMs),
@@ -9641,6 +9662,41 @@ function matchesAllowedMessage(input, texts, patterns) {
9641
9662
  }
9642
9663
  return false;
9643
9664
  }
9665
+ function consoleEventLocationUrl(input) {
9666
+ if (!isRecord2(input) || !isRecord2(input.location)) return void 0;
9667
+ return stringValue5(input.location.url);
9668
+ }
9669
+ function expectedFailedNetworkMockEvents(evidence) {
9670
+ return (evidence.network_mocks || []).filter((event) => {
9671
+ if (!isRecord2(event) || event.ok === false) return false;
9672
+ const status = numberValue3(event.status);
9673
+ return status !== void 0 && status >= 400 && Boolean(stringValue5(event.url));
9674
+ });
9675
+ }
9676
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
9677
+ const sample = allowedMessageSample(event);
9678
+ if (!/Failed to load resource/i.test(sample)) return void 0;
9679
+ const eventUrl = consoleEventLocationUrl(event);
9680
+ if (!eventUrl) return void 0;
9681
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
9682
+ const status = numberValue3(mockEvent.status);
9683
+ return stringValue5(mockEvent.url) === eventUrl && status !== void 0 && sample.includes(String(status));
9684
+ });
9685
+ }
9686
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
9687
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
9688
+ }
9689
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
9690
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
9691
+ const sample = allowedMessageSample(event);
9692
+ return {
9693
+ url: consoleEventLocationUrl(event) ?? null,
9694
+ status: match ? numberValue3(match.status) ?? null : null,
9695
+ label: match ? stringValue5(match.label) ?? null : null,
9696
+ response_label: match ? stringValue5(match.response_label) ?? null : null,
9697
+ text: isRecord2(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
9698
+ };
9699
+ }
9644
9700
  function normalizeRoutePath(path6) {
9645
9701
  const value = path6 || "/";
9646
9702
  if (value === "/") return "/";
@@ -10058,8 +10114,10 @@ function assessCheckFromEvidence(check, evidence) {
10058
10114
  }
10059
10115
  if (check.type === "no_fatal_console_errors") {
10060
10116
  const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
10061
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
10062
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
10117
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
10118
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && isExpectedFailedNetworkMockConsoleEvent(event, evidence));
10119
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) || isExpectedFailedNetworkMockConsoleEvent(event, evidence));
10120
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && !isExpectedFailedNetworkMockConsoleEvent(event, evidence));
10063
10121
  const pageErrors = evidence.page_errors || [];
10064
10122
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
10065
10123
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -10074,6 +10132,9 @@ function assessCheckFromEvidence(check, evidence) {
10074
10132
  total_console_fatal_count: fatalConsoleEvents.length,
10075
10133
  total_page_error_count: pageErrors.length,
10076
10134
  allowed_console_fatal_count: allowedConsoleEvents.length,
10135
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
10136
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
10137
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
10077
10138
  allowed_page_error_count: allowedPageErrors.length,
10078
10139
  allowed_console_texts: check.allowed_console_texts || [],
10079
10140
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -10436,6 +10497,44 @@ function matchesAllowedMessage(input, texts, patterns) {
10436
10497
  }
10437
10498
  return false;
10438
10499
  }
10500
+ function consoleEventLocationUrl(input) {
10501
+ if (!input || typeof input !== "object" || Array.isArray(input)) return undefined;
10502
+ if (!input.location || typeof input.location !== "object" || Array.isArray(input.location)) return undefined;
10503
+ return typeof input.location.url === "string" && input.location.url.trim() ? input.location.url.trim() : undefined;
10504
+ }
10505
+ function expectedFailedNetworkMockEvents(evidence) {
10506
+ return ((evidence && evidence.network_mocks) || []).filter((event) => {
10507
+ if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
10508
+ const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
10509
+ const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
10510
+ return status !== undefined && status >= 400 && Boolean(url);
10511
+ });
10512
+ }
10513
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
10514
+ const sample = allowedMessageSample(event);
10515
+ if (!/Failed to load resource/i.test(sample)) return undefined;
10516
+ const eventUrl = consoleEventLocationUrl(event);
10517
+ if (!eventUrl) return undefined;
10518
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
10519
+ const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
10520
+ const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
10521
+ return mockUrl === eventUrl && status !== undefined && sample.includes(String(status));
10522
+ });
10523
+ }
10524
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
10525
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
10526
+ }
10527
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
10528
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
10529
+ const sample = allowedMessageSample(event);
10530
+ return {
10531
+ url: consoleEventLocationUrl(event) || null,
10532
+ status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
10533
+ label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
10534
+ response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
10535
+ text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
10536
+ };
10537
+ }
10439
10538
  function textSequenceForCheck(viewport, check) {
10440
10539
  const key = check.selector || "";
10441
10540
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -11159,8 +11258,19 @@ function assessProfile(profile, evidence) {
11159
11258
  }
11160
11259
  if (check.type === "no_fatal_console_errors") {
11161
11260
  const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
11162
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
11163
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
11261
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
11262
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => (
11263
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
11264
+ && isExpectedFailedNetworkMockConsoleEvent(event, evidence)
11265
+ ));
11266
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => (
11267
+ matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
11268
+ || isExpectedFailedNetworkMockConsoleEvent(event, evidence)
11269
+ ));
11270
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => (
11271
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
11272
+ && !isExpectedFailedNetworkMockConsoleEvent(event, evidence)
11273
+ ));
11164
11274
  const pageErrors = evidence.page_errors || [];
11165
11275
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
11166
11276
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -11175,6 +11285,9 @@ function assessProfile(profile, evidence) {
11175
11285
  total_console_fatal_count: fatalConsoleEvents.length,
11176
11286
  total_page_error_count: pageErrors.length,
11177
11287
  allowed_console_fatal_count: allowedConsoleEvents.length,
11288
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
11289
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
11290
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
11178
11291
  allowed_page_error_count: allowedPageErrors.length,
11179
11292
  allowed_console_texts: check.allowed_console_texts || [],
11180
11293
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -11234,6 +11347,9 @@ const capturedAt = new Date().toISOString();
11234
11347
  const consoleEvents = [];
11235
11348
  const pageErrors = [];
11236
11349
  const networkMockEvents = [];
11350
+ const dialogEvents = [];
11351
+ let dialogResponseConfig = null;
11352
+ let dialogHandlerInstalled = false;
11237
11353
  page.on("console", (message) => {
11238
11354
  const type = message.type();
11239
11355
  if (type === "error" || type === "warning" || type === "assert") {
@@ -11247,6 +11363,50 @@ page.on("console", (message) => {
11247
11363
  page.on("pageerror", (error) => {
11248
11364
  pageErrors.push({ message: String(error && error.message ? error.message : error).slice(0, 1000) });
11249
11365
  });
11366
+ function setupDialogMessageMatches(message, config) {
11367
+ if (!config) return true;
11368
+ if (config.message_pattern) {
11369
+ try { return new RegExp(config.message_pattern, config.flags || "").test(message || ""); } catch { return false; }
11370
+ }
11371
+ if (config.message_text) return String(message || "").includes(config.message_text);
11372
+ return true;
11373
+ }
11374
+ function ensureDialogHandler() {
11375
+ if (dialogHandlerInstalled) return;
11376
+ dialogHandlerInstalled = true;
11377
+ page.on("dialog", async (dialog) => {
11378
+ const config = dialogResponseConfig || { accept: false };
11379
+ const message = typeof dialog.message === "function" ? dialog.message() : "";
11380
+ const type = typeof dialog.type === "function" ? dialog.type() : "dialog";
11381
+ const defaultValue = typeof dialog.defaultValue === "function" ? dialog.defaultValue() : "";
11382
+ const accept = config.accept !== false;
11383
+ const event = {
11384
+ type,
11385
+ message: String(message || "").slice(0, 1000),
11386
+ default_value: String(defaultValue || "").slice(0, 500),
11387
+ configured: Boolean(dialogResponseConfig),
11388
+ response: accept ? "accept" : "dismiss",
11389
+ message_matches: setupDialogMessageMatches(message, config),
11390
+ expected_message_text: config.message_text || undefined,
11391
+ expected_message_pattern: config.message_pattern || undefined,
11392
+ };
11393
+ try {
11394
+ if (accept) {
11395
+ const promptText = config.prompt_text === undefined ? undefined : String(config.prompt_text);
11396
+ await dialog.accept(promptText);
11397
+ } else {
11398
+ await dialog.dismiss();
11399
+ }
11400
+ dialogEvents.push({ ...event, ok: true });
11401
+ } catch (error) {
11402
+ dialogEvents.push({
11403
+ ...event,
11404
+ ok: false,
11405
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
11406
+ });
11407
+ }
11408
+ });
11409
+ }
11250
11410
  function textKey(check) {
11251
11411
  return check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
11252
11412
  }
@@ -11585,6 +11745,24 @@ async function executeSetupAction(action, ordinal, viewport) {
11585
11745
  pageErrors.length = 0;
11586
11746
  return { ...base, ok: true, cleared_console_event_count, cleared_page_error_count };
11587
11747
  }
11748
+ if (type === "dialog_response") {
11749
+ ensureDialogHandler();
11750
+ dialogResponseConfig = {
11751
+ accept: action.accept !== false,
11752
+ prompt_text: action.prompt_text,
11753
+ message_text: action.message_text,
11754
+ message_pattern: action.message_pattern,
11755
+ flags: action.flags || "",
11756
+ };
11757
+ return {
11758
+ ...base,
11759
+ ok: true,
11760
+ response: dialogResponseConfig.accept ? "accept" : "dismiss",
11761
+ message_text: dialogResponseConfig.message_text || undefined,
11762
+ message_pattern: dialogResponseConfig.message_pattern || undefined,
11763
+ prompt_text_length: dialogResponseConfig.prompt_text === undefined ? undefined : String(dialogResponseConfig.prompt_text).length,
11764
+ };
11765
+ }
11588
11766
  if (type === "wait_for_selector") {
11589
11767
  const scope = await setupActionScope(action, timeout);
11590
11768
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -12685,6 +12863,7 @@ function buildProfileEvidence(currentViewports) {
12685
12863
  fatal_count: consoleEvents.filter((event) => event.type === "error" || event.type === "assert").length,
12686
12864
  },
12687
12865
  page_errors: pageErrors,
12866
+ dialogs: dialogEvents.slice(),
12688
12867
  network_mocks: networkMockEvents.slice(),
12689
12868
  dom_summary: {
12690
12869
  expected_viewport_count: expectedViewportCount,
@@ -12724,6 +12903,9 @@ function buildProfileEvidence(currentViewports) {
12724
12903
  })),
12725
12904
  network_mock_count: (profile.target.network_mocks || []).length,
12726
12905
  network_mock_hit_count: networkMockEvents.filter((event) => event.ok !== false).length,
12906
+ dialog_count: dialogEvents.length,
12907
+ dialog_accept_count: dialogEvents.filter((event) => event.response === "accept" && event.ok !== false).length,
12908
+ dialog_dismiss_count: dialogEvents.filter((event) => event.response === "dismiss" && event.ok !== false).length,
12727
12909
  },
12728
12910
  };
12729
12911
  }
@@ -12732,7 +12914,7 @@ async function saveProfileArtifacts(currentViewports) {
12732
12914
  const result = assessProfile(profile, evidence);
12733
12915
  if (typeof saveJson === "function") {
12734
12916
  await saveJson("proof.json", result);
12735
- await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors });
12917
+ await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors, dialogs: dialogEvents });
12736
12918
  await saveJson("dom-summary.json", evidence.dom_summary);
12737
12919
  }
12738
12920
  return result;
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-RBZ4A5M4.js";
61
+ } from "./chunk-3RUIKF4C.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -90,6 +90,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
90
90
  "session_storage",
91
91
  "clear_storage",
92
92
  "clear_console",
93
+ "dialog_response",
93
94
  "screenshot",
94
95
  "wait",
95
96
  "wait_for_selector",
@@ -351,7 +352,7 @@ function isSupportedCheckType(value) {
351
352
  }
352
353
  function normalizeSetupActionType(value, index) {
353
354
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
354
- 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;
355
+ 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;
355
356
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
356
357
  return normalized;
357
358
  }
@@ -403,6 +404,7 @@ function normalizeSetupActionCoordinateMode(value, index) {
403
404
  function normalizeSetupAction(input, index) {
404
405
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
405
406
  const type = normalizeSetupActionType(stringValue(input.type), index);
407
+ const rawType = String(input.type || "").trim().replace(/-/g, "_").toLowerCase();
406
408
  const selector = stringValue(input.selector);
407
409
  const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
408
410
  const frameIndex = numberValue(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
@@ -444,6 +446,21 @@ function normalizeSetupAction(input, index) {
444
446
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
445
447
  }
446
448
  const key = stringValue(input.key);
449
+ let dialogAccept;
450
+ if (type === "dialog_response") {
451
+ const acceptInput = valueFromOwn(input, "accept", "accepted", "should_accept", "shouldAccept");
452
+ const responseInput = stringFromOwn(input, "response", "dialog_response", "dialogResponse", "mode");
453
+ const response = String(responseInput || "").trim().toLowerCase().replace(/-/g, "_");
454
+ if (acceptInput !== void 0) {
455
+ dialogAccept = acceptInput !== false && String(acceptInput).toLowerCase() !== "false";
456
+ } else if (rawType === "dismiss_dialog" || rawType === "dismiss_dialogs" || rawType === "cancel_dialog") {
457
+ dialogAccept = false;
458
+ } else if (response === "dismiss" || response === "cancel" || response === "reject" || response === "no" || response === "false") {
459
+ dialogAccept = false;
460
+ } else {
461
+ dialogAccept = true;
462
+ }
463
+ }
447
464
  if (type === "press" && !key) {
448
465
  throw new Error(`target.setup_actions[${index}] ${type} requires key.`);
449
466
  }
@@ -505,6 +522,10 @@ function normalizeSetupAction(input, index) {
505
522
  text: stringValue(input.text),
506
523
  pattern: stringValue(input.pattern),
507
524
  flags: stringValue(input.flags),
525
+ accept: dialogAccept,
526
+ prompt_text: stringFromOwn(input, "prompt_text", "promptText", "prompt_value", "promptValue"),
527
+ message_text: stringFromOwn(input, "message_text", "messageText", "dialog_text", "dialogText"),
528
+ message_pattern: stringFromOwn(input, "message_pattern", "messagePattern", "dialog_pattern", "dialogPattern"),
508
529
  index: numberValue(input.index),
509
530
  expected_count: expectedCount,
510
531
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
@@ -970,6 +991,41 @@ function matchesAllowedMessage(input, texts, patterns) {
970
991
  }
971
992
  return false;
972
993
  }
994
+ function consoleEventLocationUrl(input) {
995
+ if (!isRecord(input) || !isRecord(input.location)) return void 0;
996
+ return stringValue(input.location.url);
997
+ }
998
+ function expectedFailedNetworkMockEvents(evidence) {
999
+ return (evidence.network_mocks || []).filter((event) => {
1000
+ if (!isRecord(event) || event.ok === false) return false;
1001
+ const status = numberValue(event.status);
1002
+ return status !== void 0 && status >= 400 && Boolean(stringValue(event.url));
1003
+ });
1004
+ }
1005
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1006
+ const sample = allowedMessageSample(event);
1007
+ if (!/Failed to load resource/i.test(sample)) return void 0;
1008
+ const eventUrl = consoleEventLocationUrl(event);
1009
+ if (!eventUrl) return void 0;
1010
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
1011
+ const status = numberValue(mockEvent.status);
1012
+ return stringValue(mockEvent.url) === eventUrl && status !== void 0 && sample.includes(String(status));
1013
+ });
1014
+ }
1015
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1016
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
1017
+ }
1018
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
1019
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
1020
+ const sample = allowedMessageSample(event);
1021
+ return {
1022
+ url: consoleEventLocationUrl(event) ?? null,
1023
+ status: match ? numberValue(match.status) ?? null : null,
1024
+ label: match ? stringValue(match.label) ?? null : null,
1025
+ response_label: match ? stringValue(match.response_label) ?? null : null,
1026
+ text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
1027
+ };
1028
+ }
973
1029
  function normalizeRoutePath(path) {
974
1030
  const value = path || "/";
975
1031
  if (value === "/") return "/";
@@ -1387,8 +1443,10 @@ function assessCheckFromEvidence(check, evidence) {
1387
1443
  }
1388
1444
  if (check.type === "no_fatal_console_errors") {
1389
1445
  const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
1390
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1391
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1446
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
1447
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1448
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) || isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1449
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns) && !isExpectedFailedNetworkMockConsoleEvent(event, evidence));
1392
1450
  const pageErrors = evidence.page_errors || [];
1393
1451
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1394
1452
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -1403,6 +1461,9 @@ function assessCheckFromEvidence(check, evidence) {
1403
1461
  total_console_fatal_count: fatalConsoleEvents.length,
1404
1462
  total_page_error_count: pageErrors.length,
1405
1463
  allowed_console_fatal_count: allowedConsoleEvents.length,
1464
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
1465
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
1466
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
1406
1467
  allowed_page_error_count: allowedPageErrors.length,
1407
1468
  allowed_console_texts: check.allowed_console_texts || [],
1408
1469
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -1765,6 +1826,44 @@ function matchesAllowedMessage(input, texts, patterns) {
1765
1826
  }
1766
1827
  return false;
1767
1828
  }
1829
+ function consoleEventLocationUrl(input) {
1830
+ if (!input || typeof input !== "object" || Array.isArray(input)) return undefined;
1831
+ if (!input.location || typeof input.location !== "object" || Array.isArray(input.location)) return undefined;
1832
+ return typeof input.location.url === "string" && input.location.url.trim() ? input.location.url.trim() : undefined;
1833
+ }
1834
+ function expectedFailedNetworkMockEvents(evidence) {
1835
+ return ((evidence && evidence.network_mocks) || []).filter((event) => {
1836
+ if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
1837
+ const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
1838
+ const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
1839
+ return status !== undefined && status >= 400 && Boolean(url);
1840
+ });
1841
+ }
1842
+ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1843
+ const sample = allowedMessageSample(event);
1844
+ if (!/Failed to load resource/i.test(sample)) return undefined;
1845
+ const eventUrl = consoleEventLocationUrl(event);
1846
+ if (!eventUrl) return undefined;
1847
+ return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
1848
+ const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
1849
+ const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
1850
+ return mockUrl === eventUrl && status !== undefined && sample.includes(String(status));
1851
+ });
1852
+ }
1853
+ function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
1854
+ return Boolean(matchingExpectedFailedNetworkMockConsoleEvent(event, evidence));
1855
+ }
1856
+ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
1857
+ const match = matchingExpectedFailedNetworkMockConsoleEvent(event, evidence);
1858
+ const sample = allowedMessageSample(event);
1859
+ return {
1860
+ url: consoleEventLocationUrl(event) || null,
1861
+ status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
1862
+ label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
1863
+ response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
1864
+ text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
1865
+ };
1866
+ }
1768
1867
  function textSequenceForCheck(viewport, check) {
1769
1868
  const key = check.selector || "";
1770
1869
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -2488,8 +2587,19 @@ function assessProfile(profile, evidence) {
2488
2587
  }
2489
2588
  if (check.type === "no_fatal_console_errors") {
2490
2589
  const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
2491
- const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2492
- const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2590
+ const explicitlyAllowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns));
2591
+ const expectedNetworkMockConsoleEvents = fatalConsoleEvents.filter((event) => (
2592
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2593
+ && isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2594
+ ));
2595
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => (
2596
+ matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2597
+ || isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2598
+ ));
2599
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => (
2600
+ !matchesAllowedMessage(event, check.allowed_console_texts, check.allowed_console_patterns)
2601
+ && !isExpectedFailedNetworkMockConsoleEvent(event, evidence)
2602
+ ));
2493
2603
  const pageErrors = evidence.page_errors || [];
2494
2604
  const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
2495
2605
  const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error, check.allowed_page_error_texts, check.allowed_page_error_patterns));
@@ -2504,6 +2614,9 @@ function assessProfile(profile, evidence) {
2504
2614
  total_console_fatal_count: fatalConsoleEvents.length,
2505
2615
  total_page_error_count: pageErrors.length,
2506
2616
  allowed_console_fatal_count: allowedConsoleEvents.length,
2617
+ explicitly_allowed_console_fatal_count: explicitlyAllowedConsoleEvents.length,
2618
+ allowed_expected_network_mock_console_count: expectedNetworkMockConsoleEvents.length,
2619
+ allowed_expected_network_mock_console_events: expectedNetworkMockConsoleEvents.slice(0, 5).map((event) => expectedFailedNetworkMockConsoleEventSummary(event, evidence)),
2507
2620
  allowed_page_error_count: allowedPageErrors.length,
2508
2621
  allowed_console_texts: check.allowed_console_texts || [],
2509
2622
  allowed_console_patterns: check.allowed_console_patterns || [],
@@ -2563,6 +2676,9 @@ const capturedAt = new Date().toISOString();
2563
2676
  const consoleEvents = [];
2564
2677
  const pageErrors = [];
2565
2678
  const networkMockEvents = [];
2679
+ const dialogEvents = [];
2680
+ let dialogResponseConfig = null;
2681
+ let dialogHandlerInstalled = false;
2566
2682
  page.on("console", (message) => {
2567
2683
  const type = message.type();
2568
2684
  if (type === "error" || type === "warning" || type === "assert") {
@@ -2576,6 +2692,50 @@ page.on("console", (message) => {
2576
2692
  page.on("pageerror", (error) => {
2577
2693
  pageErrors.push({ message: String(error && error.message ? error.message : error).slice(0, 1000) });
2578
2694
  });
2695
+ function setupDialogMessageMatches(message, config) {
2696
+ if (!config) return true;
2697
+ if (config.message_pattern) {
2698
+ try { return new RegExp(config.message_pattern, config.flags || "").test(message || ""); } catch { return false; }
2699
+ }
2700
+ if (config.message_text) return String(message || "").includes(config.message_text);
2701
+ return true;
2702
+ }
2703
+ function ensureDialogHandler() {
2704
+ if (dialogHandlerInstalled) return;
2705
+ dialogHandlerInstalled = true;
2706
+ page.on("dialog", async (dialog) => {
2707
+ const config = dialogResponseConfig || { accept: false };
2708
+ const message = typeof dialog.message === "function" ? dialog.message() : "";
2709
+ const type = typeof dialog.type === "function" ? dialog.type() : "dialog";
2710
+ const defaultValue = typeof dialog.defaultValue === "function" ? dialog.defaultValue() : "";
2711
+ const accept = config.accept !== false;
2712
+ const event = {
2713
+ type,
2714
+ message: String(message || "").slice(0, 1000),
2715
+ default_value: String(defaultValue || "").slice(0, 500),
2716
+ configured: Boolean(dialogResponseConfig),
2717
+ response: accept ? "accept" : "dismiss",
2718
+ message_matches: setupDialogMessageMatches(message, config),
2719
+ expected_message_text: config.message_text || undefined,
2720
+ expected_message_pattern: config.message_pattern || undefined,
2721
+ };
2722
+ try {
2723
+ if (accept) {
2724
+ const promptText = config.prompt_text === undefined ? undefined : String(config.prompt_text);
2725
+ await dialog.accept(promptText);
2726
+ } else {
2727
+ await dialog.dismiss();
2728
+ }
2729
+ dialogEvents.push({ ...event, ok: true });
2730
+ } catch (error) {
2731
+ dialogEvents.push({
2732
+ ...event,
2733
+ ok: false,
2734
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
2735
+ });
2736
+ }
2737
+ });
2738
+ }
2579
2739
  function textKey(check) {
2580
2740
  return check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
2581
2741
  }
@@ -2914,6 +3074,24 @@ async function executeSetupAction(action, ordinal, viewport) {
2914
3074
  pageErrors.length = 0;
2915
3075
  return { ...base, ok: true, cleared_console_event_count, cleared_page_error_count };
2916
3076
  }
3077
+ if (type === "dialog_response") {
3078
+ ensureDialogHandler();
3079
+ dialogResponseConfig = {
3080
+ accept: action.accept !== false,
3081
+ prompt_text: action.prompt_text,
3082
+ message_text: action.message_text,
3083
+ message_pattern: action.message_pattern,
3084
+ flags: action.flags || "",
3085
+ };
3086
+ return {
3087
+ ...base,
3088
+ ok: true,
3089
+ response: dialogResponseConfig.accept ? "accept" : "dismiss",
3090
+ message_text: dialogResponseConfig.message_text || undefined,
3091
+ message_pattern: dialogResponseConfig.message_pattern || undefined,
3092
+ prompt_text_length: dialogResponseConfig.prompt_text === undefined ? undefined : String(dialogResponseConfig.prompt_text).length,
3093
+ };
3094
+ }
2917
3095
  if (type === "wait_for_selector") {
2918
3096
  const scope = await setupActionScope(action, timeout);
2919
3097
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -4014,6 +4192,7 @@ function buildProfileEvidence(currentViewports) {
4014
4192
  fatal_count: consoleEvents.filter((event) => event.type === "error" || event.type === "assert").length,
4015
4193
  },
4016
4194
  page_errors: pageErrors,
4195
+ dialogs: dialogEvents.slice(),
4017
4196
  network_mocks: networkMockEvents.slice(),
4018
4197
  dom_summary: {
4019
4198
  expected_viewport_count: expectedViewportCount,
@@ -4053,6 +4232,9 @@ function buildProfileEvidence(currentViewports) {
4053
4232
  })),
4054
4233
  network_mock_count: (profile.target.network_mocks || []).length,
4055
4234
  network_mock_hit_count: networkMockEvents.filter((event) => event.ok !== false).length,
4235
+ dialog_count: dialogEvents.length,
4236
+ dialog_accept_count: dialogEvents.filter((event) => event.response === "accept" && event.ok !== false).length,
4237
+ dialog_dismiss_count: dialogEvents.filter((event) => event.response === "dismiss" && event.ok !== false).length,
4056
4238
  },
4057
4239
  };
4058
4240
  }
@@ -4061,7 +4243,7 @@ async function saveProfileArtifacts(currentViewports) {
4061
4243
  const result = assessProfile(profile, evidence);
4062
4244
  if (typeof saveJson === "function") {
4063
4245
  await saveJson("proof.json", result);
4064
- await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors });
4246
+ await saveJson("console.json", { events: consoleEvents, page_errors: pageErrors, dialogs: dialogEvents });
4065
4247
  await saveJson("dom-summary.json", evidence.dom_summary);
4066
4248
  }
4067
4249
  return result;
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
@@ -44,6 +44,10 @@ interface RiddleProofProfileSetupAction {
44
44
  text?: string;
45
45
  pattern?: string;
46
46
  flags?: string;
47
+ accept?: boolean;
48
+ prompt_text?: string;
49
+ message_text?: string;
50
+ message_pattern?: string;
47
51
  index?: number;
48
52
  expected_count?: number;
49
53
  ms?: number;