@riddledc/riddle-proof 0.7.130 → 0.7.131

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.
@@ -1900,6 +1900,27 @@ function textMatchSamples(sample, check) {
1900
1900
  const sampleText = textSampleAroundMatch(source, index, text.length);
1901
1901
  return sampleText ? [sampleText] : [];
1902
1902
  }
1903
+ function textCaseInsensitiveSamples(sample, check) {
1904
+ const source = String(sample || "");
1905
+ const text = check.pattern ? "" : check.text || "";
1906
+ if (!source || !text) return [];
1907
+ const index = source.toLowerCase().indexOf(text.toLowerCase());
1908
+ const sampleText = textSampleAroundMatch(source, index, text.length);
1909
+ return sampleText ? [sampleText] : [];
1910
+ }
1911
+ function textCaseInsensitiveSequenceSamples(texts, check) {
1912
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
1913
+ if (!text) return [];
1914
+ const expected = text.toLowerCase();
1915
+ return texts.map((candidate) => compactTextEvidenceSample(candidate)).filter((candidate) => candidate && candidate.toLowerCase().includes(expected)).slice(0, 3).map((candidate) => candidate.slice(0, 240));
1916
+ }
1917
+ function textCaseInsensitiveFailureSamples(viewport, check) {
1918
+ const key = textKey(check);
1919
+ const captured = viewport.text_case_insensitive_samples?.[key] || [];
1920
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
1921
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
1922
+ return textCaseInsensitiveSamples(viewport.body_text_sample || "", check).slice(0, 3);
1923
+ }
1903
1924
  function textCheckFailureSamples(viewport, check) {
1904
1925
  const key = textKey(check);
1905
1926
  const captured = viewport.text_match_samples?.[key] || [];
@@ -2212,13 +2233,15 @@ function assessCheckFromEvidence(check, evidence) {
2212
2233
  const matched = matches.length > 0;
2213
2234
  const failedAgainstExpectation = matched !== expectedVisible;
2214
2235
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
2236
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveSequenceSamples(texts, check) : [];
2215
2237
  return {
2216
2238
  viewport: viewport.name,
2217
2239
  selector_count: viewport.selectors?.[key]?.count || 0,
2218
2240
  visible_count: viewport.selectors?.[key]?.visible_count || 0,
2219
2241
  matched_count: matches.length,
2220
2242
  matched,
2221
- samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240))
2243
+ samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
2244
+ case_insensitive_samples: caseInsensitiveSamples
2222
2245
  };
2223
2246
  });
2224
2247
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -2361,7 +2384,8 @@ function assessCheckFromEvidence(check, evidence) {
2361
2384
  return {
2362
2385
  viewport: viewport.name,
2363
2386
  matched,
2364
- samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
2387
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
2388
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveFailureSamples(viewport, check) : []
2365
2389
  };
2366
2390
  });
2367
2391
  const matches = results.map((result) => result.matched);
@@ -2991,6 +3015,32 @@ function textMatchSamples(sample, check) {
2991
3015
  const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
2992
3016
  return sampleText ? [sampleText] : [];
2993
3017
  }
3018
+ function textCaseInsensitiveSamples(sample, check) {
3019
+ const source = String(sample || "");
3020
+ const text = check.pattern ? "" : check.text || "";
3021
+ if (!source || !text) return [];
3022
+ const sampleText = textSampleAroundMatch(source, source.toLowerCase().indexOf(text.toLowerCase()), text.length);
3023
+ return sampleText ? [sampleText] : [];
3024
+ }
3025
+ function textCaseInsensitiveSequenceSamples(texts, check) {
3026
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
3027
+ if (!text) return [];
3028
+ const expected = text.toLowerCase();
3029
+ return (texts || [])
3030
+ .map((candidate) => compactTextEvidenceSample(candidate))
3031
+ .filter((candidate) => candidate && candidate.toLowerCase().includes(expected))
3032
+ .slice(0, 3)
3033
+ .map((candidate) => candidate.slice(0, 240));
3034
+ }
3035
+ function textCaseInsensitiveFailureSamples(viewport, check) {
3036
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
3037
+ const captured = viewport && viewport.text_case_insensitive_samples && Array.isArray(viewport.text_case_insensitive_samples[key]) ? viewport.text_case_insensitive_samples[key] : [];
3038
+ const capturedSamples = captured
3039
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
3040
+ .filter(Boolean);
3041
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
3042
+ return textCaseInsensitiveSamples(viewport && viewport.body_text_sample || "", check).slice(0, 3);
3043
+ }
2994
3044
  function textCheckFailureSamples(viewport, check) {
2995
3045
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
2996
3046
  const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
@@ -3949,6 +3999,9 @@ function assessProfile(profile, evidence) {
3949
3999
  const matched = matches.length > 0;
3950
4000
  const failedAgainstExpectation = matched !== expectedVisible;
3951
4001
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
4002
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched
4003
+ ? textCaseInsensitiveSequenceSamples(texts, check)
4004
+ : [];
3952
4005
  return {
3953
4006
  viewport: viewport.name,
3954
4007
  selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
@@ -3956,6 +4009,7 @@ function assessProfile(profile, evidence) {
3956
4009
  matched_count: matches.length,
3957
4010
  matched,
3958
4011
  samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
4012
+ case_insensitive_samples: caseInsensitiveSamples,
3959
4013
  };
3960
4014
  });
3961
4015
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -4087,6 +4141,9 @@ function assessProfile(profile, evidence) {
4087
4141
  viewport: viewport.name,
4088
4142
  matched,
4089
4143
  samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
4144
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched
4145
+ ? textCaseInsensitiveFailureSamples(viewport, check)
4146
+ : [],
4090
4147
  };
4091
4148
  });
