Skip to content
Merged
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
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Contributors sign the [CLA](CLA.md) on their first PR; the CLA bot explains how.
`bun run test:e2e` checks the built package: every `exports` target exists and the
root entry loads under Node with every optional peer blocked, then packs the
package into a Vite host and runs the Playwright specs in `e2e/` against it. Each
scenario is a route in `e2e/fixtures.tsx`. Run `bun run build` first, and
scenario is a route in `e2e/fixtures.tsx`. The same run builds the Ladle stories
and fails on any serious or critical axe violation in any story. Run `bun run build` first, and
`bunx playwright install chromium` once. CI also runs `bun run contrast-test` (theme contrast floors, reads
`dist/styles.css`) and `bun run dep-guard` (forbidden imports, see `AGENTS.md`)
after the build.
Expand Down
3 changes: 3 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions e2e/stories-a11y.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";

const STORIES = "http://localhost:61000";

test("every Ladle story is free of serious and critical axe violations", async ({
page,
request,
}) => {
test.setTimeout(600_000);
const meta = (await (await request.get(`${STORIES}/meta.json`)).json()) as {
stories: Record<string, unknown>;
};
const failures: string[] = [];

for (const theme of ["light", "dark"]) {
for (const story of Object.keys(meta.stories)) {
await page.goto(`${STORIES}/?story=${story}&mode=preview&theme=${theme}`);
await page.locator("[data-storyloaded]").waitFor();
const { violations } = await new AxeBuilder({ page }).analyze();
for (const violation of violations) {
if (violation.impact === "serious" || violation.impact === "critical") {
failures.push(
`${story} (${theme}): ${violation.id} (${violation.nodes.length})`,
);
}
}
}
}

expect(failures).toEqual([]);
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"tailwind-merge": "^3.3.1"
},
"devDependencies": {
"@axe-core/playwright": "^4.13.0",
"@happy-dom/global-registrator": "^20.11.2",
"@ladle/react": "^5.1.1",
"@playwright/test": "^1.63.0",
Expand Down
23 changes: 16 additions & 7 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig, devices } from "@playwright/test";

// Serves the Vite host e2e/helpers.ts bootstraps from the packed tarball.
// Serves the Vite host e2e/helpers.ts bootstraps from the packed tarball, and
// the Ladle stories build for the accessibility sweep.
export default defineConfig({
testDir: "e2e",
testMatch: "*.spec.ts",
Expand All @@ -10,10 +11,18 @@ export default defineConfig({
snapshotPathTemplate: "{testDir}/__screenshots__/{arg}{ext}",
use: { baseURL: "http://localhost:4173" },
projects: [{ name: "chromium", use: devices["Desktop Chrome"] }],
webServer: {
command: "bun e2e/helpers.ts",
url: "http://localhost:4173/smoke",
reuseExistingServer: false,
timeout: 180_000,
},
webServer: [
{
command: "bun e2e/helpers.ts",
url: "http://localhost:4173/smoke",
reuseExistingServer: false,
timeout: 180_000,
},
{
command: "bun run stories:build && bunx ladle preview --port 61000",
url: "http://localhost:61000/meta.json",
reuseExistingServer: false,
timeout: 180_000,
},
],
});
Loading