@riddledc/riddle-proof 0.7.53 → 0.7.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/{chunk-IKT7AKZN.js → chunk-2JFDTCIC.js} +152 -4
- package/dist/cli.cjs +152 -4
- package/dist/cli.js +1 -1
- package/dist/index.cjs +152 -4
- package/dist/index.js +1 -1
- package/dist/profile.cjs +152 -4
- package/dist/profile.d.cts +3 -1
- package/dist/profile.d.ts +3 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -303,6 +303,22 @@ These checks are useful for audit/no-diff profiles where the product should
|
|
|
303
303
|
show a fallback state and avoid rendering stale loaders, duplicate rows, or
|
|
304
304
|
missing-resource iframes.
|
|
305
305
|
|
|
306
|
+
Use `url_search_param_equals` and `url_search_param_absent` when the final URL
|
|
307
|
+
is part of the contract, such as deep-link recovery that must drop a stale
|
|
308
|
+
local identifier while preserving shareable query state:
|
|
309
|
+
|
|
310
|
+
```json
|
|
311
|
+
[
|
|
312
|
+
{ "type": "url_search_param_absent", "param": "seq" },
|
|
313
|
+
{ "type": "url_search_param_equals", "param": "song", "expected_value": "monkberry-moon-delight-tab" },
|
|
314
|
+
{ "type": "url_search_param_equals", "param": "view", "expected_value": "trainer" }
|
|
315
|
+
]
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The check uses the captured browser URL for each viewport after setup actions
|
|
319
|
+
and waits have completed. `search_param` and `key` are accepted as aliases for
|
|
320
|
+
`param`; `value` is accepted as an alias for `expected_value`.
|
|
321
|
+
|
|
306
322
|
Use `selector_text_order` when a table, list, or card group must show visible
|
|
307
323
|
items in a specific order after setup actions such as sorting or filtering:
|
|
308
324
|
|
|
@@ -12,6 +12,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
|
|
|
12
12
|
];
|
|
13
13
|
var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
14
14
|
"route_loaded",
|
|
15
|
+
"url_search_param_equals",
|
|
16
|
+
"url_search_param_absent",
|
|
15
17
|
"selector_visible",
|
|
16
18
|
"selector_absent",
|
|
17
19
|
"selector_count_at_least",
|
|
@@ -488,6 +490,13 @@ function normalizeCheck(input, index) {
|
|
|
488
490
|
if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
489
491
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
490
492
|
}
|
|
493
|
+
if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
|
|
494
|
+
throw new Error(`checks[${index}] ${type} requires param.`);
|
|
495
|
+
}
|
|
496
|
+
const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
|
|
497
|
+
if (type === "url_search_param_equals" && expectedValue === void 0) {
|
|
498
|
+
throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
|
|
499
|
+
}
|
|
491
500
|
if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
|
|
492
501
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
493
502
|
}
|
|
@@ -508,6 +517,8 @@ function normalizeCheck(input, index) {
|
|
|
508
517
|
type,
|
|
509
518
|
label: stringValue(input.label),
|
|
510
519
|
expected_path: stringValue(input.expected_path),
|
|
520
|
+
param: stringValue(input.param) || stringValue(input.search_param) || stringValue(input.searchParam) || stringValue(input.key),
|
|
521
|
+
expected_value: expectedValue,
|
|
511
522
|
expected_routes: expectedRoutes,
|
|
512
523
|
selector: stringValue(input.selector),
|
|
513
524
|
expected_texts: expectedTexts,
|
|
@@ -760,6 +771,32 @@ function successfulRoute(route, targetUrl) {
|
|
|
760
771
|
const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
|
|
761
772
|
return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
|
|
762
773
|
}
|
|
774
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
775
|
+
if (!value) return void 0;
|
|
776
|
+
try {
|
|
777
|
+
return targetUrl ? new URL(value, targetUrl) : new URL(value);
|
|
778
|
+
} catch {
|
|
779
|
+
try {
|
|
780
|
+
return new URL(value);
|
|
781
|
+
} catch {
|
|
782
|
+
return void 0;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
787
|
+
return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
|
|
788
|
+
}
|
|
789
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
790
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
791
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
792
|
+
return {
|
|
793
|
+
viewport: viewport.name,
|
|
794
|
+
url: url?.href || null,
|
|
795
|
+
value: values.length ? values[0] : null,
|
|
796
|
+
values,
|
|
797
|
+
present: values.length > 0
|
|
798
|
+
};
|
|
799
|
+
}
|
|
763
800
|
function viewportsForCheck(check, viewports) {
|
|
764
801
|
if (!check.viewports?.length) return viewports;
|
|
765
802
|
const names = new Set(check.viewports);
|
|
@@ -797,6 +834,44 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
797
834
|
message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
|
|
798
835
|
};
|
|
799
836
|
}
|
|
837
|
+
if (check.type === "url_search_param_equals") {
|
|
838
|
+
const param = check.param || "";
|
|
839
|
+
const expectedValue = check.expected_value ?? "";
|
|
840
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
841
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
842
|
+
return {
|
|
843
|
+
type: check.type,
|
|
844
|
+
label: checkLabel(check),
|
|
845
|
+
status: failed.length ? "failed" : "passed",
|
|
846
|
+
evidence: {
|
|
847
|
+
param,
|
|
848
|
+
expected_value: expectedValue,
|
|
849
|
+
observed_values: observations.map((observation) => observation.value),
|
|
850
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
851
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
852
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
853
|
+
},
|
|
854
|
+
message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
if (check.type === "url_search_param_absent") {
|
|
858
|
+
const param = check.param || "";
|
|
859
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
860
|
+
const failed = observations.filter((observation) => observation.present);
|
|
861
|
+
return {
|
|
862
|
+
type: check.type,
|
|
863
|
+
label: checkLabel(check),
|
|
864
|
+
status: failed.length ? "failed" : "passed",
|
|
865
|
+
evidence: {
|
|
866
|
+
param,
|
|
867
|
+
observed_values: observations.map((observation) => observation.value),
|
|
868
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
869
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
870
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
871
|
+
},
|
|
872
|
+
message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
|
|
873
|
+
};
|
|
874
|
+
}
|
|
800
875
|
if (check.type === "selector_visible") {
|
|
801
876
|
const key = selectorKey(check);
|
|
802
877
|
const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
|
|
@@ -1332,6 +1407,29 @@ function routePathMatches(observed, expected, targetUrl) {
|
|
|
1332
1407
|
function routeOk(route, targetUrl) {
|
|
1333
1408
|
return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
|
|
1334
1409
|
}
|
|
1410
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
1411
|
+
if (!value) return null;
|
|
1412
|
+
try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
|
|
1413
|
+
try { return new URL(value); } catch {}
|
|
1414
|
+
return null;
|
|
1415
|
+
}
|
|
1416
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
1417
|
+
return parseEvidenceUrl(viewport && viewport.url, targetUrl)
|
|
1418
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
|
|
1419
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
|
|
1420
|
+
|| parseEvidenceUrl(targetUrl, null);
|
|
1421
|
+
}
|
|
1422
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
1423
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
1424
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
1425
|
+
return {
|
|
1426
|
+
viewport: viewport && viewport.name,
|
|
1427
|
+
url: url ? url.href : null,
|
|
1428
|
+
value: values.length ? values[0] : null,
|
|
1429
|
+
values,
|
|
1430
|
+
present: values.length > 0,
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1335
1433
|
function textMatches(sample, check) {
|
|
1336
1434
|
if (check.pattern) {
|
|
1337
1435
|
try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
|
|
@@ -1636,6 +1734,46 @@ function assessProfile(profile, evidence) {
|
|
|
1636
1734
|
});
|
|
1637
1735
|
continue;
|
|
1638
1736
|
}
|
|
1737
|
+
if (check.type === "url_search_param_equals") {
|
|
1738
|
+
const param = check.param || "";
|
|
1739
|
+
const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
|
|
1740
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
1741
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
1742
|
+
checks.push({
|
|
1743
|
+
type: check.type,
|
|
1744
|
+
label: check.label || check.type,
|
|
1745
|
+
status: failed.length ? "failed" : "passed",
|
|
1746
|
+
evidence: {
|
|
1747
|
+
param,
|
|
1748
|
+
expected_value: expectedValue,
|
|
1749
|
+
observed_values: observations.map((observation) => observation.value),
|
|
1750
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
1751
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
1752
|
+
viewports: observations,
|
|
1753
|
+
},
|
|
1754
|
+
message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
|
|
1755
|
+
});
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
if (check.type === "url_search_param_absent") {
|
|
1759
|
+
const param = check.param || "";
|
|
1760
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
1761
|
+
const failed = observations.filter((observation) => observation.present);
|
|
1762
|
+
checks.push({
|
|
1763
|
+
type: check.type,
|
|
1764
|
+
label: check.label || check.type,
|
|
1765
|
+
status: failed.length ? "failed" : "passed",
|
|
1766
|
+
evidence: {
|
|
1767
|
+
param,
|
|
1768
|
+
observed_values: observations.map((observation) => observation.value),
|
|
1769
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
1770
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
1771
|
+
viewports: observations,
|
|
1772
|
+
},
|
|
1773
|
+
message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
|
|
1774
|
+
});
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1639
1777
|
if (check.type === "selector_visible") {
|
|
1640
1778
|
const selector = check.selector || "";
|
|
1641
1779
|
const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
|
|
@@ -2516,7 +2654,7 @@ async function frameEvidence(selector) {
|
|
|
2516
2654
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
2517
2655
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
2518
2656
|
const overflowOffenders = [];
|
|
2519
|
-
function
|
|
2657
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
2520
2658
|
let current = element.parentElement;
|
|
2521
2659
|
while (current && current !== body && current !== documentElement) {
|
|
2522
2660
|
const style = window.getComputedStyle(current);
|
|
@@ -2526,6 +2664,11 @@ async function frameEvidence(selector) {
|
|
|
2526
2664
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
2527
2665
|
if (contained) return true;
|
|
2528
2666
|
}
|
|
2667
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
2668
|
+
const currentRect = current.getBoundingClientRect();
|
|
2669
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
2670
|
+
if (clippedByAncestor) return true;
|
|
2671
|
+
}
|
|
2529
2672
|
current = current.parentElement;
|
|
2530
2673
|
}
|
|
2531
2674
|
return false;
|
|
@@ -2539,7 +2682,7 @@ async function frameEvidence(selector) {
|
|
|
2539
2682
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
2540
2683
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
2541
2684
|
if (overflow <= 0.5) continue;
|
|
2542
|
-
if (
|
|
2685
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
2543
2686
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
2544
2687
|
const id = element.id ? "#" + element.id : "";
|
|
2545
2688
|
const className = typeof element.className === "string"
|
|
@@ -2919,7 +3062,7 @@ async function captureViewport(viewport) {
|
|
|
2919
3062
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
2920
3063
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
2921
3064
|
const overflowOffenders = [];
|
|
2922
|
-
function
|
|
3065
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
2923
3066
|
let current = element.parentElement;
|
|
2924
3067
|
while (current && current !== body && current !== documentElement) {
|
|
2925
3068
|
const style = window.getComputedStyle(current);
|
|
@@ -2929,6 +3072,11 @@ async function captureViewport(viewport) {
|
|
|
2929
3072
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
2930
3073
|
if (contained) return true;
|
|
2931
3074
|
}
|
|
3075
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
3076
|
+
const currentRect = current.getBoundingClientRect();
|
|
3077
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
3078
|
+
if (clippedByAncestor) return true;
|
|
3079
|
+
}
|
|
2932
3080
|
current = current.parentElement;
|
|
2933
3081
|
}
|
|
2934
3082
|
return false;
|
|
@@ -2942,7 +3090,7 @@ async function captureViewport(viewport) {
|
|
|
2942
3090
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
2943
3091
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
2944
3092
|
if (overflow <= 0.5) continue;
|
|
2945
|
-
if (
|
|
3093
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
2946
3094
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
2947
3095
|
const id = element.id ? "#" + element.id : "";
|
|
2948
3096
|
const className = typeof element.className === "string"
|
package/dist/cli.cjs
CHANGED
|
@@ -6885,6 +6885,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
|
|
|
6885
6885
|
];
|
|
6886
6886
|
var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
6887
6887
|
"route_loaded",
|
|
6888
|
+
"url_search_param_equals",
|
|
6889
|
+
"url_search_param_absent",
|
|
6888
6890
|
"selector_visible",
|
|
6889
6891
|
"selector_absent",
|
|
6890
6892
|
"selector_count_at_least",
|
|
@@ -7361,6 +7363,13 @@ function normalizeCheck(input, index) {
|
|
|
7361
7363
|
if ((type === "text_visible" || type === "text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7362
7364
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
7363
7365
|
}
|
|
7366
|
+
if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue2(input.param) && !stringValue2(input.search_param) && !stringValue2(input.searchParam) && !stringValue2(input.key)) {
|
|
7367
|
+
throw new Error(`checks[${index}] ${type} requires param.`);
|
|
7368
|
+
}
|
|
7369
|
+
const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
|
|
7370
|
+
if (type === "url_search_param_equals" && expectedValue === void 0) {
|
|
7371
|
+
throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
|
|
7372
|
+
}
|
|
7364
7373
|
if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
|
|
7365
7374
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
7366
7375
|
}
|
|
@@ -7381,6 +7390,8 @@ function normalizeCheck(input, index) {
|
|
|
7381
7390
|
type,
|
|
7382
7391
|
label: stringValue2(input.label),
|
|
7383
7392
|
expected_path: stringValue2(input.expected_path),
|
|
7393
|
+
param: stringValue2(input.param) || stringValue2(input.search_param) || stringValue2(input.searchParam) || stringValue2(input.key),
|
|
7394
|
+
expected_value: expectedValue,
|
|
7384
7395
|
expected_routes: expectedRoutes,
|
|
7385
7396
|
selector: stringValue2(input.selector),
|
|
7386
7397
|
expected_texts: expectedTexts,
|
|
@@ -7633,6 +7644,32 @@ function successfulRoute(route, targetUrl) {
|
|
|
7633
7644
|
const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
|
|
7634
7645
|
return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
|
|
7635
7646
|
}
|
|
7647
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
7648
|
+
if (!value) return void 0;
|
|
7649
|
+
try {
|
|
7650
|
+
return targetUrl ? new URL(value, targetUrl) : new URL(value);
|
|
7651
|
+
} catch {
|
|
7652
|
+
try {
|
|
7653
|
+
return new URL(value);
|
|
7654
|
+
} catch {
|
|
7655
|
+
return void 0;
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7658
|
+
}
|
|
7659
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
7660
|
+
return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
|
|
7661
|
+
}
|
|
7662
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
7663
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
7664
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
7665
|
+
return {
|
|
7666
|
+
viewport: viewport.name,
|
|
7667
|
+
url: url?.href || null,
|
|
7668
|
+
value: values.length ? values[0] : null,
|
|
7669
|
+
values,
|
|
7670
|
+
present: values.length > 0
|
|
7671
|
+
};
|
|
7672
|
+
}
|
|
7636
7673
|
function viewportsForCheck(check, viewports) {
|
|
7637
7674
|
if (!check.viewports?.length) return viewports;
|
|
7638
7675
|
const names = new Set(check.viewports);
|
|
@@ -7670,6 +7707,44 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
7670
7707
|
message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
|
|
7671
7708
|
};
|
|
7672
7709
|
}
|
|
7710
|
+
if (check.type === "url_search_param_equals") {
|
|
7711
|
+
const param = check.param || "";
|
|
7712
|
+
const expectedValue = check.expected_value ?? "";
|
|
7713
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
7714
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
7715
|
+
return {
|
|
7716
|
+
type: check.type,
|
|
7717
|
+
label: checkLabel(check),
|
|
7718
|
+
status: failed.length ? "failed" : "passed",
|
|
7719
|
+
evidence: {
|
|
7720
|
+
param,
|
|
7721
|
+
expected_value: expectedValue,
|
|
7722
|
+
observed_values: observations.map((observation) => observation.value),
|
|
7723
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
7724
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
7725
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
7726
|
+
},
|
|
7727
|
+
message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
|
|
7728
|
+
};
|
|
7729
|
+
}
|
|
7730
|
+
if (check.type === "url_search_param_absent") {
|
|
7731
|
+
const param = check.param || "";
|
|
7732
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
7733
|
+
const failed = observations.filter((observation) => observation.present);
|
|
7734
|
+
return {
|
|
7735
|
+
type: check.type,
|
|
7736
|
+
label: checkLabel(check),
|
|
7737
|
+
status: failed.length ? "failed" : "passed",
|
|
7738
|
+
evidence: {
|
|
7739
|
+
param,
|
|
7740
|
+
observed_values: observations.map((observation) => observation.value),
|
|
7741
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
7742
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
7743
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
7744
|
+
},
|
|
7745
|
+
message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
|
|
7746
|
+
};
|
|
7747
|
+
}
|
|
7673
7748
|
if (check.type === "selector_visible") {
|
|
7674
7749
|
const key = selectorKey(check);
|
|
7675
7750
|
const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
|
|
@@ -8189,6 +8264,29 @@ function routePathMatches(observed, expected, targetUrl) {
|
|
|
8189
8264
|
function routeOk(route, targetUrl) {
|
|
8190
8265
|
return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
|
|
8191
8266
|
}
|
|
8267
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
8268
|
+
if (!value) return null;
|
|
8269
|
+
try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
|
|
8270
|
+
try { return new URL(value); } catch {}
|
|
8271
|
+
return null;
|
|
8272
|
+
}
|
|
8273
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
8274
|
+
return parseEvidenceUrl(viewport && viewport.url, targetUrl)
|
|
8275
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
|
|
8276
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
|
|
8277
|
+
|| parseEvidenceUrl(targetUrl, null);
|
|
8278
|
+
}
|
|
8279
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
8280
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
8281
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
8282
|
+
return {
|
|
8283
|
+
viewport: viewport && viewport.name,
|
|
8284
|
+
url: url ? url.href : null,
|
|
8285
|
+
value: values.length ? values[0] : null,
|
|
8286
|
+
values,
|
|
8287
|
+
present: values.length > 0,
|
|
8288
|
+
};
|
|
8289
|
+
}
|
|
8192
8290
|
function textMatches(sample, check) {
|
|
8193
8291
|
if (check.pattern) {
|
|
8194
8292
|
try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
|
|
@@ -8493,6 +8591,46 @@ function assessProfile(profile, evidence) {
|
|
|
8493
8591
|
});
|
|
8494
8592
|
continue;
|
|
8495
8593
|
}
|
|
8594
|
+
if (check.type === "url_search_param_equals") {
|
|
8595
|
+
const param = check.param || "";
|
|
8596
|
+
const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
|
|
8597
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
8598
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
8599
|
+
checks.push({
|
|
8600
|
+
type: check.type,
|
|
8601
|
+
label: check.label || check.type,
|
|
8602
|
+
status: failed.length ? "failed" : "passed",
|
|
8603
|
+
evidence: {
|
|
8604
|
+
param,
|
|
8605
|
+
expected_value: expectedValue,
|
|
8606
|
+
observed_values: observations.map((observation) => observation.value),
|
|
8607
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
8608
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
8609
|
+
viewports: observations,
|
|
8610
|
+
},
|
|
8611
|
+
message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
|
|
8612
|
+
});
|
|
8613
|
+
continue;
|
|
8614
|
+
}
|
|
8615
|
+
if (check.type === "url_search_param_absent") {
|
|
8616
|
+
const param = check.param || "";
|
|
8617
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
8618
|
+
const failed = observations.filter((observation) => observation.present);
|
|
8619
|
+
checks.push({
|
|
8620
|
+
type: check.type,
|
|
8621
|
+
label: check.label || check.type,
|
|
8622
|
+
status: failed.length ? "failed" : "passed",
|
|
8623
|
+
evidence: {
|
|
8624
|
+
param,
|
|
8625
|
+
observed_values: observations.map((observation) => observation.value),
|
|
8626
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
8627
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
8628
|
+
viewports: observations,
|
|
8629
|
+
},
|
|
8630
|
+
message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
|
|
8631
|
+
});
|
|
8632
|
+
continue;
|
|
8633
|
+
}
|
|
8496
8634
|
if (check.type === "selector_visible") {
|
|
8497
8635
|
const selector = check.selector || "";
|
|
8498
8636
|
const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
|
|
@@ -9373,7 +9511,7 @@ async function frameEvidence(selector) {
|
|
|
9373
9511
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
9374
9512
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
9375
9513
|
const overflowOffenders = [];
|
|
9376
|
-
function
|
|
9514
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
9377
9515
|
let current = element.parentElement;
|
|
9378
9516
|
while (current && current !== body && current !== documentElement) {
|
|
9379
9517
|
const style = window.getComputedStyle(current);
|
|
@@ -9383,6 +9521,11 @@ async function frameEvidence(selector) {
|
|
|
9383
9521
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
9384
9522
|
if (contained) return true;
|
|
9385
9523
|
}
|
|
9524
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
9525
|
+
const currentRect = current.getBoundingClientRect();
|
|
9526
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
9527
|
+
if (clippedByAncestor) return true;
|
|
9528
|
+
}
|
|
9386
9529
|
current = current.parentElement;
|
|
9387
9530
|
}
|
|
9388
9531
|
return false;
|
|
@@ -9396,7 +9539,7 @@ async function frameEvidence(selector) {
|
|
|
9396
9539
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
9397
9540
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
9398
9541
|
if (overflow <= 0.5) continue;
|
|
9399
|
-
if (
|
|
9542
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
9400
9543
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
9401
9544
|
const id = element.id ? "#" + element.id : "";
|
|
9402
9545
|
const className = typeof element.className === "string"
|
|
@@ -9776,7 +9919,7 @@ async function captureViewport(viewport) {
|
|
|
9776
9919
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
9777
9920
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
9778
9921
|
const overflowOffenders = [];
|
|
9779
|
-
function
|
|
9922
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
9780
9923
|
let current = element.parentElement;
|
|
9781
9924
|
while (current && current !== body && current !== documentElement) {
|
|
9782
9925
|
const style = window.getComputedStyle(current);
|
|
@@ -9786,6 +9929,11 @@ async function captureViewport(viewport) {
|
|
|
9786
9929
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
9787
9930
|
if (contained) return true;
|
|
9788
9931
|
}
|
|
9932
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
9933
|
+
const currentRect = current.getBoundingClientRect();
|
|
9934
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
9935
|
+
if (clippedByAncestor) return true;
|
|
9936
|
+
}
|
|
9789
9937
|
current = current.parentElement;
|
|
9790
9938
|
}
|
|
9791
9939
|
return false;
|
|
@@ -9799,7 +9947,7 @@ async function captureViewport(viewport) {
|
|
|
9799
9947
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
9800
9948
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
9801
9949
|
if (overflow <= 0.5) continue;
|
|
9802
|
-
if (
|
|
9950
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
9803
9951
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
9804
9952
|
const id = element.id ? "#" + element.id : "";
|
|
9805
9953
|
const className = typeof element.className === "string"
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8726,6 +8726,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
|
|
|
8726
8726
|
];
|
|
8727
8727
|
var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
8728
8728
|
"route_loaded",
|
|
8729
|
+
"url_search_param_equals",
|
|
8730
|
+
"url_search_param_absent",
|
|
8729
8731
|
"selector_visible",
|
|
8730
8732
|
"selector_absent",
|
|
8731
8733
|
"selector_count_at_least",
|
|
@@ -9202,6 +9204,13 @@ function normalizeCheck(input, index) {
|
|
|
9202
9204
|
if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
9203
9205
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
9204
9206
|
}
|
|
9207
|
+
if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue5(input.param) && !stringValue5(input.search_param) && !stringValue5(input.searchParam) && !stringValue5(input.key)) {
|
|
9208
|
+
throw new Error(`checks[${index}] ${type} requires param.`);
|
|
9209
|
+
}
|
|
9210
|
+
const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
|
|
9211
|
+
if (type === "url_search_param_equals" && expectedValue === void 0) {
|
|
9212
|
+
throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
|
|
9213
|
+
}
|
|
9205
9214
|
if (type === "selector_count_at_least" && numberValue3(input.min_count) === void 0) {
|
|
9206
9215
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
9207
9216
|
}
|
|
@@ -9222,6 +9231,8 @@ function normalizeCheck(input, index) {
|
|
|
9222
9231
|
type,
|
|
9223
9232
|
label: stringValue5(input.label),
|
|
9224
9233
|
expected_path: stringValue5(input.expected_path),
|
|
9234
|
+
param: stringValue5(input.param) || stringValue5(input.search_param) || stringValue5(input.searchParam) || stringValue5(input.key),
|
|
9235
|
+
expected_value: expectedValue,
|
|
9225
9236
|
expected_routes: expectedRoutes,
|
|
9226
9237
|
selector: stringValue5(input.selector),
|
|
9227
9238
|
expected_texts: expectedTexts,
|
|
@@ -9474,6 +9485,32 @@ function successfulRoute(route, targetUrl) {
|
|
|
9474
9485
|
const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
|
|
9475
9486
|
return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
|
|
9476
9487
|
}
|
|
9488
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
9489
|
+
if (!value) return void 0;
|
|
9490
|
+
try {
|
|
9491
|
+
return targetUrl ? new URL(value, targetUrl) : new URL(value);
|
|
9492
|
+
} catch {
|
|
9493
|
+
try {
|
|
9494
|
+
return new URL(value);
|
|
9495
|
+
} catch {
|
|
9496
|
+
return void 0;
|
|
9497
|
+
}
|
|
9498
|
+
}
|
|
9499
|
+
}
|
|
9500
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
9501
|
+
return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
|
|
9502
|
+
}
|
|
9503
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
9504
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
9505
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
9506
|
+
return {
|
|
9507
|
+
viewport: viewport.name,
|
|
9508
|
+
url: url?.href || null,
|
|
9509
|
+
value: values.length ? values[0] : null,
|
|
9510
|
+
values,
|
|
9511
|
+
present: values.length > 0
|
|
9512
|
+
};
|
|
9513
|
+
}
|
|
9477
9514
|
function viewportsForCheck(check, viewports) {
|
|
9478
9515
|
if (!check.viewports?.length) return viewports;
|
|
9479
9516
|
const names = new Set(check.viewports);
|
|
@@ -9511,6 +9548,44 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
9511
9548
|
message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
|
|
9512
9549
|
};
|
|
9513
9550
|
}
|
|
9551
|
+
if (check.type === "url_search_param_equals") {
|
|
9552
|
+
const param = check.param || "";
|
|
9553
|
+
const expectedValue = check.expected_value ?? "";
|
|
9554
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
9555
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
9556
|
+
return {
|
|
9557
|
+
type: check.type,
|
|
9558
|
+
label: checkLabel(check),
|
|
9559
|
+
status: failed.length ? "failed" : "passed",
|
|
9560
|
+
evidence: {
|
|
9561
|
+
param,
|
|
9562
|
+
expected_value: expectedValue,
|
|
9563
|
+
observed_values: observations.map((observation) => observation.value),
|
|
9564
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
9565
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
9566
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
9567
|
+
},
|
|
9568
|
+
message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
|
|
9569
|
+
};
|
|
9570
|
+
}
|
|
9571
|
+
if (check.type === "url_search_param_absent") {
|
|
9572
|
+
const param = check.param || "";
|
|
9573
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
9574
|
+
const failed = observations.filter((observation) => observation.present);
|
|
9575
|
+
return {
|
|
9576
|
+
type: check.type,
|
|
9577
|
+
label: checkLabel(check),
|
|
9578
|
+
status: failed.length ? "failed" : "passed",
|
|
9579
|
+
evidence: {
|
|
9580
|
+
param,
|
|
9581
|
+
observed_values: observations.map((observation) => observation.value),
|
|
9582
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
9583
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
9584
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
9585
|
+
},
|
|
9586
|
+
message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
|
|
9587
|
+
};
|
|
9588
|
+
}
|
|
9514
9589
|
if (check.type === "selector_visible") {
|
|
9515
9590
|
const key = selectorKey(check);
|
|
9516
9591
|
const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
|
|
@@ -10046,6 +10121,29 @@ function routePathMatches(observed, expected, targetUrl) {
|
|
|
10046
10121
|
function routeOk(route, targetUrl) {
|
|
10047
10122
|
return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
|
|
10048
10123
|
}
|
|
10124
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
10125
|
+
if (!value) return null;
|
|
10126
|
+
try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
|
|
10127
|
+
try { return new URL(value); } catch {}
|
|
10128
|
+
return null;
|
|
10129
|
+
}
|
|
10130
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
10131
|
+
return parseEvidenceUrl(viewport && viewport.url, targetUrl)
|
|
10132
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
|
|
10133
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
|
|
10134
|
+
|| parseEvidenceUrl(targetUrl, null);
|
|
10135
|
+
}
|
|
10136
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
10137
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
10138
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
10139
|
+
return {
|
|
10140
|
+
viewport: viewport && viewport.name,
|
|
10141
|
+
url: url ? url.href : null,
|
|
10142
|
+
value: values.length ? values[0] : null,
|
|
10143
|
+
values,
|
|
10144
|
+
present: values.length > 0,
|
|
10145
|
+
};
|
|
10146
|
+
}
|
|
10049
10147
|
function textMatches(sample, check) {
|
|
10050
10148
|
if (check.pattern) {
|
|
10051
10149
|
try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
|
|
@@ -10350,6 +10448,46 @@ function assessProfile(profile, evidence) {
|
|
|
10350
10448
|
});
|
|
10351
10449
|
continue;
|
|
10352
10450
|
}
|
|
10451
|
+
if (check.type === "url_search_param_equals") {
|
|
10452
|
+
const param = check.param || "";
|
|
10453
|
+
const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
|
|
10454
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
10455
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
10456
|
+
checks.push({
|
|
10457
|
+
type: check.type,
|
|
10458
|
+
label: check.label || check.type,
|
|
10459
|
+
status: failed.length ? "failed" : "passed",
|
|
10460
|
+
evidence: {
|
|
10461
|
+
param,
|
|
10462
|
+
expected_value: expectedValue,
|
|
10463
|
+
observed_values: observations.map((observation) => observation.value),
|
|
10464
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
10465
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
10466
|
+
viewports: observations,
|
|
10467
|
+
},
|
|
10468
|
+
message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
|
|
10469
|
+
});
|
|
10470
|
+
continue;
|
|
10471
|
+
}
|
|
10472
|
+
if (check.type === "url_search_param_absent") {
|
|
10473
|
+
const param = check.param || "";
|
|
10474
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
10475
|
+
const failed = observations.filter((observation) => observation.present);
|
|
10476
|
+
checks.push({
|
|
10477
|
+
type: check.type,
|
|
10478
|
+
label: check.label || check.type,
|
|
10479
|
+
status: failed.length ? "failed" : "passed",
|
|
10480
|
+
evidence: {
|
|
10481
|
+
param,
|
|
10482
|
+
observed_values: observations.map((observation) => observation.value),
|
|
10483
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
10484
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
10485
|
+
viewports: observations,
|
|
10486
|
+
},
|
|
10487
|
+
message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
|
|
10488
|
+
});
|
|
10489
|
+
continue;
|
|
10490
|
+
}
|
|
10353
10491
|
if (check.type === "selector_visible") {
|
|
10354
10492
|
const selector = check.selector || "";
|
|
10355
10493
|
const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
|
|
@@ -11230,7 +11368,7 @@ async function frameEvidence(selector) {
|
|
|
11230
11368
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
11231
11369
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
11232
11370
|
const overflowOffenders = [];
|
|
11233
|
-
function
|
|
11371
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
11234
11372
|
let current = element.parentElement;
|
|
11235
11373
|
while (current && current !== body && current !== documentElement) {
|
|
11236
11374
|
const style = window.getComputedStyle(current);
|
|
@@ -11240,6 +11378,11 @@ async function frameEvidence(selector) {
|
|
|
11240
11378
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
11241
11379
|
if (contained) return true;
|
|
11242
11380
|
}
|
|
11381
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
11382
|
+
const currentRect = current.getBoundingClientRect();
|
|
11383
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
11384
|
+
if (clippedByAncestor) return true;
|
|
11385
|
+
}
|
|
11243
11386
|
current = current.parentElement;
|
|
11244
11387
|
}
|
|
11245
11388
|
return false;
|
|
@@ -11253,7 +11396,7 @@ async function frameEvidence(selector) {
|
|
|
11253
11396
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
11254
11397
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
11255
11398
|
if (overflow <= 0.5) continue;
|
|
11256
|
-
if (
|
|
11399
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
11257
11400
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
11258
11401
|
const id = element.id ? "#" + element.id : "";
|
|
11259
11402
|
const className = typeof element.className === "string"
|
|
@@ -11633,7 +11776,7 @@ async function captureViewport(viewport) {
|
|
|
11633
11776
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
11634
11777
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
11635
11778
|
const overflowOffenders = [];
|
|
11636
|
-
function
|
|
11779
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
11637
11780
|
let current = element.parentElement;
|
|
11638
11781
|
while (current && current !== body && current !== documentElement) {
|
|
11639
11782
|
const style = window.getComputedStyle(current);
|
|
@@ -11643,6 +11786,11 @@ async function captureViewport(viewport) {
|
|
|
11643
11786
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
11644
11787
|
if (contained) return true;
|
|
11645
11788
|
}
|
|
11789
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
11790
|
+
const currentRect = current.getBoundingClientRect();
|
|
11791
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
11792
|
+
if (clippedByAncestor) return true;
|
|
11793
|
+
}
|
|
11646
11794
|
current = current.parentElement;
|
|
11647
11795
|
}
|
|
11648
11796
|
return false;
|
|
@@ -11656,7 +11804,7 @@ async function captureViewport(viewport) {
|
|
|
11656
11804
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
11657
11805
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
11658
11806
|
if (overflow <= 0.5) continue;
|
|
11659
|
-
if (
|
|
11807
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
11660
11808
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
11661
11809
|
const id = element.id ? "#" + element.id : "";
|
|
11662
11810
|
const className = typeof element.className === "string"
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
resolveRiddleProofProfileTimeoutSec,
|
|
59
59
|
slugifyRiddleProofProfileName,
|
|
60
60
|
summarizeRiddleProofProfileResult
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-2JFDTCIC.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -55,6 +55,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
|
|
|
55
55
|
];
|
|
56
56
|
var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
57
57
|
"route_loaded",
|
|
58
|
+
"url_search_param_equals",
|
|
59
|
+
"url_search_param_absent",
|
|
58
60
|
"selector_visible",
|
|
59
61
|
"selector_absent",
|
|
60
62
|
"selector_count_at_least",
|
|
@@ -531,6 +533,13 @@ function normalizeCheck(input, index) {
|
|
|
531
533
|
if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
532
534
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
533
535
|
}
|
|
536
|
+
if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
|
|
537
|
+
throw new Error(`checks[${index}] ${type} requires param.`);
|
|
538
|
+
}
|
|
539
|
+
const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
|
|
540
|
+
if (type === "url_search_param_equals" && expectedValue === void 0) {
|
|
541
|
+
throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
|
|
542
|
+
}
|
|
534
543
|
if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
|
|
535
544
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
536
545
|
}
|
|
@@ -551,6 +560,8 @@ function normalizeCheck(input, index) {
|
|
|
551
560
|
type,
|
|
552
561
|
label: stringValue(input.label),
|
|
553
562
|
expected_path: stringValue(input.expected_path),
|
|
563
|
+
param: stringValue(input.param) || stringValue(input.search_param) || stringValue(input.searchParam) || stringValue(input.key),
|
|
564
|
+
expected_value: expectedValue,
|
|
554
565
|
expected_routes: expectedRoutes,
|
|
555
566
|
selector: stringValue(input.selector),
|
|
556
567
|
expected_texts: expectedTexts,
|
|
@@ -803,6 +814,32 @@ function successfulRoute(route, targetUrl) {
|
|
|
803
814
|
const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
|
|
804
815
|
return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
|
|
805
816
|
}
|
|
817
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
818
|
+
if (!value) return void 0;
|
|
819
|
+
try {
|
|
820
|
+
return targetUrl ? new URL(value, targetUrl) : new URL(value);
|
|
821
|
+
} catch {
|
|
822
|
+
try {
|
|
823
|
+
return new URL(value);
|
|
824
|
+
} catch {
|
|
825
|
+
return void 0;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
830
|
+
return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
|
|
831
|
+
}
|
|
832
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
833
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
834
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
835
|
+
return {
|
|
836
|
+
viewport: viewport.name,
|
|
837
|
+
url: url?.href || null,
|
|
838
|
+
value: values.length ? values[0] : null,
|
|
839
|
+
values,
|
|
840
|
+
present: values.length > 0
|
|
841
|
+
};
|
|
842
|
+
}
|
|
806
843
|
function viewportsForCheck(check, viewports) {
|
|
807
844
|
if (!check.viewports?.length) return viewports;
|
|
808
845
|
const names = new Set(check.viewports);
|
|
@@ -840,6 +877,44 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
840
877
|
message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
|
|
841
878
|
};
|
|
842
879
|
}
|
|
880
|
+
if (check.type === "url_search_param_equals") {
|
|
881
|
+
const param = check.param || "";
|
|
882
|
+
const expectedValue = check.expected_value ?? "";
|
|
883
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
884
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
885
|
+
return {
|
|
886
|
+
type: check.type,
|
|
887
|
+
label: checkLabel(check),
|
|
888
|
+
status: failed.length ? "failed" : "passed",
|
|
889
|
+
evidence: {
|
|
890
|
+
param,
|
|
891
|
+
expected_value: expectedValue,
|
|
892
|
+
observed_values: observations.map((observation) => observation.value),
|
|
893
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
894
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
895
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
896
|
+
},
|
|
897
|
+
message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
if (check.type === "url_search_param_absent") {
|
|
901
|
+
const param = check.param || "";
|
|
902
|
+
const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
903
|
+
const failed = observations.filter((observation) => observation.present);
|
|
904
|
+
return {
|
|
905
|
+
type: check.type,
|
|
906
|
+
label: checkLabel(check),
|
|
907
|
+
status: failed.length ? "failed" : "passed",
|
|
908
|
+
evidence: {
|
|
909
|
+
param,
|
|
910
|
+
observed_values: observations.map((observation) => observation.value),
|
|
911
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
912
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
913
|
+
viewports: observations.map((observation) => toJsonValue(observation))
|
|
914
|
+
},
|
|
915
|
+
message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
|
|
916
|
+
};
|
|
917
|
+
}
|
|
843
918
|
if (check.type === "selector_visible") {
|
|
844
919
|
const key = selectorKey(check);
|
|
845
920
|
const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
|
|
@@ -1375,6 +1450,29 @@ function routePathMatches(observed, expected, targetUrl) {
|
|
|
1375
1450
|
function routeOk(route, targetUrl) {
|
|
1376
1451
|
return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
|
|
1377
1452
|
}
|
|
1453
|
+
function parseEvidenceUrl(value, targetUrl) {
|
|
1454
|
+
if (!value) return null;
|
|
1455
|
+
try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
|
|
1456
|
+
try { return new URL(value); } catch {}
|
|
1457
|
+
return null;
|
|
1458
|
+
}
|
|
1459
|
+
function observedUrlForViewport(viewport, targetUrl) {
|
|
1460
|
+
return parseEvidenceUrl(viewport && viewport.url, targetUrl)
|
|
1461
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
|
|
1462
|
+
|| parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
|
|
1463
|
+
|| parseEvidenceUrl(targetUrl, null);
|
|
1464
|
+
}
|
|
1465
|
+
function searchParamObservation(viewport, targetUrl, param) {
|
|
1466
|
+
const url = observedUrlForViewport(viewport, targetUrl);
|
|
1467
|
+
const values = url ? url.searchParams.getAll(param) : [];
|
|
1468
|
+
return {
|
|
1469
|
+
viewport: viewport && viewport.name,
|
|
1470
|
+
url: url ? url.href : null,
|
|
1471
|
+
value: values.length ? values[0] : null,
|
|
1472
|
+
values,
|
|
1473
|
+
present: values.length > 0,
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1378
1476
|
function textMatches(sample, check) {
|
|
1379
1477
|
if (check.pattern) {
|
|
1380
1478
|
try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
|
|
@@ -1679,6 +1777,46 @@ function assessProfile(profile, evidence) {
|
|
|
1679
1777
|
});
|
|
1680
1778
|
continue;
|
|
1681
1779
|
}
|
|
1780
|
+
if (check.type === "url_search_param_equals") {
|
|
1781
|
+
const param = check.param || "";
|
|
1782
|
+
const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
|
|
1783
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
1784
|
+
const failed = observations.filter((observation) => observation.value !== expectedValue);
|
|
1785
|
+
checks.push({
|
|
1786
|
+
type: check.type,
|
|
1787
|
+
label: check.label || check.type,
|
|
1788
|
+
status: failed.length ? "failed" : "passed",
|
|
1789
|
+
evidence: {
|
|
1790
|
+
param,
|
|
1791
|
+
expected_value: expectedValue,
|
|
1792
|
+
observed_values: observations.map((observation) => observation.value),
|
|
1793
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
1794
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
1795
|
+
viewports: observations,
|
|
1796
|
+
},
|
|
1797
|
+
message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
|
|
1798
|
+
});
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
if (check.type === "url_search_param_absent") {
|
|
1802
|
+
const param = check.param || "";
|
|
1803
|
+
const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
|
|
1804
|
+
const failed = observations.filter((observation) => observation.present);
|
|
1805
|
+
checks.push({
|
|
1806
|
+
type: check.type,
|
|
1807
|
+
label: check.label || check.type,
|
|
1808
|
+
status: failed.length ? "failed" : "passed",
|
|
1809
|
+
evidence: {
|
|
1810
|
+
param,
|
|
1811
|
+
observed_values: observations.map((observation) => observation.value),
|
|
1812
|
+
observed_all_values: observations.map((observation) => observation.values),
|
|
1813
|
+
observed_urls: observations.map((observation) => observation.url),
|
|
1814
|
+
viewports: observations,
|
|
1815
|
+
},
|
|
1816
|
+
message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
|
|
1817
|
+
});
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1682
1820
|
if (check.type === "selector_visible") {
|
|
1683
1821
|
const selector = check.selector || "";
|
|
1684
1822
|
const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
|
|
@@ -2559,7 +2697,7 @@ async function frameEvidence(selector) {
|
|
|
2559
2697
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
2560
2698
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
2561
2699
|
const overflowOffenders = [];
|
|
2562
|
-
function
|
|
2700
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
2563
2701
|
let current = element.parentElement;
|
|
2564
2702
|
while (current && current !== body && current !== documentElement) {
|
|
2565
2703
|
const style = window.getComputedStyle(current);
|
|
@@ -2569,6 +2707,11 @@ async function frameEvidence(selector) {
|
|
|
2569
2707
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
2570
2708
|
if (contained) return true;
|
|
2571
2709
|
}
|
|
2710
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
2711
|
+
const currentRect = current.getBoundingClientRect();
|
|
2712
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
2713
|
+
if (clippedByAncestor) return true;
|
|
2714
|
+
}
|
|
2572
2715
|
current = current.parentElement;
|
|
2573
2716
|
}
|
|
2574
2717
|
return false;
|
|
@@ -2582,7 +2725,7 @@ async function frameEvidence(selector) {
|
|
|
2582
2725
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
2583
2726
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
2584
2727
|
if (overflow <= 0.5) continue;
|
|
2585
|
-
if (
|
|
2728
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
2586
2729
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
2587
2730
|
const id = element.id ? "#" + element.id : "";
|
|
2588
2731
|
const className = typeof element.className === "string"
|
|
@@ -2962,7 +3105,7 @@ async function captureViewport(viewport) {
|
|
|
2962
3105
|
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
2963
3106
|
const viewportWidth = clientWidth || window.innerWidth;
|
|
2964
3107
|
const overflowOffenders = [];
|
|
2965
|
-
function
|
|
3108
|
+
function isHandledByHorizontalOverflowAncestor(element, rect) {
|
|
2966
3109
|
let current = element.parentElement;
|
|
2967
3110
|
while (current && current !== body && current !== documentElement) {
|
|
2968
3111
|
const style = window.getComputedStyle(current);
|
|
@@ -2972,6 +3115,11 @@ async function captureViewport(viewport) {
|
|
|
2972
3115
|
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
2973
3116
|
if (contained) return true;
|
|
2974
3117
|
}
|
|
3118
|
+
if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
|
|
3119
|
+
const currentRect = current.getBoundingClientRect();
|
|
3120
|
+
const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
|
|
3121
|
+
if (clippedByAncestor) return true;
|
|
3122
|
+
}
|
|
2975
3123
|
current = current.parentElement;
|
|
2976
3124
|
}
|
|
2977
3125
|
return false;
|
|
@@ -2985,7 +3133,7 @@ async function captureViewport(viewport) {
|
|
|
2985
3133
|
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
2986
3134
|
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
2987
3135
|
if (overflow <= 0.5) continue;
|
|
2988
|
-
if (
|
|
3136
|
+
if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
|
|
2989
3137
|
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
2990
3138
|
const id = element.id ? "#" + element.id : "";
|
|
2991
3139
|
const className = typeof element.className === "string"
|
package/dist/profile.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
|
|
|
4
4
|
declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
|
|
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
|
-
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
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_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
8
|
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "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];
|
|
@@ -88,6 +88,8 @@ interface RiddleProofProfileCheck {
|
|
|
88
88
|
type: RiddleProofProfileCheckType;
|
|
89
89
|
label?: string;
|
|
90
90
|
expected_path?: string;
|
|
91
|
+
param?: string;
|
|
92
|
+
expected_value?: string;
|
|
91
93
|
expected_routes?: RiddleProofProfileRouteInventoryRoute[];
|
|
92
94
|
selector?: string;
|
|
93
95
|
expected_texts?: string[];
|
package/dist/profile.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
|
|
|
4
4
|
declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
|
|
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
|
-
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
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_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
8
|
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "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];
|
|
@@ -88,6 +88,8 @@ interface RiddleProofProfileCheck {
|
|
|
88
88
|
type: RiddleProofProfileCheckType;
|
|
89
89
|
label?: string;
|
|
90
90
|
expected_path?: string;
|
|
91
|
+
param?: string;
|
|
92
|
+
expected_value?: string;
|
|
91
93
|
expected_routes?: RiddleProofProfileRouteInventoryRoute[];
|
|
92
94
|
selector?: string;
|
|
93
95
|
expected_texts?: string[];
|
package/dist/profile.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resolveRiddleProofProfileTimeoutSec,
|
|
20
20
|
slugifyRiddleProofProfileName,
|
|
21
21
|
summarizeRiddleProofProfileResult
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2JFDTCIC.js";
|
|
23
23
|
export {
|
|
24
24
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
25
25
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|