mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-13 06:36:26 +03:00
Fixes three detector bugs that surfaced on real-world (Shopify) URL scans: #407 — DOM named-property shadowing crash. On a <form> with a named control like <input name="id"> (every Shopify product form), HTMLFormElement's [LegacyOverrideBuiltIns] behavior makes `form.id` return the input element, not the id string, so `elId.startsWith(...)` throws and aborts the whole scan. Read the id via getAttribute whenever `el.id` is not a string, at all three sites: checkQuality (checks.mjs) and collectBrowserFindings + generateSelector (browser/injected/index.mjs). Regenerated the browser bundle. #408 — tiny-text / undersized-ui-text flagged non-rendered elements. On sites that set html{font-size:62.5%} the root computes to 10px, so <script>/<style>/ <title>/<noscript> and display:none / visibility:hidden blocks — whose JS/CSS/ JSON-LD text clears the hasDirectText gate — produced dozens of phantom "10px body text" findings. Added isNonRenderedText() (tag list + head descendants + display/visibility) and gated both text-size floors on it. #409 — contrast rules misjudged gradients. Case A: background-clip:text paints its glyphs with the element's own gradient, not a backdrop, so measuring the never-painted `color` against those stops is a guaranteed false positive; skip the backdrop-contrast checks when bgClip is 'text' (the gradient-text pattern flag still fires). Case B: a translucent gradient stop (e.g. a 9%-alpha accent glow) was treated as an opaque accent; composite alpha stops over the resolved surface beneath the gradient in resolveGradientStops(), dropping the stop rather than guessing when that surface is unresolvable. Fixtures + tests: shadowed-form-id.html (browser, #407), nonrendered-text.html (#408), and gradient-clipped + alpha-glow cases added to color.html (#409). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
51 lines
2.7 KiB
HTML
51 lines
2.7 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Regression fixture for issue #408: tiny-text / undersized-ui-text must only
|
|
measure rendered text. On sites that set `html { font-size: 62.5% }` the root
|
|
computes to 10px, so every element that inherits the root and carries text
|
|
content — including <script>, <style>, <title>, <noscript>, and display:none /
|
|
visibility:hidden blocks — reports a 10px computed size. Their JS / CSS /
|
|
JSON-LD text satisfies hasDirectText, so before the fix they produced dozens
|
|
of phantom "10px body text" findings on every Shopify page.
|
|
|
|
Explicit pixel sizes throughout because jsdom does no layout.
|
|
-->
|
|
<html style="font-size: 10px">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<!-- SHOULD PASS: a long <title> inherits the 10px root, but nothing renders it. -->
|
|
<title>This is a fairly long document title that easily exceeds twenty characters</title>
|
|
<!-- SHOULD PASS: stylesheet text is never painted. -->
|
|
<style>
|
|
/* This CSS comment is deliberately longer than twenty characters so the style
|
|
element's text node clears the hasDirectText / textLen > 20 gate. */
|
|
body { font-size: 10px; font-family: system-ui, sans-serif; }
|
|
.rendered-body { font-size: 10px; }
|
|
.rendered-nav-link { font-size: 9px; }
|
|
.none-block { display: none; font-size: 10px; }
|
|
.hidden-block { visibility: hidden; font-size: 10px; }
|
|
</style>
|
|
<!-- SHOULD PASS: script payload text is never painted. -->
|
|
<script>window.__ANALYTICS__ = { id: 1, ts: 0 }; console.log("an analytics payload string that is clearly longer than twenty characters");</script>
|
|
<!-- SHOULD PASS: JSON-LD schema block, a Shopify staple. -->
|
|
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Product","name":"A product name long enough to exceed twenty characters"}</script>
|
|
<!-- SHOULD PASS: noscript fallback prose is only shown without JS; still non-rendered here. -->
|
|
<noscript>Please enable JavaScript in your browser to view this page content correctly.</noscript>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- SHOULD PASS: display:none block, its text is never painted. -->
|
|
<div class="none-block">Hidden display-none block of body text long enough to exceed twenty characters.</div>
|
|
|
|
<!-- SHOULD PASS: visibility:hidden paragraph, its text is never painted. -->
|
|
<p class="hidden-block">Invisible visibility-hidden paragraph copy that is longer than the twenty char gate.</p>
|
|
|
|
<!-- SHOULD FLAG (tiny-text): genuinely rendered body copy at 10px. -->
|
|
<p class="rendered-body">This is real rendered body copy at 10px that is definitely long enough to flag.</p>
|
|
|
|
<!-- SHOULD FLAG (undersized-ui-text): genuinely rendered interactive text at 9px. -->
|
|
<nav aria-label="primary"><a href="/docs" class="rendered-nav-link">Rendered Nav Link</a></nav>
|
|
|
|
</body>
|
|
</html>
|