@riddledc/riddle-proof 0.7.58 → 0.7.60

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
@@ -8736,6 +8736,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8736
8736
  "selector_count_eq",
8737
8737
  "selector_text_order",
8738
8738
  "frame_text_visible",
8739
+ "frame_url_equals",
8740
+ "frame_url_matches",
8739
8741
  "frame_no_horizontal_overflow",
8740
8742
  "text_visible",
8741
8743
  "text_absent",
@@ -8950,6 +8952,11 @@ function normalizeSetupAction(input, index) {
8950
8952
  if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
8951
8953
  const type = normalizeSetupActionType(stringValue5(input.type), index);
8952
8954
  const selector = stringValue5(input.selector);
8955
+ const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
8956
+ const frameIndex = numberValue3(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
8957
+ if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
8958
+ throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
8959
+ }
8953
8960
  if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
8954
8961
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
8955
8962
  }
@@ -9002,6 +9009,8 @@ function normalizeSetupAction(input, index) {
9002
9009
  return {
9003
9010
  type,
9004
9011
  selector,
9012
+ frame_selector: frameSelector,
9013
+ frame_index: frameIndex,
9005
9014
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
9006
9015
  key,
9007
9016
  value,
@@ -9213,12 +9222,19 @@ function normalizeCheck(input, index) {
9213
9222
  if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue5(input.selector)) {
9214
9223
  throw new Error(`checks[${index}] ${type} requires selector.`);
9215
9224
  }
9216
- if ((type === "frame_text_visible" || type === "frame_no_horizontal_overflow") && !stringValue5(input.selector)) {
9225
+ if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue5(input.selector)) {
9217
9226
  throw new Error(`checks[${index}] ${type} requires selector.`);
9218
9227
  }
9219
9228
  if (type === "frame_text_visible" && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9220
9229
  throw new Error(`checks[${index}] frame_text_visible requires text or pattern.`);
9221
9230
  }
9231
+ const expectedUrl = stringFromOwn(input, "expected_url", "expectedUrl", "url", "expected_value", "expectedValue", "value");
9232
+ if (type === "frame_url_equals" && expectedUrl === void 0) {
9233
+ throw new Error(`checks[${index}] frame_url_equals requires expected_url.`);
9234
+ }
9235
+ if (type === "frame_url_matches" && !stringValue5(input.pattern)) {
9236
+ throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
9237
+ }
9222
9238
  if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9223
9239
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
9224
9240
  }
@@ -9251,6 +9267,7 @@ function normalizeCheck(input, index) {
9251
9267
  expected_path: stringValue5(input.expected_path),
9252
9268
  param: stringValue5(input.param) || stringValue5(input.search_param) || stringValue5(input.searchParam) || stringValue5(input.key),
9253
9269
  expected_value: expectedValue,
9270
+ expected_url: expectedUrl,
9254
9271
  expected_routes: expectedRoutes,
9255
9272
  selector: stringValue5(input.selector),
9256
9273
  expected_texts: expectedTexts,
@@ -9718,6 +9735,35 @@ function assessCheckFromEvidence(check, evidence) {
9718
9735
  message: failed ? `Frame selector ${key} did not contain expected text in ${failed} viewport(s).` : void 0
9719
9736
  };
9720
9737
  }
9738
+ if (check.type === "frame_url_equals" || check.type === "frame_url_matches") {
9739
+ const key = selectorKey(check);
9740
+ const expectedUrl = check.expected_url || check.expected_value || "";
9741
+ const results = viewports.map((viewport) => {
9742
+ const frames = frameEvidenceForSelector(viewport, key);
9743
+ const urls = frames.map((frame) => String(frame.url || "")).filter(Boolean);
9744
+ const matches = urls.filter((url) => check.type === "frame_url_equals" ? url === expectedUrl : matchText(url, check));
9745
+ return {
9746
+ viewport: viewport.name,
9747
+ frame_count: frames.length,
9748
+ matched_count: matches.length,
9749
+ matched: matches.length > 0,
9750
+ urls: urls.slice(0, 10)
9751
+ };
9752
+ });
9753
+ const failed = results.filter((result) => !result.matched).length;
9754
+ return {
9755
+ type: check.type,
9756
+ label: checkLabel(check),
9757
+ status: failed ? "failed" : "passed",
9758
+ evidence: {
9759
+ selector: key,
9760
+ expected_url: check.type === "frame_url_equals" ? expectedUrl : null,
9761
+ pattern: check.type === "frame_url_matches" ? check.pattern || null : null,
9762
+ viewports: results.map((result) => toJsonValue(result))
9763
+ },
9764
+ message: failed ? `Frame selector ${key} URL assertion failed in ${failed} viewport(s).` : void 0
9765
+ };
9766
+ }
9721
9767
  if (check.type === "frame_no_horizontal_overflow") {
9722
9768
  const key = selectorKey(check);
9723
9769
  const maxOverflow = check.max_overflow_px ?? 4;
@@ -9888,6 +9934,8 @@ function assessSetupActionsFromEvidence(profile, evidence) {
9888
9934
  viewport: viewport.name,
9889
9935
  action: result.action ?? result.type ?? null,
9890
9936
  selector: result.selector ?? null,
9937
+ frame_selector: result.frame_selector ?? null,
9938
+ frame_index: result.frame_index ?? null,
9891
9939
  reason: result.reason ?? result.error ?? null
9892
9940
  });
9893
9941
  }
