@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.ja.md +128 -0
  3. package/README.md +130 -0
  4. package/dist/constants.d.ts +88 -0
  5. package/dist/constants.js +184 -0
  6. package/dist/index.d.ts +13 -0
  7. package/dist/index.js +13 -0
  8. package/dist/playwright/index.d.ts +19 -0
  9. package/dist/playwright/index.js +19 -0
  10. package/dist/playwright/runAxeAudit.d.ts +28 -0
  11. package/dist/playwright/runAxeAudit.js +89 -0
  12. package/dist/playwright/runFocusIndicatorCheck.d.ts +30 -0
  13. package/dist/playwright/runFocusIndicatorCheck.js +740 -0
  14. package/dist/playwright/runReflowCheck.d.ts +36 -0
  15. package/dist/playwright/runReflowCheck.js +68 -0
  16. package/dist/playwright/runTargetSizeCheck.d.ts +35 -0
  17. package/dist/playwright/runTargetSizeCheck.js +389 -0
  18. package/dist/schemas/index.d.ts +34 -0
  19. package/dist/schemas/index.js +245 -0
  20. package/dist/test-entries/axe-audit.d.ts +13 -0
  21. package/dist/test-entries/axe-audit.js +20 -0
  22. package/dist/test-entries/focus-indicator-check.d.ts +9 -0
  23. package/dist/test-entries/focus-indicator-check.js +13 -0
  24. package/dist/test-entries/reflow-check.d.ts +9 -0
  25. package/dist/test-entries/reflow-check.js +21 -0
  26. package/dist/test-entries/target-size-check.d.ts +8 -0
  27. package/dist/test-entries/target-size-check.js +15 -0
  28. package/dist/types.d.ts +215 -0
  29. package/dist/types.js +4 -0
  30. package/dist/utils/annotations.d.ts +67 -0
  31. package/dist/utils/annotations.js +110 -0
  32. package/dist/utils/layout.d.ts +23 -0
  33. package/dist/utils/layout.js +144 -0
  34. package/dist/utils/test-harness.d.ts +76 -0
  35. package/dist/utils/test-harness.js +119 -0
  36. package/package.json +92 -0
@@ -0,0 +1,89 @@
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 { AxeBuilder } from '@axe-core/playwright';
12
+ import { AUDIT_DISCLAIMER, DEFAULT_AXE_TAGS, DEFAULT_AXE_RESULT_FILE, } from '../constants.js';
13
+ import { saveAuditResult, logAuditHeader, logSummary, logOutputPaths, } from '../utils/test-harness.js';
14
+ /**
15
+ * Run an axe-core audit against the current page, write the result JSON, and
16
+ * return the parsed result.
17
+ */
18
+ export async function runAxeAudit(options) {
19
+ const { page, tags = DEFAULT_AXE_TAGS, rules, ...location } = options;
20
+ let builder = new AxeBuilder({ page }).withTags([...tags]);
21
+ if (rules) {
22
+ builder = builder.options({ rules });
23
+ }
24
+ const axeResults = await builder.analyze();
25
+ const result = {
26
+ url: page.url(),
27
+ timestamp: new Date().toISOString(),
28
+ violations: axeResults.violations.map((v) => ({
29
+ id: v.id,
30
+ impact: v.impact ?? null,
31
+ description: v.description,
32
+ help: v.help,
33
+ helpUrl: v.helpUrl,
34
+ tags: v.tags,
35
+ nodes: v.nodes.map((n) => ({
36
+ html: n.html,
37
+ target: n.target,
38
+ failureSummary: n.failureSummary,
39
+ })),
40
+ })),
41
+ passes: axeResults.passes.length,
42
+ incomplete: axeResults.incomplete.length,
43
+ inapplicable: axeResults.inapplicable.length,
44
+ violationCount: axeResults.violations.length,
45
+ disclaimer: AUDIT_DISCLAIMER,
46
+ };
47
+ // Output results
48
+ logAuditHeader('Axe-core Accessibility Audit Results', 'axe-core', result.url);
49
+ logSummary({
50
+ Timestamp: result.timestamp,
51
+ Violations: result.violationCount,
52
+ Passes: result.passes,
53
+ 'Incomplete (needs review)': result.incomplete,
54
+ Inapplicable: result.inapplicable,
55
+ });
56
+ if (result.violations.length > 0) {
57
+ console.log('\n--- Violations ---');
58
+ result.violations.forEach((v, i) => {
59
+ console.log(`\n ${i + 1}. [${v.impact?.toUpperCase() || 'UNKNOWN'}] ${v.id}`);
60
+ console.log(` ${v.help}`);
61
+ console.log(` Affected: ${v.nodes.length} element(s)`);
62
+ console.log(` Tags: ${v.tags.filter((t) => t.startsWith('wcag')).join(', ')}`);
63
+ // Show first 3 affected elements
64
+ v.nodes.slice(0, 3).forEach((n, j) => {
65
+ const htmlPreview = n.html.length > 80 ? n.html.substring(0, 80) + '...' : n.html;
66
+ console.log(` ${j + 1}. ${htmlPreview}`);
67
+ });
68
+ if (v.nodes.length > 3) {
69
+ console.log(` ... and ${v.nodes.length - 3} more`);
70
+ }
71
+ });
72
+ }
73
+ console.log(`\n--- Summary ---`);
74
+ if (result.violationCount === 0) {
75
+ console.log('No violations detected by axe-core');
76
+ }
77
+ else {
78
+ const totalElements = result.violations.reduce((sum, v) => sum + v.nodes.length, 0);
79
+ console.log(`Found ${result.violationCount} violation type(s) affecting ${totalElements} element(s)`);
80
+ }
81
+ // axe results already carry the disclaimer field; don't append it again.
82
+ const resolvedPath = saveAuditResult(result, {
83
+ ...location,
84
+ defaultFile: DEFAULT_AXE_RESULT_FILE,
85
+ includeDisclaimer: false,
86
+ });
87
+ logOutputPaths(resolvedPath);
88
+ return result;
89
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Focus Indicator Visibility Check
3
+ *
4
+ * WCAG 2.4.7 (Focus Visible) / 2.4.12 (Focus Not Obscured) / 3.2.1 (On Focus)
5
+ *
6
+ * Unlike the other checks, this one owns its `BrowserContext`: it tabs through
7
+ * every focusable element and, when focus triggers a navigation (3.2.1), it
8
+ * restarts in a fresh context with the offending element skipped. For that
9
+ * reason it accepts a `browser` (not a `page`) and navigates internally.
10
+ *
11
+ * The context this function creates is closed before it returns.
12
+ */
13
+ import type { Browser, BrowserContextOptions } from '@playwright/test';
14
+ import type { FocusCheckResult } from '../types.js';
15
+ import { type OutputLocationOptions } from '../utils/test-harness.js';
16
+ export interface RunFocusIndicatorCheckOptions extends OutputLocationOptions {
17
+ /** The browser to create audit contexts in. */
18
+ browser: Browser;
19
+ /** Target URL. Falls back to the `TEST_PAGE` env var; required. */
20
+ targetUrl?: string;
21
+ /** Whether to capture a screenshot (default: false). */
22
+ screenshot?: boolean;
23
+ /** Options forwarded to `browser.newContext()` (locale, viewport, storageState, ...). */
24
+ contextOptions?: BrowserContextOptions;
25
+ }
26
+ /**
27
+ * Run the focus indicator check, write the result JSON (and optionally a
28
+ * screenshot), and return the parsed result.
29
+ */
30
+ export declare function runFocusIndicatorCheck(options: RunFocusIndicatorCheckOptions): Promise<FocusCheckResult>;