4092
4149
  const matches = results.map((result) => result.matched);
@@ -4476,6 +4533,14 @@ function setupTextMatches(sample, action) {
4476
4533
  return rawSample.includes(expected)
4477
4534
  || normalizeSetupMatchText(rawSample).includes(normalizeSetupMatchText(expected));
4478
4535
  }
4536
+ function setupCaseInsensitiveTextSample(sample, action) {
4537
+ if (!action || action.pattern || !action.text) return "";
4538
+ const normalizedSample = normalizeSetupMatchText(sample);
4539
+ const normalizedExpected = normalizeSetupMatchText(action.text);
4540
+ if (!normalizedSample || !normalizedExpected) return "";
4541
+ if (!normalizedSample.toLowerCase().includes(normalizedExpected.toLowerCase())) return "";
4542
+ return compactSetupResultText(normalizedSample);
4543
+ }
4479
4544
  async function waitForAnyVisibleSelector(context, selector, timeout) {
4480
4545
  const deadline = Date.now() + setupNumber(timeout, 15000);
4481
4546
  let lastReason = "selector_not_found";
@@ -5226,6 +5291,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5226
5291
  if (!count) return { ...base, reason: "selector_not_found", count };
5227
5292
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
5228
5293
  let matchedText = null;
5294
+ let caseInsensitiveText = null;
5229
5295
  let hiddenMatchIndex = -1;
5230
5296
  let hiddenMatchedText = null;
5231
5297
  if (action.text || action.pattern) {
@@ -5243,10 +5309,12 @@ async function executeSetupAction(action, ordinal, viewport) {
5243
5309
  hiddenMatchIndex = index;
5244
5310
  hiddenMatchedText = compactSetupResultText(text);
5245
5311
  }
5312
+ } else if (!caseInsensitiveText) {
5313
+ caseInsensitiveText = setupCaseInsensitiveTextSample(text, action) || null;
5246
5314
  }
5247
5315
  }
5248
5316
  if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
5249
- if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
5317
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count, case_insensitive_text: caseInsensitiveText || undefined };
5250
5318
  }
5251
5319
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
5252
5320
  const clickOptions = action.force === true
@@ -5290,6 +5358,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5290
5358
  const locator = scope.context.locator(action.selector);
5291
5359
  const startedAt = Date.now();
5292
5360
  let lastText = "";
5361
+ let caseInsensitiveText = "";
5293
5362
  while (Date.now() - startedAt <= timeout) {
5294
5363
  const count = await locator.count().catch(() => 0);
5295
5364
  for (let index = 0; index < count; index += 1) {
@@ -5298,10 +5367,11 @@ async function executeSetupAction(action, ordinal, viewport) {
5298
5367
  if (setupTextMatches(text, action)) {
5299
5368
  return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
5300
5369
  }
5370
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
5301
5371
  }
5302
5372
  await page.waitForTimeout(100);
5303
5373
  }
5304
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
5374
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
5305
5375
  }
5306
5376
  if (type === "assert_text_visible" || type === "assert_text_absent") {
5307
5377
  const scope = await setupActionScope(action, timeout);
@@ -5310,6 +5380,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5310
5380
  const startedAt = Date.now();
5311
5381
  let lastText = "";
5312
5382
  let matchedText = "";
5383
+ let caseInsensitiveText = "";
5313
5384
  let hiddenMatch = false;
5314
5385
  while (Date.now() - startedAt <= timeout) {
5315
5386
  const count = await locator.count().catch(() => 0);
@@ -5332,6 +5403,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5332
5403
  }
5333
5404
  break;
5334
5405
  }
5406
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
5335
5407
  }
5336
5408
  if (type === "assert_text_absent" && !matched) {
5337
5409
  return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
@@ -5342,7 +5414,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5342
5414
  if (hiddenMatch) {
5343
5415
  return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
5344
5416
  }
5345
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
5417
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
5346
5418
  }
5347
5419
  return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
5348
5420
  }
