@riddledc/riddle-proof 0.7.36 → 0.7.38
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 +26 -1
- package/dist/{chunk-VEK6QHPE.js → chunk-ZB7AFRN3.js} +287 -2
- package/dist/cli.cjs +287 -2
- package/dist/cli.js +1 -1
- package/dist/index.cjs +287 -2
- package/dist/index.js +1 -1
- package/dist/profile.cjs +287 -2
- package/dist/profile.d.cts +2 -1
- package/dist/profile.d.ts +2 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -6888,6 +6888,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
6888
6888
|
"selector_visible",
|
|
6889
6889
|
"selector_count_at_least",
|
|
6890
6890
|
"selector_text_order",
|
|
6891
|
+
"frame_text_visible",
|
|
6892
|
+
"frame_no_horizontal_overflow",
|
|
6891
6893
|
"text_visible",
|
|
6892
6894
|
"text_absent",
|
|
6893
6895
|
"route_inventory",
|
|
@@ -7186,6 +7188,12 @@ function normalizeCheck(input, index) {
|
|
|
7186
7188
|
if ((type === "selector_visible" || type === "selector_count_at_least") && !stringValue2(input.selector)) {
|
|
7187
7189
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
7188
7190
|
}
|
|
7191
|
+
if ((type === "frame_text_visible" || type === "frame_no_horizontal_overflow") && !stringValue2(input.selector)) {
|
|
7192
|
+
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
7193
|
+
}
|
|
7194
|
+
if (type === "frame_text_visible" && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7195
|
+
throw new Error(`checks[${index}] frame_text_visible requires text or pattern.`);
|
|
7196
|
+
}
|
|
7189
7197
|
if ((type === "text_visible" || type === "text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7190
7198
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
7191
7199
|
}
|
|
@@ -7336,6 +7344,22 @@ function textOrderMatch(texts, expectedTexts) {
|
|
|
7336
7344
|
}
|
|
7337
7345
|
return { matched: true, positions };
|
|
7338
7346
|
}
|
|
7347
|
+
function frameEvidenceForSelector(viewport, selector) {
|
|
7348
|
+
const container = viewport.frames?.[selector];
|
|
7349
|
+
if (!isRecord(container)) return [];
|
|
7350
|
+
const frames = Array.isArray(container.frames) ? container.frames : [];
|
|
7351
|
+
return frames.filter((frame) => isRecord(frame));
|
|
7352
|
+
}
|
|
7353
|
+
function frameTextSample(frame) {
|
|
7354
|
+
const parts = [
|
|
7355
|
+
frame.title,
|
|
7356
|
+
frame.text_sample,
|
|
7357
|
+
frame.body_text_sample,
|
|
7358
|
+
frame.body_text,
|
|
7359
|
+
frame.text
|
|
7360
|
+
];
|
|
7361
|
+
return parts.map((part) => String(part || "")).filter(Boolean).join(" ");
|
|
7362
|
+
}
|
|
7339
7363
|
function summarizeRouteInventory(viewport, inventory) {
|
|
7340
7364
|
const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
|
|
7341
7365
|
const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
|
|
@@ -7500,6 +7524,67 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
7500
7524
|
message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
|
|
7501
7525
|
};
|
|
7502
7526
|
}
|
|
7527
|
+
if (check.type === "frame_text_visible") {
|
|
7528
|
+
const key = selectorKey(check);
|
|
7529
|
+
const results = viewports.map((viewport) => {
|
|
7530
|
+
const frames = frameEvidenceForSelector(viewport, key);
|
|
7531
|
+
const matches = frames.map((frame, index) => ({ index, frame, matched: matchText(frameTextSample(frame), check) })).filter((item) => item.matched);
|
|
7532
|
+
return {
|
|
7533
|
+
viewport: viewport.name,
|
|
7534
|
+
frame_count: frames.length,
|
|
7535
|
+
matched_count: matches.length,
|
|
7536
|
+
matched: matches.length > 0,
|
|
7537
|
+
urls: frames.map((frame) => String(frame.url || "")).filter(Boolean).slice(0, 10),
|
|
7538
|
+
samples: matches.map((item) => frameTextSample(item.frame).replace(/\s+/g, " ").trim().slice(0, 240)).slice(0, 3)
|
|
7539
|
+
};
|
|
7540
|
+
});
|
|
7541
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
7542
|
+
return {
|
|
7543
|
+
type: check.type,
|
|
7544
|
+
label: checkLabel(check),
|
|
7545
|
+
status: failed ? "failed" : "passed",
|
|
7546
|
+
evidence: {
|
|
7547
|
+
selector: key,
|
|
7548
|
+
text: check.text || null,
|
|
7549
|
+
pattern: check.pattern || null,
|
|
7550
|
+
viewports: results.map((result) => toJsonValue(result))
|
|
7551
|
+
},
|
|
7552
|
+
message: failed ? `Frame selector ${key} did not contain expected text in ${failed} viewport(s).` : void 0
|
|
7553
|
+
};
|
|
7554
|
+
}
|
|
7555
|
+
if (check.type === "frame_no_horizontal_overflow") {
|
|
7556
|
+
const key = selectorKey(check);
|
|
7557
|
+
const maxOverflow = check.max_overflow_px ?? 4;
|
|
7558
|
+
const results = viewports.map((viewport) => {
|
|
7559
|
+
const frames = frameEvidenceForSelector(viewport, key);
|
|
7560
|
+
const frameOverflows = frames.map((frame, index) => ({
|
|
7561
|
+
index,
|
|
7562
|
+
url: String(frame.url || ""),
|
|
7563
|
+
overflow_px: horizontalBoundsOverflowPx(frame),
|
|
7564
|
+
offender_count: boundsOffendersForEvidence(frame).length
|
|
7565
|
+
}));
|
|
7566
|
+
const maxFrameOverflow = frameOverflows.reduce((max, frame) => Math.max(max, frame.overflow_px), 0);
|
|
7567
|
+
return {
|
|
7568
|
+
viewport: viewport.name,
|
|
7569
|
+
frame_count: frames.length,
|
|
7570
|
+
max_overflow_px: roundPixels(maxFrameOverflow),
|
|
7571
|
+
failed_frame_count: frameOverflows.filter((frame) => frame.overflow_px > maxOverflow).length,
|
|
7572
|
+
frames: frameOverflows.map((frame) => toJsonValue(frame))
|
|
7573
|
+
};
|
|
7574
|
+
});
|
|
7575
|
+
const failed = results.filter((result) => result.frame_count < 1 || result.failed_frame_count > 0).length;
|
|
7576
|
+
return {
|
|
7577
|
+
type: check.type,
|
|
7578
|
+
label: checkLabel(check),
|
|
7579
|
+
status: failed ? "failed" : "passed",
|
|
7580
|
+
evidence: {
|
|
7581
|
+
selector: key,
|
|
7582
|
+
max_overflow_px: maxOverflow,
|
|
7583
|
+
viewports: results.map((result) => toJsonValue(result))
|
|
7584
|
+
},
|
|
7585
|
+
message: failed ? `Frame selector ${key} overflow exceeded ${maxOverflow}px or was missing in ${failed} viewport(s).` : void 0
|
|
7586
|
+
};
|
|
7587
|
+
}
|
|
7503
7588
|
if (check.type === "text_visible" || check.type === "text_absent") {
|
|
7504
7589
|
const key = textKey(check);
|
|
7505
7590
|
const expectedVisible = check.type === "text_visible";
|
|
@@ -7859,6 +7944,21 @@ function textOrderMatch(texts, expectedTexts) {
|
|
|
7859
7944
|
}
|
|
7860
7945
|
return { matched: true, positions };
|
|
7861
7946
|
}
|
|
7947
|
+
function frameEvidenceForSelector(viewport, selector) {
|
|
7948
|
+
const container = viewport.frames && viewport.frames[selector || ""];
|
|
7949
|
+
if (!container || typeof container !== "object" || Array.isArray(container)) return [];
|
|
7950
|
+
const frames = Array.isArray(container.frames) ? container.frames : [];
|
|
7951
|
+
return frames.filter((frame) => frame && typeof frame === "object" && !Array.isArray(frame));
|
|
7952
|
+
}
|
|
7953
|
+
function frameTextSample(frame) {
|
|
7954
|
+
return [
|
|
7955
|
+
frame && frame.title,
|
|
7956
|
+
frame && frame.text_sample,
|
|
7957
|
+
frame && frame.body_text_sample,
|
|
7958
|
+
frame && frame.body_text,
|
|
7959
|
+
frame && frame.text,
|
|
7960
|
+
].map((part) => String(part || "")).filter(Boolean).join(" ");
|
|
7961
|
+
}
|
|
7862
7962
|
function summarizeRouteInventory(viewport, inventory) {
|
|
7863
7963
|
const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
|
|
7864
7964
|
const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
|
|
@@ -8105,6 +8205,62 @@ function assessProfile(profile, evidence) {
|
|
|
8105
8205
|
});
|
|
8106
8206
|
continue;
|
|
8107
8207
|
}
|
|
8208
|
+
if (check.type === "frame_text_visible") {
|
|
8209
|
+
const selector = check.selector || "";
|
|
8210
|
+
const results = viewports.map((viewport) => {
|
|
8211
|
+
const frames = frameEvidenceForSelector(viewport, selector);
|
|
8212
|
+
const matches = frames
|
|
8213
|
+
.map((frame, index) => ({ index, frame, matched: textMatches(frameTextSample(frame), check) }))
|
|
8214
|
+
.filter((item) => item.matched);
|
|
8215
|
+
return {
|
|
8216
|
+
viewport: viewport.name,
|
|
8217
|
+
frame_count: frames.length,
|
|
8218
|
+
matched_count: matches.length,
|
|
8219
|
+
matched: matches.length > 0,
|
|
8220
|
+
urls: frames.map((frame) => String(frame.url || "")).filter(Boolean).slice(0, 10),
|
|
8221
|
+
samples: matches.map((item) => frameTextSample(item.frame).replace(/\s+/g, " ").trim().slice(0, 240)).slice(0, 3),
|
|
8222
|
+
};
|
|
8223
|
+
});
|
|
8224
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
8225
|
+
checks.push({
|
|
8226
|
+
type: check.type,
|
|
8227
|
+
label: check.label || check.type,
|
|
8228
|
+
status: failed ? "failed" : "passed",
|
|
8229
|
+
evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
|
|
8230
|
+
message: failed ? "Frame selector " + selector + " did not contain expected text in " + failed + " viewport(s)." : undefined,
|
|
8231
|
+
});
|
|
8232
|
+
continue;
|
|
8233
|
+
}
|
|
8234
|
+
if (check.type === "frame_no_horizontal_overflow") {
|
|
8235
|
+
const selector = check.selector || "";
|
|
8236
|
+
const maxOverflow = check.max_overflow_px == null ? 4 : check.max_overflow_px;
|
|
8237
|
+
const results = viewports.map((viewport) => {
|
|
8238
|
+
const frames = frameEvidenceForSelector(viewport, selector);
|
|
8239
|
+
const frameOverflows = frames.map((frame, index) => ({
|
|
8240
|
+
index,
|
|
8241
|
+
url: String(frame.url || ""),
|
|
8242
|
+
overflow_px: horizontalBoundsOverflowPx(frame),
|
|
8243
|
+
offender_count: boundsOffendersForEvidence(frame).length,
|
|
8244
|
+
}));
|
|
8245
|
+
const maxFrameOverflow = frameOverflows.reduce((max, frame) => Math.max(max, frame.overflow_px), 0);
|
|
8246
|
+
return {
|
|
8247
|
+
viewport: viewport.name,
|
|
8248
|
+
frame_count: frames.length,
|
|
8249
|
+
max_overflow_px: roundPixels(maxFrameOverflow),
|
|
8250
|
+
failed_frame_count: frameOverflows.filter((frame) => frame.overflow_px > maxOverflow).length,
|
|
8251
|
+
frames: frameOverflows,
|
|
8252
|
+
};
|
|
8253
|
+
});
|
|
8254
|
+
const failed = results.filter((result) => result.frame_count < 1 || result.failed_frame_count > 0).length;
|
|
8255
|
+
checks.push({
|
|
8256
|
+
type: check.type,
|
|
8257
|
+
label: check.label || check.type,
|
|
8258
|
+
status: failed ? "failed" : "passed",
|
|
8259
|
+
evidence: { selector, max_overflow_px: maxOverflow, viewports: results },
|
|
8260
|
+
message: failed ? "Frame selector " + selector + " overflow exceeded " + maxOverflow + "px or was missing in " + failed + " viewport(s)." : undefined,
|
|
8261
|
+
});
|
|
8262
|
+
continue;
|
|
8263
|
+
}
|
|
8108
8264
|
if (check.type === "text_visible" || check.type === "text_absent") {
|
|
8109
8265
|
const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
|
|
8110
8266
|
const expectedVisible = check.type === "text_visible";
|
|
@@ -8502,6 +8658,108 @@ async function selectorTextSequence(selector) {
|
|
|
8502
8658
|
};
|
|
8503
8659
|
}).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
|
|
8504
8660
|
}
|
|
8661
|
+
async function frameEvidence(selector) {
|
|
8662
|
+
const result = { selector, count: 0, frame_count: 0, frames: [], errors: [] };
|
|
8663
|
+
let handles = [];
|
|
8664
|
+
try {
|
|
8665
|
+
const locator = page.locator(selector);
|
|
8666
|
+
result.count = await locator.count();
|
|
8667
|
+
handles = await locator.elementHandles();
|
|
8668
|
+
} catch (error) {
|
|
8669
|
+
result.errors.push(String(error && error.message ? error.message : error).slice(0, 500));
|
|
8670
|
+
return result;
|
|
8671
|
+
}
|
|
8672
|
+
for (let index = 0; index < handles.length; index += 1) {
|
|
8673
|
+
const handle = handles[index];
|
|
8674
|
+
try {
|
|
8675
|
+
const frame = typeof handle.contentFrame === "function" ? await handle.contentFrame() : null;
|
|
8676
|
+
if (!frame) {
|
|
8677
|
+
result.frames.push({ index, attached: false, error: "content_frame_unavailable" });
|
|
8678
|
+
continue;
|
|
8679
|
+
}
|
|
8680
|
+
const snapshot = await frame.evaluate(() => {
|
|
8681
|
+
const body = document.body;
|
|
8682
|
+
const documentElement = document.documentElement;
|
|
8683
|
+
const text = (body ? body.innerText : "").replace(/\s+/g, " ").trim();
|
|
8684
|
+
const clientWidth = documentElement ? documentElement.clientWidth : window.innerWidth;
|
|
8685
|
+
const clientHeight = documentElement ? documentElement.clientHeight : window.innerHeight;
|
|
8686
|
+
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
8687
|
+
const viewportWidth = clientWidth || window.innerWidth;
|
|
8688
|
+
const overflowOffenders = [];
|
|
8689
|
+
function isContainedByHorizontalScroller(element) {
|
|
8690
|
+
let current = element.parentElement;
|
|
8691
|
+
while (current && current !== body && current !== documentElement) {
|
|
8692
|
+
const style = window.getComputedStyle(current);
|
|
8693
|
+
const overflowX = style.overflowX || style.overflow || "";
|
|
8694
|
+
if ((overflowX === "auto" || overflowX === "scroll") && current.scrollWidth > current.clientWidth + 1) {
|
|
8695
|
+
const currentRect = current.getBoundingClientRect();
|
|
8696
|
+
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
8697
|
+
if (contained) return true;
|
|
8698
|
+
}
|
|
8699
|
+
current = current.parentElement;
|
|
8700
|
+
}
|
|
8701
|
+
return false;
|
|
8702
|
+
}
|
|
8703
|
+
for (const element of Array.from(body ? body.querySelectorAll("*") : [])) {
|
|
8704
|
+
const rect = element.getBoundingClientRect();
|
|
8705
|
+
if (!rect || rect.width < 1 || rect.height < 1) continue;
|
|
8706
|
+
const style = window.getComputedStyle(element);
|
|
8707
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") continue;
|
|
8708
|
+
const leftOverflow = Math.max(0, -rect.left);
|
|
8709
|
+
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
8710
|
+
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
8711
|
+
if (overflow <= 0.5) continue;
|
|
8712
|
+
if (isContainedByHorizontalScroller(element)) continue;
|
|
8713
|
+
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
8714
|
+
const id = element.id ? "#" + element.id : "";
|
|
8715
|
+
const className = typeof element.className === "string"
|
|
8716
|
+
? element.className.trim().split(/\s+/).filter(Boolean).slice(0, 2).join(".")
|
|
8717
|
+
: "";
|
|
8718
|
+
overflowOffenders.push({
|
|
8719
|
+
selector: tag + id + (className ? "." + className : ""),
|
|
8720
|
+
tag,
|
|
8721
|
+
text: (element.textContent || "").replace(/\s+/g, " ").trim().slice(0, 120),
|
|
8722
|
+
overflow,
|
|
8723
|
+
left_overflow_px: leftOverflow,
|
|
8724
|
+
right_overflow_px: rightOverflow,
|
|
8725
|
+
viewport_width: viewportWidth,
|
|
8726
|
+
rect: {
|
|
8727
|
+
left: rect.left,
|
|
8728
|
+
right: rect.right,
|
|
8729
|
+
width: rect.width,
|
|
8730
|
+
},
|
|
8731
|
+
});
|
|
8732
|
+
}
|
|
8733
|
+
overflowOffenders.sort((a, b) => b.overflow - a.overflow);
|
|
8734
|
+
const boundsOverflowPx = Math.max(
|
|
8735
|
+
0,
|
|
8736
|
+
scrollWidth - (clientWidth || viewportWidth),
|
|
8737
|
+
...overflowOffenders.map((offender) => offender.overflow),
|
|
8738
|
+
);
|
|
8739
|
+
return {
|
|
8740
|
+
url: location.href,
|
|
8741
|
+
title: document.title,
|
|
8742
|
+
text_length: text.length,
|
|
8743
|
+
text_sample: text.slice(0, 8000),
|
|
8744
|
+
body_text_sample: text.slice(0, 8000),
|
|
8745
|
+
viewport_width: viewportWidth,
|
|
8746
|
+
viewport_height: clientHeight || window.innerHeight,
|
|
8747
|
+
scroll_width: scrollWidth,
|
|
8748
|
+
client_width: clientWidth,
|
|
8749
|
+
overflow_px: Math.max(0, scrollWidth - (clientWidth || viewportWidth)),
|
|
8750
|
+
bounds_overflow_px: Math.round(boundsOverflowPx * 100) / 100,
|
|
8751
|
+
overflow_offender_count: overflowOffenders.length,
|
|
8752
|
+
overflow_offenders: overflowOffenders.slice(0, 10),
|
|
8753
|
+
};
|
|
8754
|
+
});
|
|
8755
|
+
result.frames.push({ index, attached: true, ...snapshot });
|
|
8756
|
+
} catch (error) {
|
|
8757
|
+
result.frames.push({ index, attached: false, error: String(error && error.message ? error.message : error).slice(0, 1000) });
|
|
8758
|
+
}
|
|
8759
|
+
}
|
|
8760
|
+
result.frame_count = result.frames.filter((frame) => frame && frame.attached !== false && !frame.error).length;
|
|
8761
|
+
return result;
|
|
8762
|
+
}
|
|
8505
8763
|
function inventoryAppPathFromUrl(urlLike) {
|
|
8506
8764
|
const url = new URL(String(urlLike), targetUrl);
|
|
8507
8765
|
const mountPrefix = previewMountPrefix(new URL(targetUrl).pathname);
|
|
@@ -8523,6 +8781,13 @@ function inventoryRouteUrl(expectedPath) {
|
|
|
8523
8781
|
function inventorySlugFromPath(path) {
|
|
8524
8782
|
return String(path || "route").split("/").filter(Boolean).pop()?.replace(/[^a-z0-9]+/gi, "-").toLowerCase() || "route";
|
|
8525
8783
|
}
|
|
8784
|
+
function inventorySlugFromViewport(viewport) {
|
|
8785
|
+
return String(viewport && viewport.name || "viewport").replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "viewport";
|
|
8786
|
+
}
|
|
8787
|
+
function inventoryScreenshotLabel(check, viewport, phase, path) {
|
|
8788
|
+
const viewportPart = check.run_all_viewports ? "-" + inventorySlugFromViewport(viewport) : "";
|
|
8789
|
+
return profileSlug + viewportPart + "-" + phase + "-" + inventorySlugFromPath(path);
|
|
8790
|
+
}
|
|
8526
8791
|
function inventoryCheckTimeout(check) {
|
|
8527
8792
|
const timeout = Number(check && check.timeout_ms);
|
|
8528
8793
|
return Number.isFinite(timeout) && timeout > 0 ? timeout : 45000;
|
|
@@ -8731,7 +8996,7 @@ async function collectRouteInventory(check, viewport) {
|
|
|
8731
8996
|
const snapshot = await collectInventoryRouteSnapshot(expectedRoute, "direct", check, error);
|
|
8732
8997
|
directRoutes.push(snapshot);
|
|
8733
8998
|
if (check.save_route_screenshots) {
|
|
8734
|
-
await saveScreenshot(
|
|
8999
|
+
await saveScreenshot(inventoryScreenshotLabel(check, viewport, "direct", expectedRoute.path)).catch(() => {});
|
|
8735
9000
|
}
|
|
8736
9001
|
if (error) failures.push({ code: "direct_route_unhealthy", name: expectedRoute.name || null, path: expectedRoute.path, error });
|
|
8737
9002
|
else if (snapshot.actual_app_path !== normalizeRoutePath(expectedRoute.path)) failures.push({ code: "direct_route_wrong_path", name: expectedRoute.name || null, path: expectedRoute.path, actual_app_path: snapshot.actual_app_path });
|
|
@@ -8765,7 +9030,7 @@ async function collectRouteInventory(check, viewport) {
|
|
|
8765
9030
|
result.snapshot = await collectInventoryRouteSnapshot(expectedRoute, "clickthrough", check, result.error || "");
|
|
8766
9031
|
clickthroughs.push(result);
|
|
8767
9032
|
if (check.save_route_screenshots) {
|
|
8768
|
-
await saveScreenshot(
|
|
9033
|
+
await saveScreenshot(inventoryScreenshotLabel(check, viewport, "click", expectedRoute.path)).catch(() => {});
|
|
8769
9034
|
}
|
|
8770
9035
|
if (result.error && result.error !== "source_link_not_found") failures.push({ code: "source_link_clickthrough_unhealthy", name: expectedRoute.name || null, path: expectedRoute.path, error: result.error });
|
|
8771
9036
|
else if (result.snapshot.actual_app_path !== normalizeRoutePath(expectedRoute.path)) failures.push({ code: "source_link_clickthrough_wrong_path", name: expectedRoute.name || null, path: expectedRoute.path, actual_app_path: result.snapshot.actual_app_path });
|
|
@@ -8899,6 +9164,7 @@ async function captureViewport(viewport) {
|
|
|
8899
9164
|
evaluation_error: String(error && error.message ? error.message : error).slice(0, 1000),
|
|
8900
9165
|
}));
|
|
8901
9166
|
const selectors = {};
|
|
9167
|
+
const frames = {};
|
|
8902
9168
|
const text_sequences = {};
|
|
8903
9169
|
const text_matches = {};
|
|
8904
9170
|
for (const check of profile.checks || []) {
|
|
@@ -8912,6 +9178,10 @@ async function captureViewport(viewport) {
|
|
|
8912
9178
|
if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
|
|
8913
9179
|
text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
|
|
8914
9180
|
}
|
|
9181
|
+
if ((check.type === "frame_text_visible" || check.type === "frame_no_horizontal_overflow") && check.selector) {
|
|
9182
|
+
selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
|
|
9183
|
+
frames[check.selector] = frames[check.selector] || await frameEvidence(check.selector);
|
|
9184
|
+
}
|
|
8915
9185
|
}
|
|
8916
9186
|
const screenshotLabel = profileSlug + "-" + viewport.name;
|
|
8917
9187
|
try {
|
|
@@ -8972,6 +9242,7 @@ async function captureViewport(viewport) {
|
|
|
8972
9242
|
bounds_overflow_px: dom.bounds_overflow_px,
|
|
8973
9243
|
overflow_offenders: dom.overflow_offenders || [],
|
|
8974
9244
|
selectors,
|
|
9245
|
+
frames,
|
|
8975
9246
|
text_sequences,
|
|
8976
9247
|
text_matches,
|
|
8977
9248
|
route_inventory: routeInventory,
|
|
@@ -9007,6 +9278,20 @@ function buildProfileEvidence(currentViewports) {
|
|
|
9007
9278
|
overflow_px: currentViewports.map((viewport) => viewport.overflow_px),
|
|
9008
9279
|
bounds_overflow_px: currentViewports.map((viewport) => viewport.bounds_overflow_px),
|
|
9009
9280
|
overflow_offender_counts: currentViewports.map((viewport) => (viewport.overflow_offenders || []).length),
|
|
9281
|
+
frames: currentViewports
|
|
9282
|
+
.filter((viewport) => viewport.frames)
|
|
9283
|
+
.map((viewport) => ({
|
|
9284
|
+
viewport: viewport.name,
|
|
9285
|
+
selectors: Object.entries(viewport.frames || {}).map(([selector, frameSet]) => ({
|
|
9286
|
+
selector,
|
|
9287
|
+
count: frameSet && frameSet.count,
|
|
9288
|
+
frame_count: frameSet && frameSet.frame_count,
|
|
9289
|
+
max_bounds_overflow_px: Math.max(
|
|
9290
|
+
0,
|
|
9291
|
+
...((frameSet && Array.isArray(frameSet.frames) ? frameSet.frames : [])).map((frame) => horizontalBoundsOverflowPx(frame)),
|
|
9292
|
+
),
|
|
9293
|
+
})),
|
|
9294
|
+
})),
|
|
9010
9295
|
route_inventory: currentViewports
|
|
9011
9296
|
.filter((viewport) => viewport.route_inventory)
|
|
9012
9297
|
.map((viewport) => ({
|
package/dist/cli.js
CHANGED