Merge pull request #304 from kevin9327/fix/long-screenshot-aria-case

fix(extension): treat ARIA loading tokens as case-insensitive
This commit is contained in:
Zhang GH
2026-09-22 16:54:25 +08:00
committed by GitHub
2 changed files with 29 additions and 4 deletions
@@ -313,6 +313,24 @@ describe("page capture cleanup", () => {
}
expect(await send({ action: "inspect" })).toMatchObject({ bottomReady: true });
});
it("waits for ARIA loading markers regardless of attribute case", async () => {
const loader = document.createElement("div");
loader.setAttribute("role", "PROGRESSBAR");
loader.setAttribute("aria-busy", "TRUE");
document.body.append(loader);
vi.spyOn(loader, "getBoundingClientRect").mockReturnValue({
top: 500,
bottom: 530,
width: 100,
height: 30,
} as DOMRect);
await send({ action: "begin", label: "Capture", cancelLabel: "Cancel" });
const moving = send({ action: "move", y: 1800, capture: true, final: true });
await vi.advanceTimersByTimeAsync(2500);
expect(await moving).toMatchObject({ bottomReady: false, loading: true });
expect(await send({ action: "inspect" })).toMatchObject({ bottomReady: false, loading: true });
});
it("does not treat article text, code examples or numeric progress widgets as loading", async () => {
document.body.innerHTML +=
'<p>Loading files in JavaScript</p><pre><code>Loading...</code></pre><div role="progressbar" aria-valuenow="100"></div>';
+11 -4
View File
@@ -7,6 +7,10 @@ import {
ScreenshotError,
} from "./types";
function ariaToken(element: Element, name: string): string {
return (element.getAttribute(name) ?? "").trim().toLowerCase();
}
export function createPageCapture(onCancel: (id: string, reason: CaptureCancelReason) => void) {
let task: ReturnType<typeof prepare> | undefined;
@@ -70,8 +74,11 @@ export function createPageCapture(onCancel: (id: string, reason: CaptureCancelRe
const loadingText =
/^(?:加载中|正在加载|载入中|loading(?:\s+(?:more|content|items|results))?)[\s.。…!!]*$/i;
const trackLoading = (element: Element) => {
const role = ariaToken(element, "role");
if (
element.matches('[aria-busy="true"], [role="progressbar"], [role="status"]') ||
ariaToken(element, "aria-busy") === "true" ||
role === "progressbar" ||
role === "status" ||
(element.childElementCount === 0 &&
!element.closest("pre, code") &&
loadingText.test(element.textContent?.trim() ?? ""))
@@ -144,7 +151,7 @@ export function createPageCapture(onCancel: (id: string, reason: CaptureCancelRe
seen.add(element);
trackLoading(element);
if (
element.getAttribute("role") === "contentinfo" ||
ariaToken(element, "role") === "contentinfo" ||
(element.tagName === "FOOTER" && !element.closest("article, aside, section"))
)
footers.add(element);
@@ -280,8 +287,8 @@ export function createPageCapture(onCancel: (id: string, reason: CaptureCancelRe
const style = getComputedStyle(element);
if (style.visibility === "hidden" || style.display === "none") continue;
if (
element.getAttribute("aria-busy") === "true" ||
(element.getAttribute("role") === "progressbar" &&
ariaToken(element, "aria-busy") === "true" ||
(ariaToken(element, "role") === "progressbar" &&
!element.hasAttribute("aria-valuenow")) ||
(!element.closest("pre, code") && loadingText.test(element.textContent?.trim() ?? ""))
) {