@@ -6450,6 +6522,7 @@ async function captureViewport(viewport) {
6450
6522
  const text_sequences = {};
6451
6523
  const text_matches = {};
6452
6524
  const text_match_samples = {};
6525
+ const text_case_insensitive_samples = {};
6453
6526
  const http_statuses = {};
6454
6527
  const link_statuses = {};
6455
6528
  for (const check of profile.checks || []) {
@@ -6475,6 +6548,7 @@ async function captureViewport(viewport) {
6475
6548
  const sample = dom.body_text || dom.body_text_sample || "";
6476
6549
  text_matches[key] = textMatches(sample, check);
6477
6550
  text_match_samples[key] = textMatchSamples(sample, check);
6551
+ text_case_insensitive_samples[key] = textCaseInsensitiveSamples(sample, check);
6478
6552
  }
6479
6553
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
6480
6554
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -6552,6 +6626,7 @@ async function captureViewport(viewport) {
6552
6626
  text_sequences,
6553
6627
  text_matches,
6554
6628
  text_match_samples,
6629
+ text_case_insensitive_samples,
6555
6630
  http_statuses,
6556
6631
  link_statuses,
6557
6632
  route_inventory: routeInventory,
package/dist/cli.cjs CHANGED
@@ -8837,6 +8837,27 @@ function textMatchSamples(sample, check) {
8837
8837
  const sampleText = textSampleAroundMatch(source, index, text.length);
8838
8838
  return sampleText ? [sampleText] : [];
8839
8839
  }
8840
+ function textCaseInsensitiveSamples(sample, check) {
8841
+ const source = String(sample || "");
8842
+ const text = check.pattern ? "" : check.text || "";
8843
+ if (!source || !text) return [];
8844
+ const index = source.toLowerCase().indexOf(text.toLowerCase());
8845
+ const sampleText = textSampleAroundMatch(source, index, text.length);
8846
+ return sampleText ? [sampleText] : [];
8847
+ }
8848
+ function textCaseInsensitiveSequenceSamples(texts, check) {
8849
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
8850
+ if (!text) return [];
8851
+ const expected = text.toLowerCase();
8852
+ return texts.map((candidate) => compactTextEvidenceSample(candidate)).filter((candidate) => candidate && candidate.toLowerCase().includes(expected)).slice(0, 3).map((candidate) => candidate.slice(0, 240));
8853
+ }
8854
+ function textCaseInsensitiveFailureSamples(viewport, check) {
8855
+ const key = textKey(check);
8856
+ const captured = viewport.text_case_insensitive_samples?.[key] || [];
8857
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
8858
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
8859
+ return textCaseInsensitiveSamples(viewport.body_text_sample || "", check).slice(0, 3);
8860
+ }
8840
8861
  function textCheckFailureSamples(viewport, check) {
8841
8862
  const key = textKey(check);
8842
8863
  const captured = viewport.text_match_samples?.[key] || [];
@@ -9149,13 +9170,15 @@ function assessCheckFromEvidence(check, evidence) {
9149
9170
  const matched = matches.length > 0;
9150
9171
  const failedAgainstExpectation = matched !== expectedVisible;
9151
9172
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
9173
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveSequenceSamples(texts, check) : [];
9152
9174
  return {
9153
9175
  viewport: viewport.name,
9154
9176
  selector_count: viewport.selectors?.[key]?.count || 0,
9155
9177
  visible_count: viewport.selectors?.[key]?.visible_count || 0,
9156
9178
  matched_count: matches.length,
9157
9179
  matched,
9158
- samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240))
9180
+ samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
9181
+ case_insensitive_samples: caseInsensitiveSamples
9159
9182
  };
9160
9183
  });
9161
9184
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -9298,7 +9321,8 @@ function assessCheckFromEvidence(check, evidence) {
9298
9321
  return {
9299
9322
  viewport: viewport.name,
9300
9323
  matched,
9301
- samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
9324
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
9325
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveFailureSamples(viewport, check) : []
9302
9326
  };
9303
9327
  });
9304
9328
  const matches = results.map((result) => result.matched);
@@ -9912,6 +9936,32 @@ function textMatchSamples(sample, check) {
9912
9936
  const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
9913
9937
  return sampleText ? [sampleText] : [];
9914
9938
  }
9939
+ function textCaseInsensitiveSamples(sample, check) {
9940
+ const source = String(sample || "");
9941
+ const text = check.pattern ? "" : check.text || "";
9942
+ if (!source || !text) return [];
9943
+ const sampleText = textSampleAroundMatch(source, source.toLowerCase().indexOf(text.toLowerCase()), text.length);
9944
+ return sampleText ? [sampleText] : [];
9945
+ }
9946
+ function textCaseInsensitiveSequenceSamples(texts, check) {
9947
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
9948
+ if (!text) return [];
9949
+ const expected = text.toLowerCase();
9950
+ return (texts || [])
9951
+ .map((candidate) => compactTextEvidenceSample(candidate))
9952
+ .filter((candidate) => candidate && candidate.toLowerCase().includes(expected))
9953
+ .slice(0, 3)
9954
+ .map((candidate) => candidate.slice(0, 240));
9955
+ }
9956
+ function textCaseInsensitiveFailureSamples(viewport, check) {
9957
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
9958
+ const captured = viewport && viewport.text_case_insensitive_samples && Array.isArray(viewport.text_case_insensitive_samples[key]) ? viewport.text_case_insensitive_samples[key] : [];
9959
+ const capturedSamples = captured
9960
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
9961
+ .filter(Boolean);
9962
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
9963
+ return textCaseInsensitiveSamples(viewport && viewport.body_text_sample || "", check).slice(0, 3);
9964
+ }
9915
9965
  function textCheckFailureSamples(viewport, check) {
9916
9966
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
9917
9967
  const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
@@ -10870,6 +10920,9 @@ function assessProfile(profile, evidence) {
10870
10920
  const matched = matches.length > 0;
10871
10921
  const failedAgainstExpectation = matched !== expectedVisible;
10872
10922
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
10923
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched
10924
+ ? textCaseInsensitiveSequenceSamples(texts, check)
10925
+ : [];
10873
10926
  return {
10874
10927
  viewport: viewport.name,
10875
10928
  selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
@@ -10877,6 +10930,7 @@ function assessProfile(profile, evidence) {
10877
10930
  matched_count: matches.length,
10878
10931
  matched,
10879
10932
  samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
10933
+ case_insensitive_samples: caseInsensitiveSamples,
10880
10934
  };
10881
10935
  });
10882
10936
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -11008,6 +11062,9 @@ function assessProfile(profile, evidence) {
11008
11062
  viewport: viewport.name,
11009
11063
  matched,
11010
11064
  samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
11065
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched
11066
+ ? textCaseInsensitiveFailureSamples(viewport, check)
11067
+ : [],
11011
11068
  };
11012
11069
  });
11013
11070
  const matches = results.map((result) => result.matched);
@@ -11397,6 +11454,14 @@ function setupTextMatches(sample, action) {
11397
11454
  return rawSample.includes(expected)
11398
11455
  || normalizeSetupMatchText(rawSample).includes(normalizeSetupMatchText(expected));
11399
11456
  }
