@riddledc/riddle-proof 0.7.37 → 0.7.39
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 +42 -0
- package/dist/{chunk-KZRDAMI5.js → chunk-L4FLSU7L.js} +347 -5
- package/dist/cli.cjs +347 -5
- package/dist/cli.js +1 -1
- package/dist/index.cjs +347 -5
- package/dist/index.js +1 -1
- package/dist/profile.cjs +347 -5
- package/dist/profile.d.cts +6 -1
- package/dist/profile.d.ts +6 -1
- package/dist/profile.js +1 -1
- package/dist/proof-run-engine.d.cts +3 -3
- package/dist/proof-run-engine.d.ts +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8729,6 +8729,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
8729
8729
|
"selector_visible",
|
|
8730
8730
|
"selector_count_at_least",
|
|
8731
8731
|
"selector_text_order",
|
|
8732
|
+
"frame_text_visible",
|
|
8733
|
+
"frame_no_horizontal_overflow",
|
|
8732
8734
|
"text_visible",
|
|
8733
8735
|
"text_absent",
|
|
8734
8736
|
"route_inventory",
|
|
@@ -9017,6 +9019,13 @@ function normalizeExpectedTexts(value, index) {
|
|
|
9017
9019
|
if (!texts.length) throw new Error(`checks[${index}] selector_text_order expected_texts must contain non-empty strings.`);
|
|
9018
9020
|
return texts;
|
|
9019
9021
|
}
|
|
9022
|
+
function normalizeStringList(value, label) {
|
|
9023
|
+
if (value === void 0) return void 0;
|
|
9024
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
9025
|
+
const values = value.map((item) => String(item).replace(/\s+/g, " ").trim()).filter(Boolean);
|
|
9026
|
+
if (!values.length) throw new Error(`${label} must contain non-empty strings.`);
|
|
9027
|
+
return values;
|
|
9028
|
+
}
|
|
9020
9029
|
function normalizeCheck(input, index) {
|
|
9021
9030
|
if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
9022
9031
|
const type = stringValue5(input.type);
|
|
@@ -9027,6 +9036,12 @@ function normalizeCheck(input, index) {
|
|
|
9027
9036
|
if ((type === "selector_visible" || type === "selector_count_at_least") && !stringValue5(input.selector)) {
|
|
9028
9037
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
9029
9038
|
}
|
|
9039
|
+
if ((type === "frame_text_visible" || type === "frame_no_horizontal_overflow") && !stringValue5(input.selector)) {
|
|
9040
|
+
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
9041
|
+
}
|
|
9042
|
+
if (type === "frame_text_visible" && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
9043
|
+
throw new Error(`checks[${index}] frame_text_visible requires text or pattern.`);
|
|
9044
|
+
}
|
|
9030
9045
|
if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
9031
9046
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
9032
9047
|
}
|
|
@@ -9059,6 +9074,10 @@ function normalizeCheck(input, index) {
|
|
|
9059
9074
|
text: stringValue5(input.text),
|
|
9060
9075
|
pattern: stringValue5(input.pattern),
|
|
9061
9076
|
flags: stringValue5(input.flags),
|
|
9077
|
+
allowed_console_texts: normalizeStringList(input.allowed_console_texts ?? input.allowedConsoleTexts ?? input.allow_console_texts ?? input.allowConsoleTexts, `checks[${index}] allowed_console_texts`),
|
|
9078
|
+
allowed_console_patterns: normalizeStringList(input.allowed_console_patterns ?? input.allowedConsolePatterns ?? input.allow_console_patterns ?? input.allowConsolePatterns, `checks[${index}] allowed_console_patterns`),
|
|
9079
|
+
allowed_page_error_texts: normalizeStringList(input.allowed_page_error_texts ?? input.allowedPageErrorTexts ?? input.allow_page_error_texts ?? input.allowPageErrorTexts, `checks[${index}] allowed_page_error_texts`),
|
|
9080
|
+
allowed_page_error_patterns: normalizeStringList(input.allowed_page_error_patterns ?? input.allowedPageErrorPatterns ?? input.allow_page_error_patterns ?? input.allowPageErrorPatterns, `checks[${index}] allowed_page_error_patterns`),
|
|
9062
9081
|
min_count: numberValue3(input.min_count),
|
|
9063
9082
|
max_overflow_px: numberValue3(input.max_overflow_px),
|
|
9064
9083
|
timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
|
|
@@ -9177,6 +9196,22 @@ function textOrderMatch(texts, expectedTexts) {
|
|
|
9177
9196
|
}
|
|
9178
9197
|
return { matched: true, positions };
|
|
9179
9198
|
}
|
|
9199
|
+
function frameEvidenceForSelector(viewport, selector) {
|
|
9200
|
+
const container = viewport.frames?.[selector];
|
|
9201
|
+
if (!isRecord2(container)) return [];
|
|
9202
|
+
const frames = Array.isArray(container.frames) ? container.frames : [];
|
|
9203
|
+
return frames.filter((frame) => isRecord2(frame));
|
|
9204
|
+
}
|
|
9205
|
+
function frameTextSample(frame) {
|
|
9206
|
+
const parts = [
|
|
9207
|
+
frame.title,
|
|
9208
|
+
frame.text_sample,
|
|
9209
|
+
frame.body_text_sample,
|
|
9210
|
+
frame.body_text,
|
|
9211
|
+
frame.text
|
|
9212
|
+
];
|
|
9213
|
+
return parts.map((part) => String(part || "")).filter(Boolean).join(" ");
|
|
9214
|
+
}
|
|
9180
9215
|
function summarizeRouteInventory(viewport, inventory) {
|
|
9181
9216
|
const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
|
|
9182
9217
|
const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
|
|
@@ -9206,6 +9241,18 @@ function matchText(sample, check) {
|
|
|
9206
9241
|
}
|
|
9207
9242
|
return sample.includes(check.text || "");
|
|
9208
9243
|
}
|
|
9244
|
+
function matchesAllowedMessage(message, texts, patterns) {
|
|
9245
|
+
const sample = String(message || "");
|
|
9246
|
+
if (texts?.some((text) => sample.includes(text))) return true;
|
|
9247
|
+
for (const pattern of patterns || []) {
|
|
9248
|
+
try {
|
|
9249
|
+
if (new RegExp(pattern).test(sample)) return true;
|
|
9250
|
+
} catch {
|
|
9251
|
+
continue;
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
return false;
|
|
9255
|
+
}
|
|
9209
9256
|
function normalizeRoutePath(path6) {
|
|
9210
9257
|
const value = path6 || "/";
|
|
9211
9258
|
if (value === "/") return "/";
|
|
@@ -9341,6 +9388,67 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
9341
9388
|
message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
|
|
9342
9389
|
};
|
|
9343
9390
|
}
|
|
9391
|
+
if (check.type === "frame_text_visible") {
|
|
9392
|
+
const key = selectorKey(check);
|
|
9393
|
+
const results = viewports.map((viewport) => {
|
|
9394
|
+
const frames = frameEvidenceForSelector(viewport, key);
|
|
9395
|
+
const matches = frames.map((frame, index) => ({ index, frame, matched: matchText(frameTextSample(frame), check) })).filter((item) => item.matched);
|
|
9396
|
+
return {
|
|
9397
|
+
viewport: viewport.name,
|
|
9398
|
+
frame_count: frames.length,
|
|
9399
|
+
matched_count: matches.length,
|
|
9400
|
+
matched: matches.length > 0,
|
|
9401
|
+
urls: frames.map((frame) => String(frame.url || "")).filter(Boolean).slice(0, 10),
|
|
9402
|
+
samples: matches.map((item) => frameTextSample(item.frame).replace(/\s+/g, " ").trim().slice(0, 240)).slice(0, 3)
|
|
9403
|
+
};
|
|
9404
|
+
});
|
|
9405
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
9406
|
+
return {
|
|
9407
|
+
type: check.type,
|
|
9408
|
+
label: checkLabel(check),
|
|
9409
|
+
status: failed ? "failed" : "passed",
|
|
9410
|
+
evidence: {
|
|
9411
|
+
selector: key,
|
|
9412
|
+
text: check.text || null,
|
|
9413
|
+
pattern: check.pattern || null,
|
|
9414
|
+
viewports: results.map((result) => toJsonValue(result))
|
|
9415
|
+
},
|
|
9416
|
+
message: failed ? `Frame selector ${key} did not contain expected text in ${failed} viewport(s).` : void 0
|
|
9417
|
+
};
|
|
9418
|
+
}
|
|
9419
|
+
if (check.type === "frame_no_horizontal_overflow") {
|
|
9420
|
+
const key = selectorKey(check);
|
|
9421
|
+
const maxOverflow = check.max_overflow_px ?? 4;
|
|
9422
|
+
const results = viewports.map((viewport) => {
|
|
9423
|
+
const frames = frameEvidenceForSelector(viewport, key);
|
|
9424
|
+
const frameOverflows = frames.map((frame, index) => ({
|
|
9425
|
+
index,
|
|
9426
|
+
url: String(frame.url || ""),
|
|
9427
|
+
overflow_px: horizontalBoundsOverflowPx2(frame),
|
|
9428
|
+
offender_count: boundsOffendersForEvidence2(frame).length
|
|
9429
|
+
}));
|
|
9430
|
+
const maxFrameOverflow = frameOverflows.reduce((max, frame) => Math.max(max, frame.overflow_px), 0);
|
|
9431
|
+
return {
|
|
9432
|
+
viewport: viewport.name,
|
|
9433
|
+
frame_count: frames.length,
|
|
9434
|
+
max_overflow_px: roundPixels2(maxFrameOverflow),
|
|
9435
|
+
failed_frame_count: frameOverflows.filter((frame) => frame.overflow_px > maxOverflow).length,
|
|
9436
|
+
frames: frameOverflows.map((frame) => toJsonValue(frame))
|
|
9437
|
+
};
|
|
9438
|
+
});
|
|
9439
|
+
const failed = results.filter((result) => result.frame_count < 1 || result.failed_frame_count > 0).length;
|
|
9440
|
+
return {
|
|
9441
|
+
type: check.type,
|
|
9442
|
+
label: checkLabel(check),
|
|
9443
|
+
status: failed ? "failed" : "passed",
|
|
9444
|
+
evidence: {
|
|
9445
|
+
selector: key,
|
|
9446
|
+
max_overflow_px: maxOverflow,
|
|
9447
|
+
viewports: results.map((result) => toJsonValue(result))
|
|
9448
|
+
},
|
|
9449
|
+
message: failed ? `Frame selector ${key} overflow exceeded ${maxOverflow}px or was missing in ${failed} viewport(s).` : void 0
|
|
9450
|
+
};
|
|
9451
|
+
}
|
|
9344
9452
|
if (check.type === "text_visible" || check.type === "text_absent") {
|
|
9345
9453
|
const key = textKey(check);
|
|
9346
9454
|
const expectedVisible = check.type === "text_visible";
|
|
@@ -9431,14 +9539,28 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
9431
9539
|
};
|
|
9432
9540
|
}
|
|
9433
9541
|
if (check.type === "no_fatal_console_errors") {
|
|
9434
|
-
const
|
|
9542
|
+
const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
|
|
9543
|
+
const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
|
|
9544
|
+
const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
|
|
9545
|
+
const pageErrors = evidence.page_errors || [];
|
|
9546
|
+
const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
|
|
9547
|
+
const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
|
|
9548
|
+
const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
|
|
9435
9549
|
return {
|
|
9436
9550
|
type: check.type,
|
|
9437
9551
|
label: checkLabel(check),
|
|
9438
9552
|
status: fatalCount ? "failed" : "passed",
|
|
9439
9553
|
evidence: {
|
|
9440
|
-
console_fatal_count:
|
|
9441
|
-
page_error_count:
|
|
9554
|
+
console_fatal_count: unallowedConsoleEvents.length,
|
|
9555
|
+
page_error_count: unallowedPageErrors.length,
|
|
9556
|
+
total_console_fatal_count: fatalConsoleEvents.length,
|
|
9557
|
+
total_page_error_count: pageErrors.length,
|
|
9558
|
+
allowed_console_fatal_count: allowedConsoleEvents.length,
|
|
9559
|
+
allowed_page_error_count: allowedPageErrors.length,
|
|
9560
|
+
allowed_console_texts: check.allowed_console_texts || [],
|
|
9561
|
+
allowed_console_patterns: check.allowed_console_patterns || [],
|
|
9562
|
+
allowed_page_error_texts: check.allowed_page_error_texts || [],
|
|
9563
|
+
allowed_page_error_patterns: check.allowed_page_error_patterns || []
|
|
9442
9564
|
},
|
|
9443
9565
|
message: fatalCount ? `${fatalCount} fatal browser error(s) were captured.` : void 0
|
|
9444
9566
|
};
|
|
@@ -9694,6 +9816,16 @@ function textMatches(sample, check) {
|
|
|
9694
9816
|
}
|
|
9695
9817
|
return String(sample || "").includes(check.text || "");
|
|
9696
9818
|
}
|
|
9819
|
+
function matchesAllowedMessage(message, texts, patterns) {
|
|
9820
|
+
const sample = String(message || "");
|
|
9821
|
+
if ((texts || []).some((text) => sample.includes(text))) return true;
|
|
9822
|
+
for (const pattern of patterns || []) {
|
|
9823
|
+
try {
|
|
9824
|
+
if (new RegExp(pattern).test(sample)) return true;
|
|
9825
|
+
} catch {}
|
|
9826
|
+
}
|
|
9827
|
+
return false;
|
|
9828
|
+
}
|
|
9697
9829
|
function textSequenceForCheck(viewport, check) {
|
|
9698
9830
|
const key = check.selector || "";
|
|
9699
9831
|
const sequence = viewport.text_sequences && viewport.text_sequences[key];
|
|
@@ -9716,6 +9848,21 @@ function textOrderMatch(texts, expectedTexts) {
|
|
|
9716
9848
|
}
|
|
9717
9849
|
return { matched: true, positions };
|
|
9718
9850
|
}
|
|
9851
|
+
function frameEvidenceForSelector(viewport, selector) {
|
|
9852
|
+
const container = viewport.frames && viewport.frames[selector || ""];
|
|
9853
|
+
if (!container || typeof container !== "object" || Array.isArray(container)) return [];
|
|
9854
|
+
const frames = Array.isArray(container.frames) ? container.frames : [];
|
|
9855
|
+
return frames.filter((frame) => frame && typeof frame === "object" && !Array.isArray(frame));
|
|
9856
|
+
}
|
|
9857
|
+
function frameTextSample(frame) {
|
|
9858
|
+
return [
|
|
9859
|
+
frame && frame.title,
|
|
9860
|
+
frame && frame.text_sample,
|
|
9861
|
+
frame && frame.body_text_sample,
|
|
9862
|
+
frame && frame.body_text,
|
|
9863
|
+
frame && frame.text,
|
|
9864
|
+
].map((part) => String(part || "")).filter(Boolean).join(" ");
|
|
9865
|
+
}
|
|
9719
9866
|
function summarizeRouteInventory(viewport, inventory) {
|
|
9720
9867
|
const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
|
|
9721
9868
|
const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
|
|
@@ -9962,6 +10109,62 @@ function assessProfile(profile, evidence) {
|
|
|
9962
10109
|
});
|
|
9963
10110
|
continue;
|
|
9964
10111
|
}
|
|
10112
|
+
if (check.type === "frame_text_visible") {
|
|
10113
|
+
const selector = check.selector || "";
|
|
10114
|
+
const results = viewports.map((viewport) => {
|
|
10115
|
+
const frames = frameEvidenceForSelector(viewport, selector);
|
|
10116
|
+
const matches = frames
|
|
10117
|
+
.map((frame, index) => ({ index, frame, matched: textMatches(frameTextSample(frame), check) }))
|
|
10118
|
+
.filter((item) => item.matched);
|
|
10119
|
+
return {
|
|
10120
|
+
viewport: viewport.name,
|
|
10121
|
+
frame_count: frames.length,
|
|
10122
|
+
matched_count: matches.length,
|
|
10123
|
+
matched: matches.length > 0,
|
|
10124
|
+
urls: frames.map((frame) => String(frame.url || "")).filter(Boolean).slice(0, 10),
|
|
10125
|
+
samples: matches.map((item) => frameTextSample(item.frame).replace(/\s+/g, " ").trim().slice(0, 240)).slice(0, 3),
|
|
10126
|
+
};
|
|
10127
|
+
});
|
|
10128
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
10129
|
+
checks.push({
|
|
10130
|
+
type: check.type,
|
|
10131
|
+
label: check.label || check.type,
|
|
10132
|
+
status: failed ? "failed" : "passed",
|
|
10133
|
+
evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
|
|
10134
|
+
message: failed ? "Frame selector " + selector + " did not contain expected text in " + failed + " viewport(s)." : undefined,
|
|
10135
|
+
});
|
|
10136
|
+
continue;
|
|
10137
|
+
}
|
|
10138
|
+
if (check.type === "frame_no_horizontal_overflow") {
|
|
10139
|
+
const selector = check.selector || "";
|
|
10140
|
+
const maxOverflow = check.max_overflow_px == null ? 4 : check.max_overflow_px;
|
|
10141
|
+
const results = viewports.map((viewport) => {
|
|
10142
|
+
const frames = frameEvidenceForSelector(viewport, selector);
|
|
10143
|
+
const frameOverflows = frames.map((frame, index) => ({
|
|
10144
|
+
index,
|
|
10145
|
+
url: String(frame.url || ""),
|
|
10146
|
+
overflow_px: horizontalBoundsOverflowPx(frame),
|
|
10147
|
+
offender_count: boundsOffendersForEvidence(frame).length,
|
|
10148
|
+
}));
|
|
10149
|
+
const maxFrameOverflow = frameOverflows.reduce((max, frame) => Math.max(max, frame.overflow_px), 0);
|
|
10150
|
+
return {
|
|
10151
|
+
viewport: viewport.name,
|
|
10152
|
+
frame_count: frames.length,
|
|
10153
|
+
max_overflow_px: roundPixels(maxFrameOverflow),
|
|
10154
|
+
failed_frame_count: frameOverflows.filter((frame) => frame.overflow_px > maxOverflow).length,
|
|
10155
|
+
frames: frameOverflows,
|
|
10156
|
+
};
|
|
10157
|
+
});
|
|
10158
|
+
const failed = results.filter((result) => result.frame_count < 1 || result.failed_frame_count > 0).length;
|
|
10159
|
+
checks.push({
|
|
10160
|
+
type: check.type,
|
|
10161
|
+
label: check.label || check.type,
|
|
10162
|
+
status: failed ? "failed" : "passed",
|
|
10163
|
+
evidence: { selector, max_overflow_px: maxOverflow, viewports: results },
|
|
10164
|
+
message: failed ? "Frame selector " + selector + " overflow exceeded " + maxOverflow + "px or was missing in " + failed + " viewport(s)." : undefined,
|
|
10165
|
+
});
|
|
10166
|
+
continue;
|
|
10167
|
+
}
|
|
9965
10168
|
if (check.type === "text_visible" || check.type === "text_absent") {
|
|
9966
10169
|
const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
|
|
9967
10170
|
const expectedVisible = check.type === "text_visible";
|
|
@@ -10057,12 +10260,29 @@ function assessProfile(profile, evidence) {
|
|
|
10057
10260
|
continue;
|
|
10058
10261
|
}
|
|
10059
10262
|
if (check.type === "no_fatal_console_errors") {
|
|
10060
|
-
const
|
|
10263
|
+
const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
|
|
10264
|
+
const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
|
|
10265
|
+
const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
|
|
10266
|
+
const pageErrors = evidence.page_errors || [];
|
|
10267
|
+
const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
|
|
10268
|
+
const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
|
|
10269
|
+
const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
|
|
10061
10270
|
checks.push({
|
|
10062
10271
|
type: check.type,
|
|
10063
10272
|
label: check.label || check.type,
|
|
10064
10273
|
status: fatalCount ? "failed" : "passed",
|
|
10065
|
-
evidence: {
|
|
10274
|
+
evidence: {
|
|
10275
|
+
console_fatal_count: unallowedConsoleEvents.length,
|
|
10276
|
+
page_error_count: unallowedPageErrors.length,
|
|
10277
|
+
total_console_fatal_count: fatalConsoleEvents.length,
|
|
10278
|
+
total_page_error_count: pageErrors.length,
|
|
10279
|
+
allowed_console_fatal_count: allowedConsoleEvents.length,
|
|
10280
|
+
allowed_page_error_count: allowedPageErrors.length,
|
|
10281
|
+
allowed_console_texts: check.allowed_console_texts || [],
|
|
10282
|
+
allowed_console_patterns: check.allowed_console_patterns || [],
|
|
10283
|
+
allowed_page_error_texts: check.allowed_page_error_texts || [],
|
|
10284
|
+
allowed_page_error_patterns: check.allowed_page_error_patterns || [],
|
|
10285
|
+
},
|
|
10066
10286
|
message: fatalCount ? String(fatalCount) + " fatal browser error(s) were captured." : undefined,
|
|
10067
10287
|
});
|
|
10068
10288
|
continue;
|
|
@@ -10359,6 +10579,108 @@ async function selectorTextSequence(selector) {
|
|
|
10359
10579
|
};
|
|
10360
10580
|
}).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
|
|
10361
10581
|
}
|
|
10582
|
+
async function frameEvidence(selector) {
|
|
10583
|
+
const result = { selector, count: 0, frame_count: 0, frames: [], errors: [] };
|
|
10584
|
+
let handles = [];
|
|
10585
|
+
try {
|
|
10586
|
+
const locator = page.locator(selector);
|
|
10587
|
+
result.count = await locator.count();
|
|
10588
|
+
handles = await locator.elementHandles();
|
|
10589
|
+
} catch (error) {
|
|
10590
|
+
result.errors.push(String(error && error.message ? error.message : error).slice(0, 500));
|
|
10591
|
+
return result;
|
|
10592
|
+
}
|
|
10593
|
+
for (let index = 0; index < handles.length; index += 1) {
|
|
10594
|
+
const handle = handles[index];
|
|
10595
|
+
try {
|
|
10596
|
+
const frame = typeof handle.contentFrame === "function" ? await handle.contentFrame() : null;
|
|
10597
|
+
if (!frame) {
|
|
10598
|
+
result.frames.push({ index, attached: false, error: "content_frame_unavailable" });
|
|
10599
|
+
continue;
|
|
10600
|
+
}
|
|
10601
|
+
const snapshot = await frame.evaluate(() => {
|
|
10602
|
+
const body = document.body;
|
|
10603
|
+
const documentElement = document.documentElement;
|
|
10604
|
+
const text = (body ? body.innerText : "").replace(/\s+/g, " ").trim();
|
|
10605
|
+
const clientWidth = documentElement ? documentElement.clientWidth : window.innerWidth;
|
|
10606
|
+
const clientHeight = documentElement ? documentElement.clientHeight : window.innerHeight;
|
|
10607
|
+
const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
|
|
10608
|
+
const viewportWidth = clientWidth || window.innerWidth;
|
|
10609
|
+
const overflowOffenders = [];
|
|
10610
|
+
function isContainedByHorizontalScroller(element) {
|
|
10611
|
+
let current = element.parentElement;
|
|
10612
|
+
while (current && current !== body && current !== documentElement) {
|
|
10613
|
+
const style = window.getComputedStyle(current);
|
|
10614
|
+
const overflowX = style.overflowX || style.overflow || "";
|
|
10615
|
+
if ((overflowX === "auto" || overflowX === "scroll") && current.scrollWidth > current.clientWidth + 1) {
|
|
10616
|
+
const currentRect = current.getBoundingClientRect();
|
|
10617
|
+
const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
|
|
10618
|
+
if (contained) return true;
|
|
10619
|
+
}
|
|
10620
|
+
current = current.parentElement;
|
|
10621
|
+
}
|
|
10622
|
+
return false;
|
|
10623
|
+
}
|
|
10624
|
+
for (const element of Array.from(body ? body.querySelectorAll("*") : [])) {
|
|
10625
|
+
const rect = element.getBoundingClientRect();
|
|
10626
|
+
if (!rect || rect.width < 1 || rect.height < 1) continue;
|
|
10627
|
+
const style = window.getComputedStyle(element);
|
|
10628
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") continue;
|
|
10629
|
+
const leftOverflow = Math.max(0, -rect.left);
|
|
10630
|
+
const rightOverflow = Math.max(0, rect.right - viewportWidth);
|
|
10631
|
+
const overflow = Math.max(leftOverflow, rightOverflow);
|
|
10632
|
+
if (overflow <= 0.5) continue;
|
|
10633
|
+
if (isContainedByHorizontalScroller(element)) continue;
|
|
10634
|
+
const tag = element.tagName ? element.tagName.toLowerCase() : "element";
|
|
10635
|
+
const id = element.id ? "#" + element.id : "";
|
|
10636
|
+
const className = typeof element.className === "string"
|
|
10637
|
+
? element.className.trim().split(/\s+/).filter(Boolean).slice(0, 2).join(".")
|
|
10638
|
+
: "";
|
|
10639
|
+
overflowOffenders.push({
|
|
10640
|
+
selector: tag + id + (className ? "." + className : ""),
|
|
10641
|
+
tag,
|
|
10642
|
+
text: (element.textContent || "").replace(/\s+/g, " ").trim().slice(0, 120),
|
|
10643
|
+
overflow,
|
|
10644
|
+
left_overflow_px: leftOverflow,
|
|
10645
|
+
right_overflow_px: rightOverflow,
|
|
10646
|
+
viewport_width: viewportWidth,
|
|
10647
|
+
rect: {
|
|
10648
|
+
left: rect.left,
|
|
10649
|
+
right: rect.right,
|
|
10650
|
+
width: rect.width,
|
|
10651
|
+
},
|
|
10652
|
+
});
|
|
10653
|
+
}
|
|
10654
|
+
overflowOffenders.sort((a, b) => b.overflow - a.overflow);
|
|
10655
|
+
const boundsOverflowPx = Math.max(
|
|
10656
|
+
0,
|
|
10657
|
+
scrollWidth - (clientWidth || viewportWidth),
|
|
10658
|
+
...overflowOffenders.map((offender) => offender.overflow),
|
|
10659
|
+
);
|
|
10660
|
+
return {
|
|
10661
|
+
url: location.href,
|
|
10662
|
+
title: document.title,
|
|
10663
|
+
text_length: text.length,
|
|
10664
|
+
text_sample: text.slice(0, 8000),
|
|
10665
|
+
body_text_sample: text.slice(0, 8000),
|
|
10666
|
+
viewport_width: viewportWidth,
|
|
10667
|
+
viewport_height: clientHeight || window.innerHeight,
|
|
10668
|
+
scroll_width: scrollWidth,
|
|
10669
|
+
client_width: clientWidth,
|
|
10670
|
+
overflow_px: Math.max(0, scrollWidth - (clientWidth || viewportWidth)),
|
|
10671
|
+
bounds_overflow_px: Math.round(boundsOverflowPx * 100) / 100,
|
|
10672
|
+
overflow_offender_count: overflowOffenders.length,
|
|
10673
|
+
overflow_offenders: overflowOffenders.slice(0, 10),
|
|
10674
|
+
};
|
|
10675
|
+
});
|
|
10676
|
+
result.frames.push({ index, attached: true, ...snapshot });
|
|
10677
|
+
} catch (error) {
|
|
10678
|
+
result.frames.push({ index, attached: false, error: String(error && error.message ? error.message : error).slice(0, 1000) });
|
|
10679
|
+
}
|
|
10680
|
+
}
|
|
10681
|
+
result.frame_count = result.frames.filter((frame) => frame && frame.attached !== false && !frame.error).length;
|
|
10682
|
+
return result;
|
|
10683
|
+
}
|
|
10362
10684
|
function inventoryAppPathFromUrl(urlLike) {
|
|
10363
10685
|
const url = new URL(String(urlLike), targetUrl);
|
|
10364
10686
|
const mountPrefix = previewMountPrefix(new URL(targetUrl).pathname);
|
|
@@ -10763,6 +11085,7 @@ async function captureViewport(viewport) {
|
|
|
10763
11085
|
evaluation_error: String(error && error.message ? error.message : error).slice(0, 1000),
|
|
10764
11086
|
}));
|
|
10765
11087
|
const selectors = {};
|
|
11088
|
+
const frames = {};
|
|
10766
11089
|
const text_sequences = {};
|
|
10767
11090
|
const text_matches = {};
|
|
10768
11091
|
for (const check of profile.checks || []) {
|
|
@@ -10776,6 +11099,10 @@ async function captureViewport(viewport) {
|
|
|
10776
11099
|
if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
|
|
10777
11100
|
text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
|
|
10778
11101
|
}
|
|
11102
|
+
if ((check.type === "frame_text_visible" || check.type === "frame_no_horizontal_overflow") && check.selector) {
|
|
11103
|
+
selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
|
|
11104
|
+
frames[check.selector] = frames[check.selector] || await frameEvidence(check.selector);
|
|
11105
|
+
}
|
|
10779
11106
|
}
|
|
10780
11107
|
const screenshotLabel = profileSlug + "-" + viewport.name;
|
|
10781
11108
|
try {
|
|
@@ -10836,6 +11163,7 @@ async function captureViewport(viewport) {
|
|
|
10836
11163
|
bounds_overflow_px: dom.bounds_overflow_px,
|
|
10837
11164
|
overflow_offenders: dom.overflow_offenders || [],
|
|
10838
11165
|
selectors,
|
|
11166
|
+
frames,
|
|
10839
11167
|
text_sequences,
|
|
10840
11168
|
text_matches,
|
|
10841
11169
|
route_inventory: routeInventory,
|
|
@@ -10871,6 +11199,20 @@ function buildProfileEvidence(currentViewports) {
|
|
|
10871
11199
|
overflow_px: currentViewports.map((viewport) => viewport.overflow_px),
|
|
10872
11200
|
bounds_overflow_px: currentViewports.map((viewport) => viewport.bounds_overflow_px),
|
|
10873
11201
|
overflow_offender_counts: currentViewports.map((viewport) => (viewport.overflow_offenders || []).length),
|
|
11202
|
+
frames: currentViewports
|
|
11203
|
+
.filter((viewport) => viewport.frames)
|
|
11204
|
+
.map((viewport) => ({
|
|
11205
|
+
viewport: viewport.name,
|
|
11206
|
+
selectors: Object.entries(viewport.frames || {}).map(([selector, frameSet]) => ({
|
|
11207
|
+
selector,
|
|
11208
|
+
count: frameSet && frameSet.count,
|
|
11209
|
+
frame_count: frameSet && frameSet.frame_count,
|
|
11210
|
+
max_bounds_overflow_px: Math.max(
|
|
11211
|
+
0,
|
|
11212
|
+
...((frameSet && Array.isArray(frameSet.frames) ? frameSet.frames : [])).map((frame) => horizontalBoundsOverflowPx(frame)),
|
|
11213
|
+
),
|
|
11214
|
+
})),
|
|
11215
|
+
})),
|
|
10874
11216
|
route_inventory: currentViewports
|
|
10875
11217
|
.filter((viewport) => viewport.route_inventory)
|
|
10876
11218
|
.map((viewport) => ({
|
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-L4FLSU7L.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|