cbrowser 19.4.0 → 19.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
- package/dist/analysis/accessibility-empathy.js +43 -6
- package/dist/analysis/accessibility-empathy.js.map +1 -1
- package/dist/analysis/page-understanding.d.ts.map +1 -1
- package/dist/analysis/page-understanding.js +27 -1
- package/dist/analysis/page-understanding.js.map +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +6 -0
- package/dist/browser.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +3 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools/base/performance-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/performance-tools.js +3 -2
- package/dist/mcp-tools/base/performance-tools.js.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.js +5 -2
- package/dist/mcp-tools/base/persona-comparison-tools.js.map +1 -1
- package/dist/performance/metrics.d.ts +8 -1
- package/dist/performance/metrics.d.ts.map +1 -1
- package/dist/performance/metrics.js +24 -14
- package/dist/performance/metrics.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/visual/regression.d.ts +17 -0
- package/dist/visual/regression.d.ts.map +1 -1
- package/dist/visual/regression.js +19 -0
- package/dist/visual/regression.js.map +1 -1
- package/dist/visual/responsive.d.ts.map +1 -1
- package/dist/visual/responsive.js +59 -12
- package/dist/visual/responsive.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessibility-empathy.d.ts","sourceRoot":"","sources":["../../src/analysis/accessibility-empathy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoCH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEnB,oBAAoB,EAEpB,4BAA4B,EAK7B,MAAM,aAAa,CAAC;AA8OrB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,4BAA4B,CAAA;CAAE,EAChH,QAAQ,EAAE,CAAC,EAAE,EACb,UAAU,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,GAC7B;IAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAAC,UAAU,EAAE,KAAK,CAAC,CAAC,GAAG;QAAE,eAAe,EAAE,IAAI,CAAC;QAAC,kBAAkB,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,CAAA;KAAE,CAAC,CAAA;CAAE,CAmB3G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACnH,QAAQ,EAAE,CAAC,EAAE,EACb,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAWhC;
|
|
1
|
+
{"version":3,"file":"accessibility-empathy.d.ts","sourceRoot":"","sources":["../../src/analysis/accessibility-empathy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoCH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEnB,oBAAoB,EAEpB,4BAA4B,EAK7B,MAAM,aAAa,CAAC;AA8OrB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,4BAA4B,CAAA;CAAE,EAChH,QAAQ,EAAE,CAAC,EAAE,EACb,UAAU,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,GAC7B;IAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAAC,UAAU,EAAE,KAAK,CAAC,CAAC,GAAG;QAAE,eAAe,EAAE,IAAI,CAAC;QAAC,kBAAkB,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,CAAA;KAAE,CAAC,CAAA;CAAE,CAmB3G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACnH,QAAQ,EAAE,CAAC,EAAE,EACb,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAWhC;AA0iFD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAuG3E;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA2UjF;AAsBD,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,CAAC,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGhF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAE9E;AAmKD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAmB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,KAAK,CAAC;IAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,EAC7E,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,EAChC,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,EACnC,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,GAC5B,MAAM,EAAE,CAkBV;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAmY7B"}
|
|
@@ -289,7 +289,7 @@ async function detectSmallTouchTargets(ctx) {
|
|
|
289
289
|
const _motorControl = persona.accessibilityTraits.motorControl ?? 0.5;
|
|
290
290
|
const smallTargets = await page.$$eval('button, a, input[type="checkbox"], input[type="radio"], [role="button"], [onclick]', (elements, vpOnly) => {
|
|
291
291
|
const vh = window.innerHeight;
|
|
292
|
-
|
|
292
|
+
const mapped = elements.map(el => {
|
|
293
293
|
const rect = el.getBoundingClientRect();
|
|
294
294
|
const text = el.textContent?.trim().slice(0, 50) || '';
|
|
295
295
|
const href = el.href || el.getAttribute('href') || '';
|
|
@@ -348,8 +348,32 @@ async function detectSmallTouchTargets(ctx) {
|
|
|
348
348
|
area: rect.width * rect.height,
|
|
349
349
|
inViewport: rect.bottom > 0 && rect.top < vh,
|
|
350
350
|
exempt: isSkipLink || isVisuallyHidden || isInlineTextLink,
|
|
351
|
+
notTarget: isSkipLink || isVisuallyHidden,
|
|
352
|
+
inlineLink: isInlineTextLink,
|
|
353
|
+
spaced: false,
|
|
354
|
+
el,
|
|
351
355
|
};
|
|
352
|
-
})
|
|
356
|
+
});
|
|
357
|
+
// WCAG 2.5.8's spacing exception: an undersized target passes when a 24px
|
|
358
|
+
// circle centred on it intersects no other target and no other undersized
|
|
359
|
+
// target's circle. Without it a lone 152x20 button was a critical AA failure
|
|
360
|
+
// (v10 Q2). Measured against every live target, on or off screen; a target
|
|
361
|
+
// nested in another (a button in a link) is the same target, not a neighbour.
|
|
362
|
+
// An inline text link is exempt from the SIZE rule only: it is still a target,
|
|
363
|
+
// so it stays a neighbour (with no circle of its own). 19.4.1 dropped it, and
|
|
364
|
+
// cbrowser.ai's carousel step dots overlapping an inline link passed.
|
|
365
|
+
const live = mapped.filter((m) => m.area > 0 && !m.notTarget);
|
|
366
|
+
const small = (m) => !m.inlineLink && (Math.round(m.width) < 24 || Math.round(m.height) < 24);
|
|
367
|
+
const centre = (m) => ({ x: m.x + m.width / 2, y: m.y + m.height / 2 });
|
|
368
|
+
const distToRect = (p, m) => Math.hypot(Math.max(m.x - p.x, 0, p.x - (m.x + m.width)), Math.max(m.y - p.y, 0, p.y - (m.y + m.height)));
|
|
369
|
+
for (const u of live) {
|
|
370
|
+
if (!small(u))
|
|
371
|
+
continue;
|
|
372
|
+
const c = centre(u);
|
|
373
|
+
u.spaced = !live.some((t) => t !== u && !t.el.contains(u.el) && !u.el.contains(t.el) &&
|
|
374
|
+
(distToRect(c, t) < 12 || (small(t) && Math.hypot(c.x - centre(t).x, c.y - centre(t).y) < 24)));
|
|
375
|
+
}
|
|
376
|
+
return mapped.map(({ el: _el, ...rest }) => rest).filter(el => {
|
|
353
377
|
if (el.area <= 0 || el.exempt)
|
|
354
378
|
return false;
|
|
355
379
|
if (vpOnly && !el.inViewport)
|
|
@@ -373,7 +397,8 @@ async function detectSmallTouchTargets(ctx) {
|
|
|
373
397
|
.map((t) => {
|
|
374
398
|
const w = Math.round(t.width);
|
|
375
399
|
const h = Math.round(t.height);
|
|
376
|
-
|
|
400
|
+
const undersized = w < aaMinimum || h < aaMinimum;
|
|
401
|
+
return { ...t, w, h, undersized, failsAA: undersized && !t.spaced, failsAAA: w < aaaTarget || h < aaaTarget };
|
|
377
402
|
})
|
|
378
403
|
.filter((t) => t.failsAAA);
|
|
379
404
|
// AA failures first, THEN the cap, so AAA-only candidates (now more numerous
|
|
@@ -393,6 +418,14 @@ async function detectSmallTouchTargets(ctx) {
|
|
|
393
418
|
rawSeverity = w < 16 || h < 16 ? "critical" : "major";
|
|
394
419
|
ctx.wcagViolations.add("2.5.8");
|
|
395
420
|
}
|
|
421
|
+
else if (target.undersized) {
|
|
422
|
+
// Under 24px but passes 2.5.8 AA by its spacing exception; still under the
|
|
423
|
+
// 44px of 2.5.5 AAA. (v10 Q2)
|
|
424
|
+
wcagCriteria.push("2.5.5");
|
|
425
|
+
description = `Touch target under 24px (${w}x${h}px) — passes WCAG 2.5.8 AA by its spacing exception (nothing within its 24px circle), but under 44px for 2.5.5 AAA`;
|
|
426
|
+
rawSeverity = "minor";
|
|
427
|
+
ctx.wcagViolations.add("2.5.5");
|
|
428
|
+
}
|
|
396
429
|
else {
|
|
397
430
|
// Passes AA but fails AAA: at least 24 on both axes, under 44 on one.
|
|
398
431
|
wcagCriteria.push("2.5.5");
|
|
@@ -890,7 +923,10 @@ async function detectMotionWithoutPause(ctx) {
|
|
|
890
923
|
function pushClassOnlyMotionBarrier(ctx, selectors) {
|
|
891
924
|
const n = selectors.length;
|
|
892
925
|
ctx.barriers.push({
|
|
893
|
-
type
|
|
926
|
+
// "timing", the type 2.2.2 is weighted as. "cognitive_load" rated the fix
|
|
927
|
+
// "hard" and fired the ADHD "complex form layout" friction on pages with no
|
|
928
|
+
// form. (v10 B44/B45)
|
|
929
|
+
type: "timing",
|
|
894
930
|
element: `${n} class-named motion element${n === 1 ? "" : "s"}`,
|
|
895
931
|
// A page-wide aggregate; each element is in members.
|
|
896
932
|
pageLevel: true,
|
|
@@ -907,7 +943,8 @@ function pushClassOnlyMotionBarrier(ctx, selectors) {
|
|
|
907
943
|
/** One 2.2.2 barrier for an uncredited motion group. */
|
|
908
944
|
function pushMotionBarrier(ctx, g) {
|
|
909
945
|
ctx.barriers.push({
|
|
910
|
-
|
|
946
|
+
// See pushClassOnlyMotionBarrier: 2.2.2 is a timing barrier. (v10 B44/B45)
|
|
947
|
+
type: "timing",
|
|
911
948
|
element: g.selector,
|
|
912
949
|
description: `Moving content (${g.memberCount} animated element${g.memberCount === 1 ? "" : "s"}, found by ${g.detectedBy}) has no associated pause, stop or hide control - may distract users with attention difficulties`,
|
|
913
950
|
affectedPersonas: ["cognitive-adhd", "dyslexic-user"],
|
|
@@ -3261,7 +3298,7 @@ export async function runEmpathyAudit(url, options) {
|
|
|
3261
3298
|
if (!persona) {
|
|
3262
3299
|
// Try to find as a regular cognitive persona and wrap it
|
|
3263
3300
|
const { getAnyPersona, createCognitivePersona } = await import("../personas.js");
|
|
3264
|
-
|
|
3301
|
+
const cognitivePersona = getAnyPersona(personaName);
|
|
3265
3302
|
// No CMS fallback here any more: the account's CMS personas were loaded
|
|
3266
3303
|
// into the scoped registry above, so getAnyPersona already sees them, and
|
|
3267
3304
|
// a name nothing resolves was refused before the loop. (2026-10-09)
|