11457
+ function setupCaseInsensitiveTextSample(sample, action) {
11458
+ if (!action || action.pattern || !action.text) return "";
11459
+ const normalizedSample = normalizeSetupMatchText(sample);
11460
+ const normalizedExpected = normalizeSetupMatchText(action.text);
11461
+ if (!normalizedSample || !normalizedExpected) return "";
11462
+ if (!normalizedSample.toLowerCase().includes(normalizedExpected.toLowerCase())) return "";
11463
+ return compactSetupResultText(normalizedSample);
11464
+ }
11400
11465
  async function waitForAnyVisibleSelector(context, selector, timeout) {
11401
11466
  const deadline = Date.now() + setupNumber(timeout, 15000);
11402
11467
  let lastReason = "selector_not_found";
@@ -12147,6 +12212,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12147
12212
  if (!count) return { ...base, reason: "selector_not_found", count };
12148
12213
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
12149
12214
  let matchedText = null;
12215
+ let caseInsensitiveText = null;
12150
12216
  let hiddenMatchIndex = -1;
12151
12217
  let hiddenMatchedText = null;
12152
12218
  if (action.text || action.pattern) {
@@ -12164,10 +12230,12 @@ async function executeSetupAction(action, ordinal, viewport) {
12164
12230
  hiddenMatchIndex = index;
12165
12231
  hiddenMatchedText = compactSetupResultText(text);
12166
12232
  }
12233
+ } else if (!caseInsensitiveText) {
12234
+ caseInsensitiveText = setupCaseInsensitiveTextSample(text, action) || null;
12167
12235
  }
12168
12236
  }
12169
12237
  if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
12170
- if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
12238
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count, case_insensitive_text: caseInsensitiveText || undefined };
12171
12239
  }
12172
12240
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
12173
12241
  const clickOptions = action.force === true
@@ -12211,6 +12279,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12211
12279
  const locator = scope.context.locator(action.selector);
12212
12280
  const startedAt = Date.now();
12213
12281
  let lastText = "";
12282
+ let caseInsensitiveText = "";
12214
12283
  while (Date.now() - startedAt <= timeout) {
12215
12284
  const count = await locator.count().catch(() => 0);
12216
12285
  for (let index = 0; index < count; index += 1) {
@@ -12219,10 +12288,11 @@ async function executeSetupAction(action, ordinal, viewport) {
12219
12288
  if (setupTextMatches(text, action)) {
12220
12289
  return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
12221
12290
  }
12291
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
12222
12292
  }
12223
12293
  await page.waitForTimeout(100);
12224
12294
  }
12225
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
12295
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
12226
12296
  }
12227
12297
  if (type === "assert_text_visible" || type === "assert_text_absent") {
12228
12298
  const scope = await setupActionScope(action, timeout);
@@ -12231,6 +12301,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12231
12301
  const startedAt = Date.now();
12232
12302
  let lastText = "";
12233
12303
  let matchedText = "";
12304
+ let caseInsensitiveText = "";
12234
12305
  let hiddenMatch = false;
12235
12306
  while (Date.now() - startedAt <= timeout) {
12236
12307
  const count = await locator.count().catch(() => 0);
@@ -12253,6 +12324,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12253
12324
  }
12254
12325
  break;
12255
12326
  }
12327
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
12256
12328
  }
12257
12329
  if (type === "assert_text_absent" && !matched) {
12258
12330
  return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
@@ -12263,7 +12335,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12263
12335
  if (hiddenMatch) {
12264
12336
  return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
12265
12337
  }
12266
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
12338
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
12267
12339
  }
12268
12340
  return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
12269
12341
  }
@@ -13371,6 +13443,7 @@ async function captureViewport(viewport) {
13371
13443
  const text_sequences = {};
13372
13444
  const text_matches = {};
13373
13445
  const text_match_samples = {};
13446
+ const text_case_insensitive_samples = {};
13374
13447
  const http_statuses = {};
13375
13448
  const link_statuses = {};
13376
13449
  for (const check of profile.checks || []) {
@@ -13396,6 +13469,7 @@ async function captureViewport(viewport) {
13396
13469
  const sample = dom.body_text || dom.body_text_sample || "";
13397
13470
  text_matches[key] = textMatches(sample, check);
13398
13471
  text_match_samples[key] = textMatchSamples(sample, check);
13472
+ text_case_insensitive_samples[key] = textCaseInsensitiveSamples(sample, check);
13399
13473
  }
13400
13474
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
13401
13475
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -13473,6 +13547,7 @@ async function captureViewport(viewport) {
13473
13547
  text_sequences,
13474
13548
  text_matches,
13475
13549
  text_match_samples,
13550
+ text_case_insensitive_samples,
13476
13551
  http_statuses,
13477
13552
  link_statuses,
13478
13553
  route_inventory: routeInventory,
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  profileStatusExitCode,
13
13
  resolveRiddleProofProfileTargetUrl,
14
14
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-ZJNM3YAB.js";
15
+ } from "./chunk-ZYD2SGEM.js";
16
16
  import {
17
17
  createRiddleApiClient,
18
18
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -10633,6 +10633,27 @@ function textMatchSamples(sample, check) {
10633
10633
  const sampleText = textSampleAroundMatch(source, index, text.length);
10634
10634
  return sampleText ? [sampleText] : [];
10635
10635
  }
10636
+ function textCaseInsensitiveSamples(sample, check) {
10637
+ const source = String(sample || "");
10638
+ const text = check.pattern ? "" : check.text || "";
10639
+ if (!source || !text) return [];
10640
+ const index = source.toLowerCase().indexOf(text.toLowerCase());
10641
+ const sampleText = textSampleAroundMatch(source, index, text.length);
10642
+ return sampleText ? [sampleText] : [];
10643
+ }
10644
+ function textCaseInsensitiveSequenceSamples(texts, check) {
10645
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
10646
+ if (!text) return [];
10647
+ const expected = text.toLowerCase();
10648
+ return texts.map((candidate) => compactTextEvidenceSample(candidate)).filter((candidate) => candidate && candidate.toLowerCase().includes(expected)).slice(0, 3).map((candidate) => candidate.slice(0, 240));
10649
+ }
10650
+ function textCaseInsensitiveFailureSamples(viewport, check) {
10651
+ const key = textKey(check);
10652
+ const captured = viewport.text_case_insensitive_samples?.[key] || [];
10653
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
10654
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
10655
+ return textCaseInsensitiveSamples(viewport.body_text_sample || "", check).slice(0, 3);
10656
+ }
10636
10657
  function textCheckFailureSamples(viewport, check) {
10637
10658
  const key = textKey(check);
10638
10659
  const captured = viewport.text_match_samples?.[key] || [];
@@ -10945,13 +10966,15 @@ function assessCheckFromEvidence(check, evidence) {
10945
10966
  const matched = matches.length > 0;
10946
10967
  const failedAgainstExpectation = matched !== expectedVisible;
10947
10968
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
10969
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveSequenceSamples(texts, check) : [];
10948
10970
  return {
10949
10971
  viewport: viewport.name,
10950
10972
  selector_count: viewport.selectors?.[key]?.count || 0,
10951
10973
  visible_count: viewport.selectors?.[key]?.visible_count || 0,
10952
10974
  matched_count: matches.length,
10953
10975
  matched,
10954
- samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240))
10976
+ samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
10977
+ case_insensitive_samples: caseInsensitiveSamples
10955
10978
  };
10956
10979
  });
10957
10980
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -11094,7 +11117,8 @@ function assessCheckFromEvidence(check, evidence) {
11094
11117
  return {
11095
11118
  viewport: viewport.name,
11096
11119
  matched,
11097
- samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
11120
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
11121
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveFailureSamples(viewport, check) : []
11098
11122
  };
11099
11123
  });
