fix(harness): filter known storybook axe false positives

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-24 18:00:20 +08:00
parent abd4b3015d
commit db38adbe12
+59 -8
View File
@@ -34,7 +34,7 @@ const stories = [
label: "Date picker playground", label: "Date picker playground",
prepare: async (page) => { prepare: async (page) => {
await page.getByRole("combobox", { name: "Launch date" }).click(); await page.getByRole("combobox", { name: "Launch date" }).click();
await page.getByRole("grid").waitFor({ state: "visible" }); await page.getByRole("dialog", { name: "Launch date calendar" }).waitFor({ state: "visible" });
} }
}, },
{ {
@@ -96,8 +96,8 @@ async function gotoStory(page, story) {
await page.waitForLoadState("domcontentloaded"); await page.waitForLoadState("domcontentloaded");
await page.waitForFunction( await page.waitForFunction(
(storyId) => { (storyId) => {
const title = document.title.toLowerCase(); const title = globalThis.document.title.toLowerCase();
const root = document.getElementById("storybook-root"); const root = globalThis.document.getElementById("storybook-root");
return ( return (
title.includes(String(storyId).toLowerCase()) || title.includes(String(storyId).toLowerCase()) ||
@@ -125,12 +125,63 @@ function summarizeResults(results) {
})); }));
} }
function isKnownIncompleteFalsePositive(result, node) {
const failureSummary = node.failureSummary ?? "";
return (
(result.id === "aria-valid-attr-value" &&
failureSummary.includes(
"Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup"
)) ||
(result.id === "color-contrast" &&
(failureSummary.includes("Could not parse color string") ||
failureSummary.includes("Axe encountered an error; test the page for this type of problem manually")))
);
}
function summarizeIncompleteResults(results) {
return results
.map((result) => {
const nodes = result.nodes
.filter((node) => !isKnownIncompleteFalsePositive(result, node))
.map((node) => ({
failureSummary: node.failureSummary,
html: node.html,
target: node.target
}));
if (nodes.length === 0) {
return null;
}
return {
description: result.description,
help: result.help,
helpUrl: result.helpUrl,
id: result.id,
impact: result.impact,
nodeCount: nodes.length,
nodes
};
})
.filter(Boolean);
}
async function runAxe(page) { async function runAxe(page) {
return page.evaluate(async () => { return page.evaluate(async () => {
const root = document.getElementById("storybook-root") ?? document.body; return globalThis.window.axe.run(
return window.axe.run(root, { {
resultTypes: ["violations", "incomplete"] exclude: [
}); ["#storybook-root[aria-hidden='true']"],
["#storybook-root[data-aria-hidden='true']"],
["[data-radix-focus-guard]"]
],
include: [["body"]]
},
{
resultTypes: ["violations", "incomplete"]
}
);
}); });
} }
@@ -170,7 +221,7 @@ async function main() {
const result = await runAxe(page); const result = await runAxe(page);
const violations = summarizeResults(result.violations); const violations = summarizeResults(result.violations);
const incomplete = summarizeResults(result.incomplete); const incomplete = summarizeIncompleteResults(result.incomplete);
report.violationCount += violations.length; report.violationCount += violations.length;
report.incompleteCount += incomplete.length; report.incompleteCount += incomplete.length;