Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/cli/src/commands/layout-audit.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,8 @@
};

// Frozen-sweep guard (#U10, checkPipeline.ts): a compact per-sample
// fingerprint of every visible element's box + opacity, in DOM order. Node
// fingerprint of every visible element's identity + box + opacity, in DOM
// order. Node
// calls this once per seeked grid point and compares the strings across the
// whole run — if every sample produces the identical string, the seek never
// actually moved anything and the whole audit run is unreliable. Deliberately
Expand Down Expand Up @@ -1472,7 +1473,7 @@
const parts = elements.map((element) => {
const rect = toRect(element.getBoundingClientRect());
const opacity = round(opacityChain(element));
return `${rect.left},${rect.top},${rect.width},${rect.height},${opacity}`;
return `${uniqueSelectorFor(element)},${rect.left},${rect.top},${rect.width},${rect.height},${opacity}`;
});
for (const media of root.querySelectorAll("canvas, video")) {
if (!isVisibleElement(media)) continue;
Expand Down
50 changes: 50 additions & 0 deletions packages/cli/src/commands/layout-audit.browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,56 @@ describe("layout-audit.browser", () => {
expect(after).not.toBe(before);
});

it.each([
["ids", 'id="slice-a"', 'id="slice-b"'],
["data layout names", 'data-layout-name="slice-a"', 'data-layout-name="slice-b"'],
["shared classes", 'class="raster-slice"', 'class="raster-slice"'],
["structural positions", "", ""],
])(
"changes the sweep fingerprint when same-sized raster slices with %s swap visibility",
(_identity, firstAttributes, secondAttributes) => {
document.body.innerHTML = `
<div id="root" data-composition-id="main" data-width="640" data-height="360">
<img ${firstAttributes} alt="" style="opacity: 1" />
<img ${secondAttributes} alt="" style="opacity: 0" />
</div>
`;
const [firstSlice, secondSlice] = Array.from(document.querySelectorAll("img")) as [
HTMLImageElement,
HTMLImageElement,
];
const sliceRect = rect({ left: 80, top: 60, width: 480, height: 240 });
installGeometry({
root: rect({ left: 0, top: 0, width: 640, height: 360 }),
"slice-a": sliceRect,
"slice-b": sliceRect,
headline: sliceRect,
"": sliceRect,
});
const nativeGetComputedStyle = window.getComputedStyle.bind(window);
vi.spyOn(window, "getComputedStyle").mockImplementation((element) => {
const computed = nativeGetComputedStyle(element);
const inlineOpacity = (element as HTMLElement).style.opacity;
if (!inlineOpacity) return computed;
return new Proxy(computed, {
get(target, property, receiver) {
return property === "opacity" ? inlineOpacity : Reflect.get(target, property, receiver);
},
});
});

installAuditScript();
const collect = (window as unknown as { __hyperframesLayoutGeometry: () => string })
.__hyperframesLayoutGeometry;
const before = collect();
firstSlice.style.opacity = "0";
secondSlice.style.opacity = "1";
const after = collect();

expect(after).not.toBe(before);
},
);

it("uses authored canvas dimensions when the root bounding rect is degenerate", () => {
document.body.innerHTML = `
<div id="root" data-composition-id="main" data-width="640" data-height="360">
Expand Down