11100
11124
  const matches = results.map((result) => result.matched);
@@ -11724,6 +11748,32 @@ function textMatchSamples(sample, check) {
11724
11748
  const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
11725
11749
  return sampleText ? [sampleText] : [];
11726
11750
  }
11751
+ function textCaseInsensitiveSamples(sample, check) {
11752
+ const source = String(sample || "");
11753
+ const text = check.pattern ? "" : check.text || "";
11754
+ if (!source || !text) return [];
11755
+ const sampleText = textSampleAroundMatch(source, source.toLowerCase().indexOf(text.toLowerCase()), text.length);
11756
+ return sampleText ? [sampleText] : [];
11757
+ }
11758
+ function textCaseInsensitiveSequenceSamples(texts, check) {
11759
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
11760
+ if (!text) return [];
11761
+ const expected = text.toLowerCase();
11762
+ return (texts || [])
11763
+ .map((candidate) => compactTextEvidenceSample(candidate))
11764
+ .filter((candidate) => candidate && candidate.toLowerCase().includes(expected))
11765
+ .slice(0, 3)
11766
+ .map((candidate) => candidate.slice(0, 240));
11767
+ }
11768
+ function textCaseInsensitiveFailureSamples(viewport, check) {
11769
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
11770
+ const captured = viewport && viewport.text_case_insensitive_samples && Array.isArray(viewport.text_case_insensitive_samples[key]) ? viewport.text_case_insensitive_samples[key] : [];
11771
+ const capturedSamples = captured
11772
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
11773
+ .filter(Boolean);
11774
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
11775
+ return textCaseInsensitiveSamples(viewport && viewport.body_text_sample || "", check).slice(0, 3);
11776
+ }
11727
11777
  function textCheckFailureSamples(viewport, check) {
11728
11778
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
11729
11779
  const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
@@ -12682,6 +12732,9 @@ function assessProfile(profile, evidence) {
12682
12732
  const matched = matches.length > 0;
12683
12733
  const failedAgainstExpectation = matched !== expectedVisible;
12684
12734
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
12735
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched
12736
+ ? textCaseInsensitiveSequenceSamples(texts, check)
12737
+ : [];
12685
12738
  return {
12686
12739
  viewport: viewport.name,
12687
12740
  selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
@@ -12689,6 +12742,7 @@ function assessProfile(profile, evidence) {
12689
12742
  matched_count: matches.length,
12690
12743
  matched,
12691
12744
  samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
12745
+ case_insensitive_samples: caseInsensitiveSamples,
12692
12746
  };
12693
12747
  });
12694
12748
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -12820,6 +12874,9 @@ function assessProfile(profile, evidence) {
12820
12874
  viewport: viewport.name,
12821
12875
  matched,
12822
12876
  samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
12877
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched
12878
+ ? textCaseInsensitiveFailureSamples(viewport, check)
12879
+ : [],
12823
12880
  };
12824
12881
  });
12825
12882
  const matches = results.map((result) => result.matched);
@@ -13209,6 +13266,14 @@ function setupTextMatches(sample, action) {
13209
13266
  return rawSample.includes(expected)
13210
13267
  || normalizeSetupMatchText(rawSample).includes(normalizeSetupMatchText(expected));
13211
13268
  }
