@masup9/a11y-audit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.ja.md +128 -0
- package/README.md +130 -0
- package/dist/constants.d.ts +88 -0
- package/dist/constants.js +184 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/playwright/index.d.ts +19 -0
- package/dist/playwright/index.js +19 -0
- package/dist/playwright/runAxeAudit.d.ts +28 -0
- package/dist/playwright/runAxeAudit.js +89 -0
- package/dist/playwright/runFocusIndicatorCheck.d.ts +30 -0
- package/dist/playwright/runFocusIndicatorCheck.js +740 -0
- package/dist/playwright/runReflowCheck.d.ts +36 -0
- package/dist/playwright/runReflowCheck.js +68 -0
- package/dist/playwright/runTargetSizeCheck.d.ts +35 -0
- package/dist/playwright/runTargetSizeCheck.js +389 -0
- package/dist/schemas/index.d.ts +34 -0
- package/dist/schemas/index.js +245 -0
- package/dist/test-entries/axe-audit.d.ts +13 -0
- package/dist/test-entries/axe-audit.js +20 -0
- package/dist/test-entries/focus-indicator-check.d.ts +9 -0
- package/dist/test-entries/focus-indicator-check.js +13 -0
- package/dist/test-entries/reflow-check.d.ts +9 -0
- package/dist/test-entries/reflow-check.js +21 -0
- package/dist/test-entries/target-size-check.d.ts +8 -0
- package/dist/test-entries/target-size-check.js +15 -0
- package/dist/types.d.ts +215 -0
- package/dist/types.js +4 -0
- package/dist/utils/annotations.d.ts +67 -0
- package/dist/utils/annotations.js +110 -0
- package/dist/utils/layout.d.ts +23 -0
- package/dist/utils/layout.js +144 -0
- package/dist/utils/test-harness.d.ts +76 -0
- package/dist/utils/test-harness.js +119 -0
- package/package.json +92 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@masup9/a11y-audit` are documented here. This project
|
|
4
|
+
adheres to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## 0.1.0
|
|
7
|
+
|
|
8
|
+
Initial preview release. The function API may change before `1.0.0` based on
|
|
9
|
+
downstream feedback.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `runAxeAudit` — axe-core broad WCAG coverage (2.0/2.1/2.2 A & AA).
|
|
14
|
+
- `runFocusIndicatorCheck` — WCAG 2.4.7 / 2.4.12 / 3.2.1 (owns its browser
|
|
15
|
+
context; supports `contextOptions`).
|
|
16
|
+
- `runReflowCheck` — WCAG 1.4.10.
|
|
17
|
+
- `runTargetSizeCheck` — WCAG 2.5.5 / 2.5.8.
|
|
18
|
+
- Compatibility `test-entries/*`, run via a one-line local re-export spec
|
|
19
|
+
(`TEST_PAGE` / `A11Y_OUTPUT_DIR`). Note: Playwright excludes `node_modules`
|
|
20
|
+
from test collection, so a `testMatch` glob into `node_modules` finds no
|
|
21
|
+
tests — use the re-export spec instead.
|
|
22
|
+
- `schemas` subpath: result types + hand-written JSON Schemas.
|
|
23
|
+
- Output path resolution: `outputDir` option → `A11Y_OUTPUT_DIR` env →
|
|
24
|
+
`process.cwd()`, with `outputPath`/`outputDir` exclusivity (promoted from
|
|
25
|
+
the downstream `resolveOutputPath` improvement).
|
|
26
|
+
|
|
27
|
+
### Notes
|
|
28
|
+
|
|
29
|
+
- Ported from the `auditing-wcag` skill's vendor scripts, including the
|
|
30
|
+
downstream strict-TS fix in the focus check.
|
|
31
|
+
- Screenshots default to `false` in the function API; the compatibility entries
|
|
32
|
+
enable them to preserve legacy behavior.
|
|
33
|
+
- Phase 2 checks (text-spacing / zoom-200 / orientation / autocomplete /
|
|
34
|
+
time-limit / auto-play) are out of scope for this release.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# @masup9/a11y-audit
|
|
2
|
+
|
|
3
|
+
Playwright + axe-core ベースの WCAG 2.2 アクセシビリティ検査関数。
|
|
4
|
+
|
|
5
|
+
本パッケージは [`auditing-wcag`](https://github.com/masuP9/a11y-specialist-skills)
|
|
6
|
+
Claude Code skill から機能本体を切り出したものです。4 つの検査を関数として提供し、
|
|
7
|
+
すぐ実行できる Playwright 用の互換 test entry も同梱します。
|
|
8
|
+
|
|
9
|
+
> **English: see [README.md](./README.md).**
|
|
10
|
+
|
|
11
|
+
> **スコープ.** 自動テストで検出できるのは WCAG 違反の約 30〜40% です。完全な準拠確認には
|
|
12
|
+
> 手動テストが必須です。本パッケージはその一部を自動化します。
|
|
13
|
+
|
|
14
|
+
## 検査一覧 (v0.1.0)
|
|
15
|
+
|
|
16
|
+
| 関数 | WCAG |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `runAxeAudit` | axe-core による広範な検出 (2.0/2.1/2.2 A & AA) |
|
|
19
|
+
| `runFocusIndicatorCheck` | 2.4.7 フォーカスの可視化 / 2.4.12 フォーカスの非遮蔽 / 3.2.1 オンフォーカス |
|
|
20
|
+
| `runReflowCheck` | 1.4.10 リフロー |
|
|
21
|
+
| `runTargetSizeCheck` | 2.5.5 / 2.5.8 ターゲットのサイズ |
|
|
22
|
+
|
|
23
|
+
## インストール
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install -D @masup9/a11y-audit @playwright/test @axe-core/playwright
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`@playwright/test` と `@axe-core/playwright` は **peer dependencies** です。
|
|
30
|
+
|
|
31
|
+
> ESM 専用です。CommonJS ビルドは同梱しません。ESM(または ESM 出力の TypeScript)から
|
|
32
|
+
> import してください。
|
|
33
|
+
|
|
34
|
+
## 使い方 — 関数 API(推奨)
|
|
35
|
+
|
|
36
|
+
ページの遷移は呼び出し側で行い、関数は検査の実行・結果 JSON の書き出し・結果オブジェクトの
|
|
37
|
+
return を担います。
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { test } from "@playwright/test";
|
|
41
|
+
import { runAxeAudit } from "@masup9/a11y-audit/playwright";
|
|
42
|
+
|
|
43
|
+
test("axe audit", async ({ page }, testInfo) => {
|
|
44
|
+
await page.goto("https://example.com");
|
|
45
|
+
const result = await runAxeAudit({
|
|
46
|
+
page,
|
|
47
|
+
outputDir: testInfo.outputDir, // axe-result.json の出力先
|
|
48
|
+
// outputFile: "axe-result.json", // 任意で上書き
|
|
49
|
+
// tags: ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"],
|
|
50
|
+
});
|
|
51
|
+
expect(result.violationCount).toBe(0);
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
フォーカス表示検査は、フォーカスで遷移が起きた際に新しい context で再試行するため、
|
|
56
|
+
自身の browser context を所有します。そのため `page` ではなく `browser` と `targetUrl`
|
|
57
|
+
を受け取ります。
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { runFocusIndicatorCheck } from "@masup9/a11y-audit/playwright";
|
|
61
|
+
|
|
62
|
+
test("focus indicators", async ({ browser }, testInfo) => {
|
|
63
|
+
const result = await runFocusIndicatorCheck({
|
|
64
|
+
browser,
|
|
65
|
+
targetUrl: "https://example.com", // または TEST_PAGE 環境変数
|
|
66
|
+
outputDir: testInfo.outputDir,
|
|
67
|
+
screenshot: true, // 既定: false
|
|
68
|
+
// contextOptions: { locale: "ja-JP" }, // browser.newContext() に転送
|
|
69
|
+
});
|
|
70
|
+
expect(result.elementsWithoutFocusStyle).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 出力先の解決順
|
|
75
|
+
|
|
76
|
+
各検査共通:
|
|
77
|
+
|
|
78
|
+
1. `outputPath` — フルパス(`outputDir`/`outputFile` とは排他)。
|
|
79
|
+
2. それ以外は `outputDir` → `A11Y_OUTPUT_DIR` 環境変数 → `process.cwd()` に、
|
|
80
|
+
`outputFile` → 各検査の既定ファイル名を結合。
|
|
81
|
+
|
|
82
|
+
スクリーンショット(有効時)は結果ファイルの隣に書き出します。`outputFile` はファイル名のみ
|
|
83
|
+
指定可能です。絶対パスを使う場合は `outputPath` を使ってください。
|
|
84
|
+
|
|
85
|
+
> **リフローの注意.** `runReflowCheck` は自身で狭い viewport を設定するため、遷移済みの
|
|
86
|
+
> page でも動作します。load 時にのみ viewport を読むページでは、legacy スクリプトと完全に
|
|
87
|
+
> 同じ結果を得るために `page.goto(...)` の**前**に viewport を設定してください(互換 entry
|
|
88
|
+
> はこれを行っています)。
|
|
89
|
+
|
|
90
|
+
## 使い方 — 互換 test entry
|
|
91
|
+
|
|
92
|
+
テスト本体を書きたくない場合は、同梱 entry を 1 行のローカル spec から re-export します。
|
|
93
|
+
entry は import 時に `test(...)` を呼び、`TEST_PAGE`(対象 URL)と `A11Y_OUTPUT_DIR`
|
|
94
|
+
(出力先)を読み、スクリーンショットも撮ります(従来スクリプトと同等の挙動)。
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// tests/a11y/axe.spec.ts
|
|
98
|
+
import "@masup9/a11y-audit/test-entries/axe-audit";
|
|
99
|
+
// tests/a11y/focus.spec.ts
|
|
100
|
+
import "@masup9/a11y-audit/test-entries/focus-indicator-check";
|
|
101
|
+
// tests/a11y/reflow.spec.ts
|
|
102
|
+
import "@masup9/a11y-audit/test-entries/reflow-check";
|
|
103
|
+
// tests/a11y/target-size.spec.ts
|
|
104
|
+
import "@masup9/a11y-audit/test-entries/target-size-check";
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
TEST_PAGE=https://example.com A11Y_OUTPUT_DIR=./a11y-results npx playwright test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> **`node_modules` への `testMatch` が使えない理由.** Playwright はテスト収集から
|
|
112
|
+
> `node_modules` を除外するため、`**/node_modules/@masup9/a11y-audit/dist/test-entries/*.js`
|
|
113
|
+
> を `testMatch` に指定してもテストは見つかりません。上記の 1 行 re-export spec が
|
|
114
|
+
> entry を実行する正式な方法です。
|
|
115
|
+
|
|
116
|
+
## 結果型とスキーマ
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import type { AxeAuditResult, FocusCheckResult } from "@masup9/a11y-audit/schemas";
|
|
120
|
+
import { RESULT_SCHEMAS } from "@masup9/a11y-audit/schemas";
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`RESULT_SCHEMAS` は各検査 id に手書きの JSON Schema を対応付けており、`*-result.json`
|
|
124
|
+
を実行時に検証できます。
|
|
125
|
+
|
|
126
|
+
## ライセンス
|
|
127
|
+
|
|
128
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @masup9/a11y-audit
|
|
2
|
+
|
|
3
|
+
Playwright + axe-core based WCAG 2.2 accessibility audit functions.
|
|
4
|
+
|
|
5
|
+
This package is the functional core extracted from the
|
|
6
|
+
[`auditing-wcag`](https://github.com/masuP9/a11y-specialist-skills) Claude Code
|
|
7
|
+
skill. It ships four checks as plain functions plus ready-to-run Playwright
|
|
8
|
+
test entries.
|
|
9
|
+
|
|
10
|
+
> **日本語版は [README.ja.md](./README.ja.md) を参照してください。**
|
|
11
|
+
|
|
12
|
+
> **Scope.** Automated testing detects only ~30–40% of WCAG issues. Manual
|
|
13
|
+
> testing is required for full conformance. This package automates a subset.
|
|
14
|
+
|
|
15
|
+
## Checks (v0.1.0)
|
|
16
|
+
|
|
17
|
+
| Function | WCAG |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `runAxeAudit` | axe-core broad coverage (2.0/2.1/2.2 A & AA) |
|
|
20
|
+
| `runFocusIndicatorCheck` | 2.4.7 Focus Visible / 2.4.12 Focus Not Obscured / 3.2.1 On Focus |
|
|
21
|
+
| `runReflowCheck` | 1.4.10 Reflow |
|
|
22
|
+
| `runTargetSizeCheck` | 2.5.5 / 2.5.8 Target Size |
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm install -D @masup9/a11y-audit @playwright/test @axe-core/playwright
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`@playwright/test` and `@axe-core/playwright` are **peer dependencies**.
|
|
31
|
+
|
|
32
|
+
> ESM only. This package does not ship a CommonJS build; import it from ESM
|
|
33
|
+
> (or a TypeScript project compiled to ESM).
|
|
34
|
+
|
|
35
|
+
## Usage — function API (recommended)
|
|
36
|
+
|
|
37
|
+
You navigate the page; the function runs the check, writes a result JSON, and
|
|
38
|
+
returns the parsed result.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { test } from "@playwright/test";
|
|
42
|
+
import { runAxeAudit } from "@masup9/a11y-audit/playwright";
|
|
43
|
+
|
|
44
|
+
test("axe audit", async ({ page }, testInfo) => {
|
|
45
|
+
await page.goto("https://example.com");
|
|
46
|
+
const result = await runAxeAudit({
|
|
47
|
+
page,
|
|
48
|
+
outputDir: testInfo.outputDir, // where to write axe-result.json
|
|
49
|
+
// outputFile: "axe-result.json", // optional override
|
|
50
|
+
// tags: ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"],
|
|
51
|
+
});
|
|
52
|
+
expect(result.violationCount).toBe(0);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The focus indicator check owns its browser context (it restarts in a fresh
|
|
57
|
+
context when focus triggers a navigation), so it takes a `browser` and a
|
|
58
|
+
`targetUrl` instead of a `page`:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { runFocusIndicatorCheck } from "@masup9/a11y-audit/playwright";
|
|
62
|
+
|
|
63
|
+
test("focus indicators", async ({ browser }, testInfo) => {
|
|
64
|
+
const result = await runFocusIndicatorCheck({
|
|
65
|
+
browser,
|
|
66
|
+
targetUrl: "https://example.com", // or set TEST_PAGE env var
|
|
67
|
+
outputDir: testInfo.outputDir,
|
|
68
|
+
screenshot: true, // default: false
|
|
69
|
+
// contextOptions: { locale: "ja-JP" }, // forwarded to browser.newContext()
|
|
70
|
+
});
|
|
71
|
+
expect(result.elementsWithoutFocusStyle).toBe(0);
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Output location resolution
|
|
76
|
+
|
|
77
|
+
For every check:
|
|
78
|
+
|
|
79
|
+
1. `outputPath` — full path (mutually exclusive with `outputDir`/`outputFile`).
|
|
80
|
+
2. otherwise `outputDir` → `A11Y_OUTPUT_DIR` env → `process.cwd()`, joined with
|
|
81
|
+
`outputFile` → the check's default filename.
|
|
82
|
+
|
|
83
|
+
Screenshots (when enabled) are written next to the result file. `outputFile`
|
|
84
|
+
must be a bare filename; use `outputPath` for an absolute location.
|
|
85
|
+
|
|
86
|
+
> **Reflow note.** `runReflowCheck` sets the narrow viewport itself, so it works
|
|
87
|
+
> on an already-navigated page. For pages that read the viewport only at load
|
|
88
|
+
> time, set the viewport *before* `page.goto(...)` for results identical to the
|
|
89
|
+
> legacy script (the compatibility entry does this).
|
|
90
|
+
|
|
91
|
+
## Usage — compatibility test entries
|
|
92
|
+
|
|
93
|
+
If you prefer not to write test bodies, re-export the bundled entries from a
|
|
94
|
+
one-line local spec. The entries call `test(...)` at import time and read
|
|
95
|
+
`TEST_PAGE` (target URL) and `A11Y_OUTPUT_DIR` (output directory), capturing
|
|
96
|
+
screenshots — reproducing the legacy script behavior.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// tests/a11y/axe.spec.ts
|
|
100
|
+
import "@masup9/a11y-audit/test-entries/axe-audit";
|
|
101
|
+
// tests/a11y/focus.spec.ts
|
|
102
|
+
import "@masup9/a11y-audit/test-entries/focus-indicator-check";
|
|
103
|
+
// tests/a11y/reflow.spec.ts
|
|
104
|
+
import "@masup9/a11y-audit/test-entries/reflow-check";
|
|
105
|
+
// tests/a11y/target-size.spec.ts
|
|
106
|
+
import "@masup9/a11y-audit/test-entries/target-size-check";
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
TEST_PAGE=https://example.com A11Y_OUTPUT_DIR=./a11y-results npx playwright test
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
> **Why not `testMatch` into `node_modules`?** Playwright excludes
|
|
114
|
+
> `node_modules` from test collection, so pointing `testMatch` at
|
|
115
|
+
> `**/node_modules/@masup9/a11y-audit/dist/test-entries/*.js` finds no tests.
|
|
116
|
+
> The one-line re-export specs above are the supported way to run the entries.
|
|
117
|
+
|
|
118
|
+
## Result types & schemas
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import type { AxeAuditResult, FocusCheckResult } from "@masup9/a11y-audit/schemas";
|
|
122
|
+
import { RESULT_SCHEMAS } from "@masup9/a11y-audit/schemas";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`RESULT_SCHEMAS` maps each check id to a hand-written JSON Schema for validating
|
|
126
|
+
the `*-result.json` files at runtime.
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the WCAG audit checks shipped in @masup9/a11y-audit.
|
|
3
|
+
*
|
|
4
|
+
* Only the constants used by the four checks (axe / focus indicator / reflow /
|
|
5
|
+
* target size) are included here. Constants for the Phase 2 checks remain in the
|
|
6
|
+
* skill repository until those checks are ported.
|
|
7
|
+
*/
|
|
8
|
+
/** Disclaimer to include in all audit results */
|
|
9
|
+
export declare const AUDIT_DISCLAIMER: {
|
|
10
|
+
readonly message: "自動テストで検出できるのはWCAG違反の一部です。完全な準拠確認には手動テストが必須です。";
|
|
11
|
+
readonly messageEn: "Automated testing can only detect a subset of WCAG violations. Manual testing is required for full compliance.";
|
|
12
|
+
readonly coverage: "approximately 30-40%";
|
|
13
|
+
readonly moreInfo: "https://www.w3.org/WAI/test-evaluate/preliminary/";
|
|
14
|
+
};
|
|
15
|
+
/** Console disclaimer message */
|
|
16
|
+
export declare const DISCLAIMER_CONSOLE = "\nNote: Automated testing detects only ~30-40% of WCAG issues.\n Manual testing is required for complete accessibility evaluation.\n";
|
|
17
|
+
/** Default axe-core tag set (WCAG 2.0/2.1/2.2 A & AA) */
|
|
18
|
+
export declare const DEFAULT_AXE_TAGS: readonly ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"];
|
|
19
|
+
/** CSS properties to check for focus style changes */
|
|
20
|
+
export declare const FOCUS_STYLE_PROPERTIES: readonly ["outline", "outlineStyle", "outlineColor", "outlineWidth", "outlineOffset", "boxShadow", "backgroundColor"];
|
|
21
|
+
/** Selector for focusable elements */
|
|
22
|
+
export declare const FOCUSABLE_SELECTOR: string;
|
|
23
|
+
/** Extra tab iterations for safety margin */
|
|
24
|
+
export declare const EXTRA_TAB_ITERATIONS = 10;
|
|
25
|
+
/**
|
|
26
|
+
* Minimum overlap ratio to report as obscured (0-1)
|
|
27
|
+
* 0.2 means 20% of the focused element must be covered
|
|
28
|
+
*/
|
|
29
|
+
export declare const FOCUS_OBSCURED_MIN_OVERLAP_RATIO = 0.2;
|
|
30
|
+
/**
|
|
31
|
+
* Minimum overlap area in pixels to report
|
|
32
|
+
* Ignores tiny overlaps (e.g., 1px border touches)
|
|
33
|
+
*/
|
|
34
|
+
export declare const FOCUS_OBSCURED_MIN_OVERLAP_PX = 8;
|
|
35
|
+
/**
|
|
36
|
+
* Selectors to exclude from obscurer detection
|
|
37
|
+
* These elements should not be considered as obscurers
|
|
38
|
+
*/
|
|
39
|
+
export declare const FOCUS_OBSCURED_EXCLUDE_SELECTORS: readonly ["#focus-audit-overlay", ".focus-audit-box", "[data-focus-visited]"];
|
|
40
|
+
/** Default screenshot filename for the focus indicator check */
|
|
41
|
+
export declare const DEFAULT_FOCUS_SCREENSHOT_FILE = "focus-indicators.png";
|
|
42
|
+
/** Default result filename for the focus indicator check */
|
|
43
|
+
export declare const DEFAULT_FOCUS_RESULT_FILE = "focus-indicator-result.json";
|
|
44
|
+
/** Default result filename for the axe audit */
|
|
45
|
+
export declare const DEFAULT_AXE_RESULT_FILE = "axe-result.json";
|
|
46
|
+
/** Default result filename for the reflow check */
|
|
47
|
+
export declare const DEFAULT_REFLOW_RESULT_FILE = "reflow-result.json";
|
|
48
|
+
/** Default screenshot filename for the reflow check */
|
|
49
|
+
export declare const DEFAULT_REFLOW_SCREENSHOT_FILE = "reflow-screenshot.png";
|
|
50
|
+
/** Default result filename for the target size check */
|
|
51
|
+
export declare const DEFAULT_TARGET_SIZE_RESULT_FILE = "target-size-result.json";
|
|
52
|
+
/** Default screenshot filename for the target size check */
|
|
53
|
+
export declare const DEFAULT_TARGET_SIZE_SCREENSHOT_FILE = "target-size-screenshot.png";
|
|
54
|
+
/** Viewport size for reflow test (320 CSS px width at 400% zoom equivalent) */
|
|
55
|
+
export declare const REFLOW_VIEWPORT: {
|
|
56
|
+
readonly width: 320;
|
|
57
|
+
readonly height: 256;
|
|
58
|
+
};
|
|
59
|
+
/** Tolerance for overflow detection in pixels */
|
|
60
|
+
export declare const REFLOW_OVERFLOW_TOLERANCE = 5;
|
|
61
|
+
/** Selector for elements to check for overflow */
|
|
62
|
+
export declare const REFLOW_CHECK_SELECTOR: string;
|
|
63
|
+
/** Elements that are allowed to have horizontal scroll */
|
|
64
|
+
export declare const REFLOW_ALLOWED_OVERFLOW_SELECTORS: readonly ["pre", "code", "table[role=\"presentation\"]", ".data-table", "[data-allow-scroll]"];
|
|
65
|
+
/**
|
|
66
|
+
* Target Size thresholds in CSS pixels
|
|
67
|
+
* - AA (2.5.8 Minimum): 24x24 px
|
|
68
|
+
* - AAA (2.5.5 Enhanced): 44x44 px
|
|
69
|
+
*/
|
|
70
|
+
export declare const TARGET_SIZE_AA = 24;
|
|
71
|
+
export declare const TARGET_SIZE_AAA = 44;
|
|
72
|
+
/**
|
|
73
|
+
* Selector for interactive elements (tap/click targets)
|
|
74
|
+
* Includes all elements that users may tap/click to perform actions
|
|
75
|
+
*/
|
|
76
|
+
export declare const INTERACTIVE_SELECTOR: string;
|
|
77
|
+
/**
|
|
78
|
+
* Tags that indicate inline context (for inline exception)
|
|
79
|
+
*/
|
|
80
|
+
export declare const INLINE_CONTEXT_TAGS: readonly ["p", "li", "dd", "td", "th", "span", "blockquote", "cite", "figcaption"];
|
|
81
|
+
/**
|
|
82
|
+
* Native input types controlled by user agent (for ua-control exception)
|
|
83
|
+
*/
|
|
84
|
+
export declare const UA_CONTROLLED_INPUT_TYPES: readonly ["checkbox", "radio", "range", "color", "date", "datetime-local", "month", "week", "time", "file"];
|
|
85
|
+
/**
|
|
86
|
+
* Minimum text length around inline link to qualify for inline exception
|
|
87
|
+
*/
|
|
88
|
+
export declare const INLINE_CONTEXT_MIN_TEXT = 10;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the WCAG audit checks shipped in @masup9/a11y-audit.
|
|
3
|
+
*
|
|
4
|
+
* Only the constants used by the four checks (axe / focus indicator / reflow /
|
|
5
|
+
* target size) are included here. Constants for the Phase 2 checks remain in the
|
|
6
|
+
* skill repository until those checks are ported.
|
|
7
|
+
*/
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Common Disclaimer
|
|
10
|
+
// =============================================================================
|
|
11
|
+
/** Disclaimer to include in all audit results */
|
|
12
|
+
export const AUDIT_DISCLAIMER = {
|
|
13
|
+
message: '自動テストで検出できるのはWCAG違反の一部です。完全な準拠確認には手動テストが必須です。',
|
|
14
|
+
messageEn: 'Automated testing can only detect a subset of WCAG violations. Manual testing is required for full compliance.',
|
|
15
|
+
coverage: 'approximately 30-40%',
|
|
16
|
+
moreInfo: 'https://www.w3.org/WAI/test-evaluate/preliminary/',
|
|
17
|
+
};
|
|
18
|
+
/** Console disclaimer message */
|
|
19
|
+
export const DISCLAIMER_CONSOLE = `
|
|
20
|
+
Note: Automated testing detects only ~30-40% of WCAG issues.
|
|
21
|
+
Manual testing is required for complete accessibility evaluation.
|
|
22
|
+
`;
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Axe Audit defaults (broad WCAG coverage)
|
|
25
|
+
// =============================================================================
|
|
26
|
+
/** Default axe-core tag set (WCAG 2.0/2.1/2.2 A & AA) */
|
|
27
|
+
export const DEFAULT_AXE_TAGS = [
|
|
28
|
+
'wcag2a',
|
|
29
|
+
'wcag2aa',
|
|
30
|
+
'wcag21a',
|
|
31
|
+
'wcag21aa',
|
|
32
|
+
'wcag22aa',
|
|
33
|
+
];
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Focus Indicator Detection Constants (WCAG 2.4.7)
|
|
36
|
+
// =============================================================================
|
|
37
|
+
/** CSS properties to check for focus style changes */
|
|
38
|
+
export const FOCUS_STYLE_PROPERTIES = [
|
|
39
|
+
'outline',
|
|
40
|
+
'outlineStyle',
|
|
41
|
+
'outlineColor',
|
|
42
|
+
'outlineWidth',
|
|
43
|
+
'outlineOffset',
|
|
44
|
+
'boxShadow',
|
|
45
|
+
'backgroundColor',
|
|
46
|
+
];
|
|
47
|
+
/** Selector for focusable elements */
|
|
48
|
+
export const FOCUSABLE_SELECTOR = `
|
|
49
|
+
input:not([type="hidden"]):not([disabled]),
|
|
50
|
+
select:not([disabled]),
|
|
51
|
+
textarea:not([disabled]),
|
|
52
|
+
button:not([disabled]),
|
|
53
|
+
a[href],
|
|
54
|
+
[tabindex]:not([tabindex="-1"])
|
|
55
|
+
`.trim();
|
|
56
|
+
/** Extra tab iterations for safety margin */
|
|
57
|
+
export const EXTRA_TAB_ITERATIONS = 10;
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Focus Obscured Detection Constants (WCAG 2.4.12)
|
|
60
|
+
// =============================================================================
|
|
61
|
+
/**
|
|
62
|
+
* Minimum overlap ratio to report as obscured (0-1)
|
|
63
|
+
* 0.2 means 20% of the focused element must be covered
|
|
64
|
+
*/
|
|
65
|
+
export const FOCUS_OBSCURED_MIN_OVERLAP_RATIO = 0.2;
|
|
66
|
+
/**
|
|
67
|
+
* Minimum overlap area in pixels to report
|
|
68
|
+
* Ignores tiny overlaps (e.g., 1px border touches)
|
|
69
|
+
*/
|
|
70
|
+
export const FOCUS_OBSCURED_MIN_OVERLAP_PX = 8;
|
|
71
|
+
/**
|
|
72
|
+
* Selectors to exclude from obscurer detection
|
|
73
|
+
* These elements should not be considered as obscurers
|
|
74
|
+
*/
|
|
75
|
+
export const FOCUS_OBSCURED_EXCLUDE_SELECTORS = [
|
|
76
|
+
'#focus-audit-overlay',
|
|
77
|
+
'.focus-audit-box',
|
|
78
|
+
'[data-focus-visited]',
|
|
79
|
+
];
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// Output filename defaults
|
|
82
|
+
// =============================================================================
|
|
83
|
+
/** Default screenshot filename for the focus indicator check */
|
|
84
|
+
export const DEFAULT_FOCUS_SCREENSHOT_FILE = 'focus-indicators.png';
|
|
85
|
+
/** Default result filename for the focus indicator check */
|
|
86
|
+
export const DEFAULT_FOCUS_RESULT_FILE = 'focus-indicator-result.json';
|
|
87
|
+
/** Default result filename for the axe audit */
|
|
88
|
+
export const DEFAULT_AXE_RESULT_FILE = 'axe-result.json';
|
|
89
|
+
/** Default result filename for the reflow check */
|
|
90
|
+
export const DEFAULT_REFLOW_RESULT_FILE = 'reflow-result.json';
|
|
91
|
+
/** Default screenshot filename for the reflow check */
|
|
92
|
+
export const DEFAULT_REFLOW_SCREENSHOT_FILE = 'reflow-screenshot.png';
|
|
93
|
+
/** Default result filename for the target size check */
|
|
94
|
+
export const DEFAULT_TARGET_SIZE_RESULT_FILE = 'target-size-result.json';
|
|
95
|
+
/** Default screenshot filename for the target size check */
|
|
96
|
+
export const DEFAULT_TARGET_SIZE_SCREENSHOT_FILE = 'target-size-screenshot.png';
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// Reflow Check Constants (WCAG 1.4.10)
|
|
99
|
+
// =============================================================================
|
|
100
|
+
/** Viewport size for reflow test (320 CSS px width at 400% zoom equivalent) */
|
|
101
|
+
export const REFLOW_VIEWPORT = { width: 320, height: 256 };
|
|
102
|
+
/** Tolerance for overflow detection in pixels */
|
|
103
|
+
export const REFLOW_OVERFLOW_TOLERANCE = 5;
|
|
104
|
+
/** Selector for elements to check for overflow */
|
|
105
|
+
export const REFLOW_CHECK_SELECTOR = `
|
|
106
|
+
p, h1, h2, h3, h4, h5, h6, li, td, th, span, div, section, article,
|
|
107
|
+
a, button, input, select, textarea, label,
|
|
108
|
+
img, svg, table, nav, header, footer, main, aside
|
|
109
|
+
`.trim();
|
|
110
|
+
/** Elements that are allowed to have horizontal scroll */
|
|
111
|
+
export const REFLOW_ALLOWED_OVERFLOW_SELECTORS = [
|
|
112
|
+
'pre',
|
|
113
|
+
'code',
|
|
114
|
+
'table[role="presentation"]',
|
|
115
|
+
'.data-table',
|
|
116
|
+
'[data-allow-scroll]',
|
|
117
|
+
];
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// Target Size Check Constants (WCAG 2.5.5 / 2.5.8)
|
|
120
|
+
// =============================================================================
|
|
121
|
+
/**
|
|
122
|
+
* Target Size thresholds in CSS pixels
|
|
123
|
+
* - AA (2.5.8 Minimum): 24x24 px
|
|
124
|
+
* - AAA (2.5.5 Enhanced): 44x44 px
|
|
125
|
+
*/
|
|
126
|
+
export const TARGET_SIZE_AA = 24;
|
|
127
|
+
export const TARGET_SIZE_AAA = 44;
|
|
128
|
+
/**
|
|
129
|
+
* Selector for interactive elements (tap/click targets)
|
|
130
|
+
* Includes all elements that users may tap/click to perform actions
|
|
131
|
+
*/
|
|
132
|
+
export const INTERACTIVE_SELECTOR = `
|
|
133
|
+
a[href],
|
|
134
|
+
button:not([disabled]),
|
|
135
|
+
input:not([type="hidden"]):not([disabled]),
|
|
136
|
+
select:not([disabled]),
|
|
137
|
+
textarea:not([disabled]),
|
|
138
|
+
[role="button"]:not([aria-disabled="true"]),
|
|
139
|
+
[role="link"]:not([aria-disabled="true"]),
|
|
140
|
+
[role="checkbox"]:not([aria-disabled="true"]),
|
|
141
|
+
[role="radio"]:not([aria-disabled="true"]),
|
|
142
|
+
[role="switch"]:not([aria-disabled="true"]),
|
|
143
|
+
[role="menuitem"]:not([aria-disabled="true"]),
|
|
144
|
+
[role="tab"]:not([aria-disabled="true"]),
|
|
145
|
+
[role="slider"]:not([aria-disabled="true"]),
|
|
146
|
+
[role="option"]:not([aria-disabled="true"]),
|
|
147
|
+
[tabindex]:not([tabindex="-1"]):not([disabled]),
|
|
148
|
+
summary,
|
|
149
|
+
label[for],
|
|
150
|
+
[onclick]:not([disabled])
|
|
151
|
+
`.trim();
|
|
152
|
+
/**
|
|
153
|
+
* Tags that indicate inline context (for inline exception)
|
|
154
|
+
*/
|
|
155
|
+
export const INLINE_CONTEXT_TAGS = [
|
|
156
|
+
'p',
|
|
157
|
+
'li',
|
|
158
|
+
'dd',
|
|
159
|
+
'td',
|
|
160
|
+
'th',
|
|
161
|
+
'span',
|
|
162
|
+
'blockquote',
|
|
163
|
+
'cite',
|
|
164
|
+
'figcaption',
|
|
165
|
+
];
|
|
166
|
+
/**
|
|
167
|
+
* Native input types controlled by user agent (for ua-control exception)
|
|
168
|
+
*/
|
|
169
|
+
export const UA_CONTROLLED_INPUT_TYPES = [
|
|
170
|
+
'checkbox',
|
|
171
|
+
'radio',
|
|
172
|
+
'range',
|
|
173
|
+
'color',
|
|
174
|
+
'date',
|
|
175
|
+
'datetime-local',
|
|
176
|
+
'month',
|
|
177
|
+
'week',
|
|
178
|
+
'time',
|
|
179
|
+
'file',
|
|
180
|
+
];
|
|
181
|
+
/**
|
|
182
|
+
* Minimum text length around inline link to qualify for inline exception
|
|
183
|
+
*/
|
|
184
|
+
export const INLINE_CONTEXT_MIN_TEXT = 10;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @masup9/a11y-audit
|
|
3
|
+
*
|
|
4
|
+
* Playwright + axe-core based WCAG 2.2 accessibility audit functions.
|
|
5
|
+
*
|
|
6
|
+
* - Main subpath (`@masup9/a11y-audit`): shared types & constants.
|
|
7
|
+
* - `@masup9/a11y-audit/playwright`: the `runXxx()` function API.
|
|
8
|
+
* - `@masup9/a11y-audit/test-entries/*`: ready-to-run compatibility entries,
|
|
9
|
+
* run via a one-line local re-export spec (`import "...test-entries/axe-audit"`).
|
|
10
|
+
* - `@masup9/a11y-audit/schemas`: result types & JSON Schemas.
|
|
11
|
+
*/
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export { AUDIT_DISCLAIMER, DEFAULT_AXE_TAGS, REFLOW_VIEWPORT, TARGET_SIZE_AA, TARGET_SIZE_AAA, } from './constants.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @masup9/a11y-audit
|
|
3
|
+
*
|
|
4
|
+
* Playwright + axe-core based WCAG 2.2 accessibility audit functions.
|
|
5
|
+
*
|
|
6
|
+
* - Main subpath (`@masup9/a11y-audit`): shared types & constants.
|
|
7
|
+
* - `@masup9/a11y-audit/playwright`: the `runXxx()` function API.
|
|
8
|
+
* - `@masup9/a11y-audit/test-entries/*`: ready-to-run compatibility entries,
|
|
9
|
+
* run via a one-line local re-export spec (`import "...test-entries/axe-audit"`).
|
|
10
|
+
* - `@masup9/a11y-audit/schemas`: result types & JSON Schemas.
|
|
11
|
+
*/
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export { AUDIT_DISCLAIMER, DEFAULT_AXE_TAGS, REFLOW_VIEWPORT, TARGET_SIZE_AA, TARGET_SIZE_AAA, } from './constants.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function API for the WCAG audit checks.
|
|
3
|
+
*
|
|
4
|
+
* Import these to wire the checks into your own Playwright tests:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { runAxeAudit } from "@masup9/a11y-audit/playwright";
|
|
8
|
+
*
|
|
9
|
+
* test("axe", async ({ page }, testInfo) => {
|
|
10
|
+
* await page.goto(url);
|
|
11
|
+
* await runAxeAudit({ page, outputDir: testInfo.outputDir });
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { runAxeAudit, type RunAxeAuditOptions } from './runAxeAudit.js';
|
|
16
|
+
export { runFocusIndicatorCheck, type RunFocusIndicatorCheckOptions, } from './runFocusIndicatorCheck.js';
|
|
17
|
+
export { runReflowCheck, type RunReflowCheckOptions } from './runReflowCheck.js';
|
|
18
|
+
export { runTargetSizeCheck, type RunTargetSizeCheckOptions, } from './runTargetSizeCheck.js';
|
|
19
|
+
export { resolveOutputPath, type OutputLocationOptions, } from '../utils/test-harness.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function API for the WCAG audit checks.
|
|
3
|
+
*
|
|
4
|
+
* Import these to wire the checks into your own Playwright tests:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { runAxeAudit } from "@masup9/a11y-audit/playwright";
|
|
8
|
+
*
|
|
9
|
+
* test("axe", async ({ page }, testInfo) => {
|
|
10
|
+
* await page.goto(url);
|
|
11
|
+
* await runAxeAudit({ page, outputDir: testInfo.outputDir });
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { runAxeAudit } from './runAxeAudit.js';
|
|
16
|
+
export { runFocusIndicatorCheck, } from './runFocusIndicatorCheck.js';
|
|
17
|
+
export { runReflowCheck } from './runReflowCheck.js';
|
|
18
|
+
export { runTargetSizeCheck, } from './runTargetSizeCheck.js';
|
|
19
|
+
export { resolveOutputPath, } from '../utils/test-harness.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Axe-core Accessibility Audit (broad WCAG coverage)
|
|
3
|
+
*
|
|
4
|
+
* Runs axe-core automated accessibility testing on the *current* page. The
|
|
5
|
+
* caller is responsible for navigating the page (e.g. `await page.goto(url)`)
|
|
6
|
+
* before calling this function.
|
|
7
|
+
*
|
|
8
|
+
* Axe-core cannot detect all accessibility issues — manual testing and the
|
|
9
|
+
* other checks in this package are still needed for complete coverage.
|
|
10
|
+
*/
|
|
11
|
+
import type { Page } from '@playwright/test';
|
|
12
|
+
import type { AxeAuditResult } from '../types.js';
|
|
13
|
+
import { type OutputLocationOptions } from '../utils/test-harness.js';
|
|
14
|
+
export interface RunAxeAuditOptions extends OutputLocationOptions {
|
|
15
|
+
/** A page already navigated to the target URL. */
|
|
16
|
+
page: Page;
|
|
17
|
+
/** axe-core tags to run with (default: WCAG 2.0/2.1/2.2 A & AA). */
|
|
18
|
+
tags?: readonly string[];
|
|
19
|
+
/** axe rule overrides, forwarded to `AxeBuilder.options({ rules })`. */
|
|
20
|
+
rules?: Record<string, {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Run an axe-core audit against the current page, write the result JSON, and
|
|
26
|
+
* return the parsed result.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runAxeAudit(options: RunAxeAuditOptions): Promise<AxeAuditResult>;
|