waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ app src shared wcag.ts

3,2 KB Rohdatei
app/src/shared/wcag.ts — 82 Zeilen
1 /**
2 * Der Prüfmaßstab für Barrierefreiheit – an einer einzigen Stelle.
3 *
4 * ## Warum eine gemeinsame Konstante
5 *
6 * Der Regelsatz stand vorher an elf Stellen einzeln im Quelltext, und genau
7 * deshalb war er auseinandergelaufen: acht Stellen prüften gegen WCAG 2.1,
8 * zwei gegen 2.2, eine benutzte bereits eine Konstante. Der Anspruch dieses
9 * Projekts ist aber überall derselbe – **WCAG 2.2 AA**, siehe `PLAN.md` § 6.3.
10 * Eine Kopie, die man vergisst mitzuziehen, ist keine Nachlässigkeit im
11 * Kleinen: Sie senkt den Maßstab an einer Stelle, an der niemand hinsieht.
12 *
13 * ## Was der Regelsatz allein NICHT leistet
14 *
15 * Nachgemessen an axe-core 4.13.0: Am Tag `wcag22aa` hängt **genau eine**
16 * Regel – `target-size` (SC 2.5.8) –, und die steht auf `enabled: false`.
17 * Ein Tag in `runOnly` schaltet eine abgeschaltete Regel **nicht** ein. Wer
18 * die Tagliste erweitert und das als „wir prüfen jetzt 2.2 AA" verbucht,
19 * verbucht eine Null als Erfolg.
20 *
21 * Scharf wird die Regel erst über {@link FENSTER_REGELN}, und zwar
22 * ausschließlich im echten Fenster – siehe dort.
23 */
24 export const WCAG_TAGS = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'] as const;
25
26 /**
27 * Regelabweichungen für Läufe in **jsdom** (Vitest, `app/tests`).
28 *
29 * ## Das ist kein Schlupfloch
30 *
31 * Beide Regeln gelten unverändert. Sie sind hier nur deshalb abgeschaltet,
32 * weil jsdom kein Layout rechnet und sie dort nichts messen **können** – sie
33 * würden nicht bestehen, sie würden schweigen oder, schlimmer, falsch
34 * bestehen. Geprüft werden sie im echten Fenster, siehe
35 * {@link FENSTER_REGELN}.
36 *
37 * - `color-contrast` braucht gerechnete Farben. Unter jsdom landet die Regel
38 * mangels CSS in `incomplete` statt in `violations` – ein stilles Nichts.
39 * - `target-size` ist noch heikler: Nachgemessen meldet sie unter jsdom für
40 * einen 8×8-Pixel-Knopf **„bestanden"**, weil jedes
41 * `getBoundingClientRect()` dort `0×0` liefert und die Nachbarschafts-
42 * rechnung degeneriert. Ein grünes Signal, das nichts gemessen hat, ist
43 * schlechter als gar keins.
44 */
45 export const JSDOM_REGELN = Object.freeze({
46 'color-contrast': { enabled: false },
47 'target-size': { enabled: false },
48 });
49
50 /**
51 * Regelabweichungen für Läufe im **echten Fenster** (Playwright, `app/e2e`).
52 *
53 * Hier rechnet Chromium Layout und Farben – erst hier lässt sich WCAG 2.2 AA
54 * tatsächlich messen. `target-size` muss ausdrücklich eingeschaltet werden,
55 * weil axe-core sie standardmäßig abgeschaltet ausliefert und der Tag sie
56 * nicht aktiviert.
57 */
58 export const FENSTER_REGELN = Object.freeze({
59 'target-size': { enabled: true },
60 });
61
62 /** Optionen für einen axe-Lauf unter jsdom. */
63 export function jsdomOptionen(): {
64 runOnly: { type: 'tag'; values: string[] };
65 rules: Record<string, { enabled: boolean }>;
66 } {
67 return {
68 runOnly: { type: 'tag', values: [...WCAG_TAGS] },
69 rules: { ...JSDOM_REGELN },
70 };
71 }
72
73 /** Optionen für einen axe-Lauf im echten Fenster. */
74 export function fensterOptionen(): {
75 runOnly: { type: 'tag'; values: string[] };
76 rules: Record<string, { enabled: boolean }>;
77 } {
78 return {
79 runOnly: { type: 'tag', values: [...WCAG_TAGS] },
80 rules: { ...FENSTER_REGELN },
81 };
82 }