13269
+ function setupCaseInsensitiveTextSample(sample, action) {
13270
+ if (!action || action.pattern || !action.text) return "";
13271
+ const normalizedSample = normalizeSetupMatchText(sample);
13272
+ const normalizedExpected = normalizeSetupMatchText(action.text);
13273
+ if (!normalizedSample || !normalizedExpected) return "";
13274
+ if (!normalizedSample.toLowerCase().includes(normalizedExpected.toLowerCase())) return "";
13275
+ return compactSetupResultText(normalizedSample);
13276
+ }
13212
13277
  async function waitForAnyVisibleSelector(context, selector, timeout) {
13213
13278
  const deadline = Date.now() + setupNumber(timeout, 15000);
13214
13279
  let lastReason = "selector_not_found";
@@ -13959,6 +14024,7 @@ async function executeSetupAction(action, ordinal, viewport) {
13959
14024
  if (!count) return { ...base, reason: "selector_not_found", count };
13960
14025
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
13961
14026
  let matchedText = null;
14027
+ let caseInsensitiveText = null;
13962
14028
  let hiddenMatchIndex = -1;
13963
14029
  let hiddenMatchedText = null;
13964
14030
  if (action.text || action.pattern) {
@@ -13976,10 +14042,12 @@ async function executeSetupAction(action, ordinal, viewport) {
13976
14042
  hiddenMatchIndex = index;
13977
14043
  hiddenMatchedText = compactSetupResultText(text);
13978
14044
  }
14045
+ } else if (!caseInsensitiveText) {
14046
+ caseInsensitiveText = setupCaseInsensitiveTextSample(text, action) || null;
13979
14047
  }
13980
14048
  }
13981
14049
  if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
13982
- if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
14050
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count, case_insensitive_text: caseInsensitiveText || undefined };
13983
14051
  }
13984
14052
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
13985
14053
  const clickOptions = action.force === true
@@ -14023,6 +14091,7 @@ async function executeSetupAction(action, ordinal, viewport) {
14023
14091
  const locator = scope.context.locator(action.selector);
14024
14092
  const startedAt = Date.now();
14025
14093
  let lastText = "";
14094
+ let caseInsensitiveText = "";
14026
14095
  while (Date.now() - startedAt <= timeout) {
14027
14096
  const count = await locator.count().catch(() => 0);
14028
14097
  for (let index = 0; index < count; index += 1) {
@@ -14031,10 +14100,11 @@ async function executeSetupAction(action, ordinal, viewport) {
14031
14100
  if (setupTextMatches(text, action)) {
14032
14101
  return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
14033
14102
  }
14103
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
14034
14104
  }
14035
14105
  await page.waitForTimeout(100);
14036
14106
  }
14037
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
14107
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
14038
14108
  }
14039
14109
  if (type === "assert_text_visible" || type === "assert_text_absent") {
14040
14110
  const scope = await setupActionScope(action, timeout);
@@ -14043,6 +14113,7 @@ async function executeSetupAction(action, ordinal, viewport) {
14043
14113
  const startedAt = Date.now();
14044
14114
  let lastText = "";
14045
14115
  let matchedText = "";
14116
+ let caseInsensitiveText = "";
14046
14117
  let hiddenMatch = false;
14047
14118
  while (Date.now() - startedAt <= timeout) {
14048
14119
  const count = await locator.count().catch(() => 0);
@@ -14065,6 +14136,7 @@ async function executeSetupAction(action, ordinal, viewport) {
14065
14136
  }
14066
14137
  break;
14067
14138
  }
14139
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
14068
14140
  }
14069
14141
  if (type === "assert_text_absent" && !matched) {
14070
14142
  return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
@@ -14075,7 +14147,7 @@ async function executeSetupAction(action, ordinal, viewport) {
14075
14147
  if (hiddenMatch) {
14076
14148
  return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
14077
14149
  }
14078
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
14150
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
14079
14151
  }
14080
14152
  return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
14081
14153
  }
@@ -15183,6 +15255,7 @@ async function captureViewport(viewport) {
15183
15255
  const text_sequences = {};
15184
15256
  const text_matches = {};
15185
15257
  const text_match_samples = {};
15258
+ const text_case_insensitive_samples = {};
15186
15259
  const http_statuses = {};
15187
15260
  const link_statuses = {};
15188
15261
  for (const check of profile.checks || []) {
@@ -15208,6 +15281,7 @@ async function captureViewport(viewport) {
15208
15281
  const sample = dom.body_text || dom.body_text_sample || "";
15209
15282
  text_matches[key] = textMatches(sample, check);
15210
15283
  text_match_samples[key] = textMatchSamples(sample, check);
15284
+ text_case_insensitive_samples[key] = textCaseInsensitiveSamples(sample, check);
15211
15285
  }
15212
15286
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
15213
15287
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -15285,6 +15359,7 @@ async function captureViewport(viewport) {
15285
15359
  text_sequences,
15286
15360
  text_matches,
15287
15361
  text_match_samples,
15362
+ text_case_insensitive_samples,
15288
15363
  http_statuses,
15289
15364
  link_statuses,
15290
15365
  route_inventory: routeInventory,
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-ZJNM3YAB.js";
65
+ } from "./chunk-ZYD2SGEM.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -1947,6 +1947,27 @@ function textMatchSamples(sample, check) {
1947
1947
  const sampleText = textSampleAroundMatch(source, index, text.length);
1948
1948
  return sampleText ? [sampleText] : [];
1949
1949
  }
1950
+ function textCaseInsensitiveSamples(sample, check) {
1951
+ const source = String(sample || "");
1952
+ const text = check.pattern ? "" : check.text || "";
1953
+ if (!source || !text) return [];
1954
+ const index = source.toLowerCase().indexOf(text.toLowerCase());
1955
+ const sampleText = textSampleAroundMatch(source, index, text.length);
1956
+ return sampleText ? [sampleText] : [];
1957
+ }
1958
+ function textCaseInsensitiveSequenceSamples(texts, check) {
1959
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
1960
+ if (!text) return [];
1961
+ const expected = text.toLowerCase();
1962
+ return texts.map((candidate) => compactTextEvidenceSample(candidate)).filter((candidate) => candidate && candidate.toLowerCase().includes(expected)).slice(0, 3).map((candidate) => candidate.slice(0, 240));
1963
+ }
1964
+ function textCaseInsensitiveFailureSamples(viewport, check) {
1965
+ const key = textKey(check);
1966
+ const captured = viewport.text_case_insensitive_samples?.[key] || [];
1967
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
1968
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
1969
+ return textCaseInsensitiveSamples(viewport.body_text_sample || "", check).slice(0, 3);
1970
+ }
1950
1971
  function textCheckFailureSamples(viewport, check) {
1951
1972
  const key = textKey(check);
1952
1973
  const captured = viewport.text_match_samples?.[key] || [];
@@ -2259,13 +2280,15 @@ function assessCheckFromEvidence(check, evidence) {
2259
2280
  const matched = matches.length > 0;
2260
2281
  const failedAgainstExpectation = matched !== expectedVisible;
2261
2282
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
2283
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveSequenceSamples(texts, check) : [];
2262
2284
  return {
2263
2285
  viewport: viewport.name,
2264
2286
  selector_count: viewport.selectors?.[key]?.count || 0,
2265
2287
  visible_count: viewport.selectors?.[key]?.visible_count || 0,
2266
2288
  matched_count: matches.length,
2267
2289
  matched,
2268
- samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240))
2290
+ samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
2291
+ case_insensitive_samples: caseInsensitiveSamples
2269
2292
  };
2270
2293
  });
2271
2294
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -2408,7 +2431,8 @@ function assessCheckFromEvidence(check, evidence) {
2408
2431
  return {
2409
2432
  viewport: viewport.name,
2410
2433
  matched,
2411
- samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
2434
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
2435
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched ? textCaseInsensitiveFailureSamples(viewport, check) : []
2412
2436
  };
2413
2437
  });