@@ -10400,10 +10448,12 @@ function assessProfile(profile, evidence) {
10400
10448
  if (result && result.ok === false) {
10401
10449
  failed.push({
10402
10450
  viewport: viewport.name,
10403
- action: result.action || result.type || null,
10404
- selector: result.selector || null,
10405
- reason: result.reason || result.error || null,
10406
- });
10451
+ action: result.action || result.type || null,
10452
+ selector: result.selector || null,
10453
+ frame_selector: result.frame_selector || null,
10454
+ frame_index: result.frame_index ?? null,
10455
+ reason: result.reason || result.error || null,
10456
+ });
10407
10457
  }
10408
10458
  }
10409
10459
  if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
@@ -10605,6 +10655,36 @@ function assessProfile(profile, evidence) {
10605
10655
  });
10606
10656
  continue;
10607
10657
  }
10658
+ if (check.type === "frame_url_equals" || check.type === "frame_url_matches") {
10659
+ const selector = check.selector || "";
10660
+ const expectedUrl = check.expected_url || check.expected_value || "";
10661
+ const results = checkViewports.map((viewport) => {
10662
+ const frames = frameEvidenceForSelector(viewport, selector);
10663
+ const urls = frames.map((frame) => String(frame.url || "")).filter(Boolean);
10664
+ const matches = urls.filter((url) => check.type === "frame_url_equals" ? url === expectedUrl : textMatches(url, check));
10665
+ return {
10666
+ viewport: viewport.name,
10667
+ frame_count: frames.length,
10668
+ matched_count: matches.length,
10669
+ matched: matches.length > 0,
10670
+ urls: urls.slice(0, 10),
10671
+ };
10672
+ });
10673
+ const failed = results.filter((result) => !result.matched).length;
10674
+ checks.push({
10675
+ type: check.type,
10676
+ label: check.label || check.type,
10677
+ status: failed ? "failed" : "passed",
10678
+ evidence: {
10679
+ selector,
10680
+ expected_url: check.type === "frame_url_equals" ? expectedUrl : null,
10681
+ pattern: check.type === "frame_url_matches" ? check.pattern || null : null,
10682
+ viewports: results,
10683
+ },
10684
+ message: failed ? "Frame selector " + selector + " URL assertion failed in " + failed + " viewport(s)." : undefined,
10685
+ });
10686
+ continue;
10687
+ }
10608
10688
  if (check.type === "frame_no_horizontal_overflow") {
10609
10689
  const selector = check.selector || "";
10610
10690
  const maxOverflow = check.max_overflow_px == null ? 4 : check.max_overflow_px;
@@ -10866,8 +10946,8 @@ function setupJsonValue(value) {
10866
10946
  function setupValuesEqual(left, right) {
10867
10947
  return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
10868
10948
  }
10869
- async function setupReadWindowValue(path) {
10870
- return await page.evaluate(({ path }) => {
10949
+ async function setupReadWindowValue(context, path) {
10950
+ return await context.evaluate(({ path }) => {
10871
10951
  const toJsonValue = (value) => {
10872
10952
  if (value === null || value === undefined) return null;
10873
10953
  if (typeof value === "string" || typeof value === "boolean") return value;
@@ -10889,6 +10969,80 @@ async function setupReadWindowValue(path) {
10889
10969
  return { ok: true, value: toJsonValue(current) };
10890
10970
  }, { path });
10891
10971
  }
10972
+ function setupFrameSelector(action) {
10973
+ return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
10974
+ }
10975
+ function setupFrameIndex(action) {
10976
+ const raw = action?.frame_index ?? action?.frameIndex ?? action?.iframe_index ?? action?.iframeIndex ?? 0;
10977
+ const number = Number(raw);
10978
+ return Number.isInteger(number) && number >= 0 ? number : 0;
10979
+ }
10980
+ function setupScopeEvidence(scope) {
10981
+ if (!scope || !scope.frame_selector) return {};
10982
+ return {
10983
+ frame_selector: scope.frame_selector,
10984
+ frame_index: scope.frame_index,
10985
+ frame_count: scope.frame_count,
10986
+ };
10987
+ }
10988
+ function setupScopeFailure(base, scope) {
10989
+ return {
10990
+ ...base,
10991
+ ...setupScopeEvidence(scope),
10992
+ reason: scope?.reason || "frame_scope_unavailable",
10993
+ error: scope?.error || undefined,
10994
+ };
10995
+ }
10996
+ async function setupActionScope(action, timeout) {
10997
+ const frameSelector = setupFrameSelector(action);
10998
+ if (!frameSelector) return { ok: true, context: page };
10999
+ const frameIndex = setupFrameIndex(action);
11000
+ let frameCount = 0;
11001
+ let locator = null;
11002
+ try {
11003
+ await page.waitForSelector(frameSelector, { state: "attached", timeout });
11004
+ locator = page.locator(frameSelector);
11005
+ frameCount = await locator.count();
11006
+ } catch (error) {
11007
+ return {
11008
+ ok: false,
11009
+ reason: "frame_selector_not_found",
11010
+ frame_selector: frameSelector,
11011
+ frame_index: frameIndex,
11012
+ frame_count: frameCount,
11013
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
11014
+ };
11015
+ }
11016
+ if (!frameCount) {
11017
+ return { ok: false, reason: "frame_selector_not_found", frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
11018
+ }
11019
+ if (frameIndex >= frameCount) {
11020
+ return { ok: false, reason: "frame_index_out_of_range", frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
11021
+ }
11022
+ const handle = await locator.nth(frameIndex).elementHandle({ timeout }).catch((error) => ({ __riddle_error: error }));
11023
+ if (!handle || handle.__riddle_error) {
11024
+ return {
11025
+ ok: false,
11026
+ reason: "frame_element_unavailable",
11027
+ frame_selector: frameSelector,
11028
+ frame_index: frameIndex,
11029
+ frame_count: frameCount,
11030
+ error: handle?.__riddle_error ? String(handle.__riddle_error && handle.__riddle_error.message ? handle.__riddle_error.message : handle.__riddle_error).slice(0, 1000) : undefined,
11031
+ };
11032
+ }
11033
+ const frame = typeof handle.contentFrame === "function" ? await handle.contentFrame().catch((error) => ({ __riddle_error: error })) : null;
11034
+ if (!frame || frame.__riddle_error) {
11035
+ return {
11036
+ ok: false,
11037
+ reason: "content_frame_unavailable",
11038
+ frame_selector: frameSelector,
11039
+ frame_index: frameIndex,
11040
+ frame_count: frameCount,
11041
+ error: frame?.__riddle_error ? String(frame.__riddle_error && frame.__riddle_error.message ? frame.__riddle_error.message : frame.__riddle_error).slice(0, 1000) : undefined,
11042
+ };
11043
+ }
11044
+ return { ok: true, context: frame, frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
11045
+ }
10892
11046
  async function setupLocatorText(locator, index) {
10893
11047
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
10894
11048
  }
@@ -11050,7 +11204,8 @@ async function registerNetworkMocks(mocks) {
11050
11204
  }
11051
11205
  async function executeSetupAction(action, ordinal) {
11052
11206
  const type = setupActionType(action);
11053
- const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
11207
+ const frameSelector = setupFrameSelector(action);
11208
+ const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null, frame_selector: frameSelector || null };
11054
11209
  const timeout = setupNumber(action.timeout_ms, 5000);
11055
11210
  try {
11056
11211
  if (type === "wait") {
@@ -11059,51 +11214,65 @@ async function executeSetupAction(action, ordinal) {
11059
11214
  return { ...base, ok: true, ms };
11060
11215
  }
11061
11216
  if (type === "wait_for_selector") {
11062
- await page.waitForSelector(action.selector, { state: "visible", timeout });
11063
- return { ...base, ok: true, timeout_ms: timeout };
11217
+ const scope = await setupActionScope(action, timeout);
11218
+ if (!scope.ok) return setupScopeFailure(base, scope);
11219
+ await scope.context.waitForSelector(action.selector, { state: "visible", timeout });
11220
+ return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
11064
11221
  }
11065
11222
  if (type === "press") {
11066
11223
  const key = String(action.key || "").trim();
11067
11224
  if (!key) return { ...base, reason: "missing_key" };
11225
+ const scope = await setupActionScope(action, timeout);
11226
+ if (!scope.ok) return setupScopeFailure(base, scope);
11068
11227
  if (!action.selector) {
11069
- await page.keyboard.press(key);
11070
- return { ...base, ok: true, key };
11228
+ if (scope.frame_selector) {
11229
+ await scope.context.locator("body").press(key, { timeout });
11230
+ } else {
11231
+ await page.keyboard.press(key);
11232
+ }
11233
+ return { ...base, ...setupScopeEvidence(scope), ok: true, key };
11071
11234
  }
11072
- const locator = page.locator(action.selector);
11235
+ const locator = scope.context.locator(action.selector);
11073
11236
  const count = await locator.count();
11074
11237
  if (!count) return { ...base, reason: "selector_not_found", count, key };
11075
11238
  const targetIndex = Number.isInteger(action.index) ? action.index : 0;
11076
11239
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex, key };
11077
11240
  await locator.nth(targetIndex).press(key, { timeout });
11078
- return { ...base, ok: true, count, target_index: targetIndex, key };
11241
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, key };
11079
11242
  }
11080
11243
  if (type === "local_storage" || type === "session_storage") {
11081
11244
  const value = setupActionValue(action);
11082
- await page.evaluate(({ type, key, value }) => {
11245
+ const scope = await setupActionScope(action, timeout);
11246
+ if (!scope.ok) return setupScopeFailure(base, scope);
11247
+ await scope.context.evaluate(({ type, key, value }) => {
11083
11248
  const storage = type === "session_storage" ? window.sessionStorage : window.localStorage;
11084
11249
  storage.setItem(key, value);
11085
11250
  }, { type, key: action.key, value });
11086
11251
  if (action.reload === true) {
11087
11252
  await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
11088
11253
  }
11089
- return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
11254
+ return { ...base, ...setupScopeEvidence(scope), ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
11090
11255
  }
11091
11256
  if (type === "clear_storage") {
11092
11257
  const storage = action.storage || "both";
11093
- await page.evaluate(({ storage }) => {
11258
+ const scope = await setupActionScope(action, timeout);
11259
+ if (!scope.ok) return setupScopeFailure(base, scope);
11260
+ await scope.context.evaluate(({ storage }) => {
11094
11261
  if (storage === "local" || storage === "both") window.localStorage.clear();
11095
11262
  if (storage === "session" || storage === "both") window.sessionStorage.clear();
11096
11263
  }, { storage });
11097
11264
  if (action.reload === true) {
11098
11265
  await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
11099
11266
  }
11100
- return { ...base, ok: true, storage, reload: action.reload === true };
11267
+ return { ...base, ...setupScopeEvidence(scope), ok: true, storage, reload: action.reload === true };
11101
11268
  }
11102
11269
  if (type === "window_call") {
11103
11270
  const path = String(action.path || action.function_path || action.functionPath || "");
11104
11271
  const args = Array.isArray(action.args) ? action.args : [];
11105
11272
  if (!path) return { ...base, path, reason: "missing_path" };
11106
- const result = await page.evaluate(async ({ path, args }) => {
11273
+ const scope = await setupActionScope(action, timeout);
11274
+ if (!scope.ok) return setupScopeFailure(base, scope);
11275
+ const result = await scope.context.evaluate(async ({ path, args }) => {
11107
11276
  const toJsonValue = (value) => {
11108
11277
  if (value === null || value === undefined) return null;
11109
11278
  if (typeof value === "string" || typeof value === "boolean") return value;
@@ -11143,6 +11312,7 @@ async function executeSetupAction(action, ordinal) {
11143
11312
  const expectationMet = !hasExpectation || setupValuesEqual(result.returned, expected);
11144
11313
  return {
11145
11314
  ...base,
11315
+ ...setupScopeEvidence(scope),
11146
11316
  ok: Boolean(result.ok && expectationMet),
11147
11317
  path,
11148
11318
  arg_count: args.length,
@@ -11173,13 +11343,16 @@ async function executeSetupAction(action, ordinal) {
11173
11343
  : action.expect;
11174
11344
  if (!path) return { ...base, path, reason: "missing_path" };
11175
11345
  if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
11346
+ const scope = await setupActionScope(action, timeout);
11347
+ if (!scope.ok) return setupScopeFailure(base, scope);
11176
11348
  const startedAt = Date.now();
11177
11349
  let result = null;
11178
11350
  while (Date.now() - startedAt <= timeout) {
11179
- result = await setupReadWindowValue(path);
11351
+ result = await setupReadWindowValue(scope.context, path);
11180
11352
  if (result.ok && setupValuesEqual(result.value, expected)) {
11181
11353
  return {
11182
11354
  ...base,
11355
+ ...setupScopeEvidence(scope),
11183
11356
  ok: true,
11184
11357
  path,
11185
11358
  value: setupJsonValue(result.value),
@@ -11191,6 +11364,7 @@ async function executeSetupAction(action, ordinal) {
11191
11364
  }
11192
11365
  return {
11193
11366
  ...base,
11367
+ ...setupScopeEvidence(scope),
11194
11368
  path,
11195
11369
  reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
11196
11370
  missing_part: result?.missing_part || undefined,
@@ -11207,11 +11381,13 @@ async function executeSetupAction(action, ordinal) {
11207
11381
  const hasExpected = expected !== undefined;
11208
11382
  if (!path) return { ...base, path, reason: "missing_path" };
11209
11383
  if (!hasExpected && minValue === undefined && maxValue === undefined) return { ...base, path, reason: "missing_number_expectation" };
11384
+ const scope = await setupActionScope(action, timeout);
11385
+ if (!scope.ok) return setupScopeFailure(base, scope);
11210
11386
  const startedAt = Date.now();
11211
11387
  let result = null;
11212
11388
  let lastReason = "path_not_found";
11213
11389
  while (Date.now() - startedAt <= timeout) {
11214
- result = await setupReadWindowValue(path);
11390
+ result = await setupReadWindowValue(scope.context, path);
11215
11391
  if (result.ok) {
11216
11392
  const actual = setupFiniteNumber(result.value);
11217
11393
  if (actual === undefined) {
@@ -11225,6 +11401,7 @@ async function executeSetupAction(action, ordinal) {
11225
11401
  } else {
11226
11402
  return {
11227
11403
  ...base,
11404
+ ...setupScopeEvidence(scope),
11228
11405
  ok: true,
11229
11406
  path,
11230
11407
  value: actual,
@@ -11241,6 +11418,7 @@ async function executeSetupAction(action, ordinal) {
11241
11418
  }
11242
11419
  return {
11243
11420
  ...base,
11421
+ ...setupScopeEvidence(scope),
11244
11422
  path,
11245
11423
  reason: lastReason,
11246
11424
  missing_part: result?.missing_part || undefined,
@@ -11252,7 +11430,9 @@ async function executeSetupAction(action, ordinal) {
11252
11430
  };
11253
11431
  }
11254
11432
  if (type === "click") {
11255
- const locator = page.locator(action.selector);
11433
+ const scope = await setupActionScope(action, timeout);
11434
+ if (!scope.ok) return setupScopeFailure(base, scope);
11435
+ const locator = scope.context.locator(action.selector);
11256
11436
  const count = await locator.count();
11257
11437
  if (!count) return { ...base, reason: "selector_not_found", count };
11258
11438
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
@@ -11284,33 +11464,39 @@ async function executeSetupAction(action, ordinal) {
11284
11464
  ? { timeout, noWaitAfter: true, force: true }
11285
11465
  : { timeout, noWaitAfter: true };
11286
11466
  await locator.nth(targetIndex).click(clickOptions);
11287
- return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
11467
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
11288
11468
  }
11289
11469
  if (type === "fill" || type === "set_input_value") {
11290
- const locator = page.locator(action.selector);
11470
+ const scope = await setupActionScope(action, timeout);
11471
+ if (!scope.ok) return setupScopeFailure(base, scope);
11472
+ const locator = scope.context.locator(action.selector);
11291
11473
  const count = await locator.count();
11292
11474
  if (!count) return { ...base, reason: "selector_not_found", count };
11293
11475
  const targetIndex = Number.isInteger(action.index) ? action.index : 0;
11294
11476
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
11295
11477
  const value = setupActionValue(action);
11296
11478
  await locator.nth(targetIndex).fill(value, { timeout });
11297
- return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
11479
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, value_length: value.length };
11298
11480
  }
11299
11481
  if (type === "assert_selector_count") {
11300
- const locator = page.locator(action.selector);
11482
+ const scope = await setupActionScope(action, timeout);
11483
+ if (!scope.ok) return setupScopeFailure(base, scope);
11484
+ const locator = scope.context.locator(action.selector);
11301
11485
  const expectedCount = setupNumber(action.expected_count, -1);
11302
11486
  if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
11303
11487
  const startedAt = Date.now();
11304
11488
  let count = 0;
11305
11489
  while (Date.now() - startedAt <= timeout) {
11306
11490
  count = await locator.count().catch(() => 0);
11307
- if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
11491
+ if (count === expectedCount) return { ...base, ...setupScopeEvidence(scope), ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
11308
11492
  await page.waitForTimeout(100);
11309
11493
  }
11310
- return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
11494
+ return { ...base, ...setupScopeEvidence(scope), reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
11311
11495
  }
11312
11496
  if (type === "wait_for_text") {
11313
- const locator = page.locator(action.selector);
11497
+ const scope = await setupActionScope(action, timeout);
11498
+ if (!scope.ok) return setupScopeFailure(base, scope);
11499
+ const locator = scope.context.locator(action.selector);
11314
11500
  const startedAt = Date.now();
11315
11501
  let lastText = "";
11316
11502
  while (Date.now() - startedAt <= timeout) {
@@ -11319,15 +11505,17 @@ async function executeSetupAction(action, ordinal) {
11319
11505
  const text = await setupLocatorText(locator, index);
11320
11506
  lastText = text || lastText;
11321
11507
  if (setupTextMatches(text, action)) {
11322
- return { ...base, ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
11508
+ return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
11323
11509
  }
11324
11510
  }
11325
11511
  await page.waitForTimeout(100);
11326
11512
  }
11327
- return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
11513
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
11328
11514
  }
11329
11515
  if (type === "assert_text_visible" || type === "assert_text_absent") {
11330
- const locator = page.locator(action.selector);
11516
+ const scope = await setupActionScope(action, timeout);
11517
+ if (!scope.ok) return setupScopeFailure(base, scope);
11518
+ const locator = scope.context.locator(action.selector);
11331
11519
  const startedAt = Date.now();
11332
11520
  let lastText = "";
11333
11521
  let matchedText = "";
@@ -11346,7 +11534,7 @@ async function executeSetupAction(action, ordinal) {
11346
11534
  if (type === "assert_text_visible") {
11347
11535
  const visible = await setupLocatorVisible(locator, index);
11348
11536
  if (visible) {
11349
- return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
11537
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
11350
11538
  }
11351
11539
  hiddenMatch = true;
11352
11540
  break;
@@ -11355,17 +11543,17 @@ async function executeSetupAction(action, ordinal) {
11355
11543
  }
11356
11544
  }
11357
11545
  if (type === "assert_text_absent" && !matched) {
11358
- return { ...base, ok: true, count, timeout_ms: timeout };
11546
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
11359
11547
  }
11360
11548
  await page.waitForTimeout(100);
11361
11549
  }
11362
11550
  if (type === "assert_text_visible") {
11363
11551
  if (hiddenMatch) {
11364
- return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
11552
+ return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
11365
11553
  }
11366
- return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
11554
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
11367
11555
  }
11368
- return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
11556
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
11369
11557
  }
11370
11558
  return { ...base, reason: "unsupported_action" };
11371
11559
  } catch (error) {
@@ -11968,7 +12156,7 @@ async function captureViewport(viewport) {
11968
12156
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
11969
12157
  text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
11970
12158
  }
11971
- if ((check.type === "frame_text_visible" || check.type === "frame_no_horizontal_overflow") && check.selector) {
12159
+ if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
11972
12160
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
11973
12161
  frames[check.selector] = frames[check.selector] || await frameEvidence(check.selector);
11974
12162
  }
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-7ZBK2GQX.js";
61
+ } from "./chunk-FLQ4HHTT.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,