2414
2438
  const matches = results.map((result) => result.matched);
@@ -3038,6 +3062,32 @@ function textMatchSamples(sample, check) {
3038
3062
  const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
3039
3063
  return sampleText ? [sampleText] : [];
3040
3064
  }
3065
+ function textCaseInsensitiveSamples(sample, check) {
3066
+ const source = String(sample || "");
3067
+ const text = check.pattern ? "" : check.text || "";
3068
+ if (!source || !text) return [];
3069
+ const sampleText = textSampleAroundMatch(source, source.toLowerCase().indexOf(text.toLowerCase()), text.length);
3070
+ return sampleText ? [sampleText] : [];
3071
+ }
3072
+ function textCaseInsensitiveSequenceSamples(texts, check) {
3073
+ const text = check.pattern ? "" : compactTextEvidenceSample(check.text || "");
3074
+ if (!text) return [];
3075
+ const expected = text.toLowerCase();
3076
+ return (texts || [])
3077
+ .map((candidate) => compactTextEvidenceSample(candidate))
3078
+ .filter((candidate) => candidate && candidate.toLowerCase().includes(expected))
3079
+ .slice(0, 3)
3080
+ .map((candidate) => candidate.slice(0, 240));
3081
+ }
3082
+ function textCaseInsensitiveFailureSamples(viewport, check) {
3083
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
3084
+ const captured = viewport && viewport.text_case_insensitive_samples && Array.isArray(viewport.text_case_insensitive_samples[key]) ? viewport.text_case_insensitive_samples[key] : [];
3085
+ const capturedSamples = captured
3086
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
3087
+ .filter(Boolean);
3088
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
3089
+ return textCaseInsensitiveSamples(viewport && viewport.body_text_sample || "", check).slice(0, 3);
3090
+ }
3041
3091
  function textCheckFailureSamples(viewport, check) {
3042
3092
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
3043
3093
  const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
@@ -3996,6 +4046,9 @@ function assessProfile(profile, evidence) {
3996
4046
  const matched = matches.length > 0;
3997
4047
  const failedAgainstExpectation = matched !== expectedVisible;
3998
4048
  const sampleTexts = matches.length ? matches : failedAgainstExpectation ? texts : [];
4049
+ const caseInsensitiveSamples = failedAgainstExpectation && expectedVisible && !matched
4050
+ ? textCaseInsensitiveSequenceSamples(texts, check)
4051
+ : [];
3999
4052
  return {
4000
4053
  viewport: viewport.name,
4001
4054
  selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
@@ -4003,6 +4056,7 @@ function assessProfile(profile, evidence) {
4003
4056
  matched_count: matches.length,
4004
4057
  matched,
4005
4058
  samples: sampleTexts.slice(0, 3).map((text) => text.slice(0, 240)),
4059
+ case_insensitive_samples: caseInsensitiveSamples,
4006
4060
  };
4007
4061
  });
4008
4062
  const failed = results.filter((result) => result.matched !== expectedVisible).length;
@@ -4134,6 +4188,9 @@ function assessProfile(profile, evidence) {
4134
4188
  viewport: viewport.name,
4135
4189
  matched,
4136
4190
  samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
4191
+ case_insensitive_samples: failedAgainstExpectation && expectedVisible && !matched
4192
+ ? textCaseInsensitiveFailureSamples(viewport, check)
4193
+ : [],
4137
4194
  };
4138
4195
  });
4139
4196
  const matches = results.map((result) => result.matched);
@@ -4523,6 +4580,14 @@ function setupTextMatches(sample, action) {
4523
4580
  return rawSample.includes(expected)
4524
4581
  || normalizeSetupMatchText(rawSample).includes(normalizeSetupMatchText(expected));
4525
4582
  }
4583
+ function setupCaseInsensitiveTextSample(sample, action) {
4584
+ if (!action || action.pattern || !action.text) return "";
4585
+ const normalizedSample = normalizeSetupMatchText(sample);
4586
+ const normalizedExpected = normalizeSetupMatchText(action.text);
4587
+ if (!normalizedSample || !normalizedExpected) return "";
4588
+ if (!normalizedSample.toLowerCase().includes(normalizedExpected.toLowerCase())) return "";
4589
+ return compactSetupResultText(normalizedSample);
4590
+ }
4526
4591
  async function waitForAnyVisibleSelector(context, selector, timeout) {
4527
4592
  const deadline = Date.now() + setupNumber(timeout, 15000);
4528
4593
  let lastReason = "selector_not_found";
@@ -5273,6 +5338,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5273
5338
  if (!count) return { ...base, reason: "selector_not_found", count };
5274
5339
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
5275
5340
  let matchedText = null;
5341
+ let caseInsensitiveText = null;
5276
5342
  let hiddenMatchIndex = -1;
5277
5343
  let hiddenMatchedText = null;
5278
5344
  if (action.text || action.pattern) {
@@ -5290,10 +5356,12 @@ async function executeSetupAction(action, ordinal, viewport) {
5290
5356
  hiddenMatchIndex = index;
5291
5357
  hiddenMatchedText = compactSetupResultText(text);
5292
5358
  }
5359
+ } else if (!caseInsensitiveText) {
5360
+ caseInsensitiveText = setupCaseInsensitiveTextSample(text, action) || null;
5293
5361
  }
5294
5362
  }
5295
5363
  if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
5296
- if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
5364
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count, case_insensitive_text: caseInsensitiveText || undefined };
5297
5365
  }
5298
5366
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
5299
5367
  const clickOptions = action.force === true
@@ -5337,6 +5405,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5337
5405
  const locator = scope.context.locator(action.selector);
5338
5406
  const startedAt = Date.now();
5339
5407
  let lastText = "";
5408
+ let caseInsensitiveText = "";
5340
5409
  while (Date.now() - startedAt <= timeout) {
5341
5410
  const count = await locator.count().catch(() => 0);
5342
5411
  for (let index = 0; index < count; index += 1) {
@@ -5345,10 +5414,11 @@ async function executeSetupAction(action, ordinal, viewport) {
5345
5414
  if (setupTextMatches(text, action)) {
5346
5415
  return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
5347
5416
  }
5417
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
5348
5418
  }
5349
5419
  await page.waitForTimeout(100);
5350
5420
  }
5351
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
5421
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
5352
5422
  }
5353
5423
  if (type === "assert_text_visible" || type === "assert_text_absent") {
5354
5424
  const scope = await setupActionScope(action, timeout);
@@ -5357,6 +5427,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5357
5427
  const startedAt = Date.now();
5358
5428
  let lastText = "";
5359
5429
  let matchedText = "";
5430
+ let caseInsensitiveText = "";
5360
5431
  let hiddenMatch = false;
5361
5432
  while (Date.now() - startedAt <= timeout) {
5362
5433
  const count = await locator.count().catch(() => 0);
@@ -5379,6 +5450,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5379
5450
  }
5380
5451
  break;
5381
5452
  }
5453
+ caseInsensitiveText = caseInsensitiveText || setupCaseInsensitiveTextSample(text, action);
5382
5454
  }
5383
5455
  if (type === "assert_text_absent" && !matched) {
5384
5456
  return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
@@ -5389,7 +5461,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5389
5461
  if (hiddenMatch) {
5390
5462
  return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
5391
5463
  }
5392
- return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
5464
+ return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), case_insensitive_text: caseInsensitiveText || undefined, timeout_ms: timeout };
5393
5465
  }
5394
5466
  return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
5395
5467
  }
@@ -6497,6 +6569,7 @@ async function captureViewport(viewport) {
6497
6569
  const text_sequences = {};
6498
6570
  const text_matches = {};
6499
6571
  const text_match_samples = {};
6572
+ const text_case_insensitive_samples = {};
6500
6573
  const http_statuses = {};
6501
6574
  const link_statuses = {};
6502
6575
  for (const check of profile.checks || []) {
@@ -6522,6 +6595,7 @@ async function captureViewport(viewport) {
6522
6595
  const sample = dom.body_text || dom.body_text_sample || "";
6523
6596
  text_matches[key] = textMatches(sample, check);
6524
6597
  text_match_samples[key] = textMatchSamples(sample, check);
6598
+ text_case_insensitive_samples[key] = textCaseInsensitiveSamples(sample, check);
6525
6599
  }
6526
6600
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
6527
6601
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -6599,6 +6673,7 @@ async function captureViewport(viewport) {
6599
6673
  text_sequences,
6600
6674
  text_matches,
6601
6675
  text_match_samples,
6676
+ text_case_insensitive_samples,
6602
6677
  http_statuses,
6603
6678
  link_statuses,
6604
6679
  route_inventory: routeInventory,
@@ -309,6 +309,7 @@ interface RiddleProofProfileViewportEvidence {
309
309
  text_sequences?: Record<string, Record<string, JsonValue>>;
310
310
  text_matches?: Record<string, boolean>;
311
311
  text_match_samples?: Record<string, string[]>;
312
+ text_case_insensitive_samples?: Record<string, string[]>;
312
313
  http_statuses?: Record<string, Record<string, JsonValue>>;
313
314
  link_statuses?: Record<string, Record<string, JsonValue>>;
314
315
  route_inventory?: Record<string, JsonValue>;
package/dist/profile.d.ts CHANGED
@@ -309,6 +309,7 @@ interface RiddleProofProfileViewportEvidence {
309
309
  text_sequences?: Record<string, Record<string, JsonValue>>;
310
310
  text_matches?: Record<string, boolean>;
311
311
  text_match_samples?: Record<string, string[]>;
312
+ text_case_insensitive_samples?: Record<string, string[]>;
312
313
  http_statuses?: Record<string, Record<string, JsonValue>>;
313
314
  link_statuses?: Record<string, Record<string, JsonValue>>;
314
315
  route_inventory?: Record<string, JsonValue>;
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-ZJNM3YAB.js";
26
+ } from "./chunk-ZYD2SGEM.js";
27
27
  export {
28
28
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
29
29
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.130",
3
+ "version": "0.7.131",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",