test: enforce accessible portfolio interaction

This commit is contained in:
2026-09-02 07:01:33 +03:00
parent f953905a4b
commit 5abd1c19ae
8 changed files with 805 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
# Physical screen-reader test scripts
Run these scripts against the exact release candidate. Do not simulate a
screen reader with the accessibility tree, and do not mark a row complete from
automated output. Record the operating-system, browser, and screen-reader
versions plus the commit/build identifier in the WCAG checklist.
## Test states
Use a fresh private window/profile for each state unless the step explicitly
requires saved preference state.
1. **Default** — normal motion preference, sound not started.
2. **Audio running** — activate **START THE DRIVE** once.
3. **Static** — choose **Static** from **Quality**.
4. **Reduced motion** — enable the OS reduced-motion preference before load.
5. **Media/scene failure** — use the release test build's documented failure
setup; never alter production code or expose a public test hook.
6. **Missing social** — use the approved optional-social build fixture; the
email action must remain.
For each platform, repeat Tasks 1–3 and Task 7 in all six states. Run Tasks
4–6 in every state where their content is present. If final project media is
still awaiting approval, record Tasks 5–6 as **not present in candidate — must
re-run when approved media enters the manifest**, not as PASS.
## NVDA + Firefox on Windows
Setup:
- Start NVDA, then Firefox. Record exact versions from NVDA Help → About and
Firefox Help → About.
- Use a fresh Firefox private window at 100% zoom for the default pass.
- Keep NVDA speech viewer open only if it does not change viewport geometry.
- Use `NVDA+F7` for the Elements List, `H`/`Shift+H` for headings,
`D`/`Shift+D` for landmarks, `K`/`Shift+K` for links, `B` for buttons,
`F` for form fields, `Tab`/`Shift+Tab` for focus order, and `Enter`/`Space`
for activation.
Run the seven literal tasks below. Record the exact announcement when an
oracle fails; do not paraphrase the failure.
## VoiceOver + Safari on macOS
Setup:
- Record macOS and Safari versions, enable VoiceOver with `Command+F5`, and
record the VoiceOver version from VoiceOver Utility → About.
- Enable Safari's **Press Tab to highlight each item on a webpage**.
- Use `VO` (`Control+Option`) + `U` for the rotor, `VO+Command+H` for the next
heading, `VO+Command+L` for the next link, `VO+Command+J` for the next form
control, `VO+Right/Left Arrow` for sequential reading, and `VO+Space` to
activate.
Run the seven literal tasks below in Safari. Note whether Quick Nav is on for
each run because it changes key behavior, not page semantics.
## VoiceOver + Safari on iOS
Setup:
- Record device model, iOS version, and Safari build. Enable VoiceOver in
Settings → Accessibility → VoiceOver.
- Set the rotor to Headings, Links, Form Controls, and Containers as needed.
- Use one-finger right/left swipes for sequential navigation, rotor swipes for
category navigation, double-tap to activate, and a four-finger tap near the
top/bottom to move to the first/last accessible item.
- Test portrait at the 320 CSS px-equivalent supported width and landscape.
Run the same seven tasks. Also confirm that touch exploration never lands on
the decorative canvas, road signs, speed, particles, or HUD.
## Seven literal tasks and pass oracles
### 1. Load, identity, structure, and scene description
1. Load the page at the top without interacting.
2. Read from the first accessible item through the main navigation.
3. Open the landmarks/headings rotor or Elements List.
Pass only when:
- the document title identifies Luca Pîslaru and the portfolio role;
- **Skip to portfolio content** is the first actionable item;
- exactly one H1 announces **Luca Pîslaru**, followed by **System
Administrator & Full-Stack Developer**;
- the portfolio navigation has a useful name and ordered section links;
- one concise description explains the restrained retro-futuristic road
journey and portfolio progress;
- the canvas, poster, car, road signs, speed, particles, and HUD do not appear
as separate accessible objects or repeated live announcements.
### 2. Skip link, section navigation, focus, and passive scrolling
1. Return to the top and focus **Skip to portfolio content** with the keyboard
or rotor.
2. Activate it and read the focused item.
3. Navigate back to the section navigation, activate **Infrastructure**, and
read the focused item.
4. Move through **Selected Builds**, **Toolkit**, and **Contact** using only
the navigation links.
5. Put the reading cursor on a navigation link, then scroll manually without
activating it. Use Back/Forward once after an explicit section activation.
Pass only when:
- skip activation lands on the portfolio main content;
- explicit section navigation focuses and announces the correct H2 once;
- logical focus order matches the visible document order;
- focus is visible and not covered by the fixed HUD or drive controls;
- passive scrolling and history restoration do not steal keyboard focus or
relocate the screen-reader reading cursor.
### 3. Start the Drive and audio controls
1. Find **START THE DRIVE** by button navigation.
2. Read the button and its adjacent supporting description before activating.
3. Activate it once, then navigate through the newly exposed sound controls.
4. Activate **Mute sound**, verify the name becomes **Unmute sound**, adjust
**Sound volume**, and mute again before continuing.
Pass only when:
- the control is announced as a button and the nearby text explains that it
enables the interactive soundtrack;
- sound never begins before explicit activation;
- **Mute sound**/**Unmute sound** and **Sound volume** have correct role,
name, and current value/state;
- audio state changes are understandable without repeated or continuous live
announcements and do not drown out assistive-technology speech;
- audio failure, when tested, announces **Audio unavailable** while all
portfolio content remains usable.
### 4. Toolkit labels
1. Navigate to **Toolkit** and enter each technology group.
2. Read at least Linux, Docker, Python, Vue.js, C# / .NET, and the Additional
experience group in sequence.
Pass only when each technology is announced once from its visible text label;
the decorative repeated icon/dot is silent; group headings are announced in
the expected hierarchy; and no percentage, rating, or invented expertise
claim is exposed.
### 5. Chart descriptions and data tables
1. Navigate to the Opinion Dynamics Simulation chart group, if present in the
approved candidate.
2. Read the figure caption, adjacent Variables, Trend, and Conclusion fields.
3. Enter any data table by table navigation and traverse its headers and at
least two data cells.
Pass only when the purpose, axes/variables, trend, and conclusion are usable
without inspecting color or pixels; each table has a useful caption and
associated row/column headers; and the image alt does not redundantly recite
the full adjacent description.
### 6. Authored video controls and failure fallback
1. Navigate to an approved project video, if present in the candidate.
2. Read its name, caption, structured description, initial status, and authored
**Play video** control.
3. Activate Play, verify **Pause video**, pause, then repeat with OS reduced
motion enabled.
4. Run the approved media-failure state and revisit the same figure.
Pass only when no sound autoplays; reduced motion begins from a poster until
explicit Play; the authored button exposes the correct play/pause state; the
caption/description remains available; failure exposes **Video unavailable**
and explanatory text; and inaccessible user-agent shadow controls are not the
only control surface.
### 7. Contact and optional social links
1. Navigate to **Contact** by heading and by the section navigation.
2. Read Luca's name, role, visible email address, CV/contact note, and every
optional profile link.
3. Inspect the email link's destination/purpose without sending mail.
4. Repeat in the missing-social state.
Pass only when:
- the visible email and primary `mailto:` action are announced with an
unambiguous purpose;
- GitHub, GitLab, and LinkedIn have distinct visible/accessibility names when
present;
- missing optional social links are omitted rather than announced as empty,
disabled, or placeholder controls;
- the email action remains reachable and the page exposes no CV download.
## Result template
Copy one row per state/platform into the WCAG checklist evidence log:
```text
Date/time:
Build/commit:
OS/device:
Browser + version:
Screen reader + version:
State:
Tasks run: 1 2 3 4 5 6 7
Result: PASS / FAIL / NOT PRESENT — RE-RUN REQUIRED
Exact failed announcement or interaction:
Screenshot/speech-viewer/video evidence location (private):
Tester:
```
Never place private hostnames, private project names, credentials, personal
account identifiers, or uncleared media in the committed evidence log.

View File

@@ -0,0 +1,119 @@
# WCAG 2.2 A/AA release checklist
This is a release checkpoint for the portfolio, not a claim that automated
testing can certify accessibility. Automated checks are complete for the
current preview build. The named physical screen-reader runs and final visual
review remain **pending release evidence**, not code failures.
## Evidence status
| Evidence | Current result | Re-run trigger |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Axe WCAG A/AA scan | **PASS** — default, audio running, Static, reduced motion, scene/media failure, and missing optional social links; desktop and mobile Chromium | Any rendered markup, color token, control, or state change |
| Author target geometry | **PASS** — every enabled `a`, `button`, `input`, `select`, and `textarea` is at least 44×44 CSS px; only a paragraph-contained link with `data-target-size-exception="inline-link"` may be exempt | Any new or restyled interactive element |
| Keyboard and focus geometry | **PASS** — logical navigation reaches Contact; focus is visible, in the visual viewport, and has zero intersection with unrelated fixed controls | Navigation, focus, HUD, or control-surface changes |
| Reflow | **PASS** — 320 CSS px mobile and desktop-Chromium effective 320 CSS px at the 400% zoom boundary | Layout, typography, media, or control changes |
| WCAG text spacing | **PASS** — 1.5 line height, 0.12em letter spacing, 0.16em word spacing, and 2em paragraph spacing preserve content and controls | Copy or layout changes |
| Forced colors | **PASS** — focus, borders, controls, content, and Contact remain visible and usable | Color, border, focus, or control changes |
| No-JavaScript and SSR | **PASS in the project browser/build gates** — semantic sections, native links, and Contact do not depend on hydration | Rendering or hydration changes |
| NVDA + Firefox on Windows | **PENDING PHYSICAL RUN** — use `screen-reader-scripts.md`; record versions and results below | Before public release and after material semantic changes |
| VoiceOver + Safari on macOS | **PENDING PHYSICAL RUN** — use `screen-reader-scripts.md`; record versions and results below | Before public release and after material semantic changes |
| VoiceOver + Safari on iOS | **PENDING PHYSICAL RUN** — use `screen-reader-scripts.md`; record versions and results below | Before public release and after material semantic/touch changes |
| Final visual focus/overflow review | **PENDING RELEASE REVIEW** — automated geometry is necessary but not sufficient | Before public release |
| Final encoded-media flash/caption review | **PENDING ASSET APPROVAL** — current public preview has no cleared project media | When any approved video/chart/image derivative is added |
Focused command:
```bash
npm run test:browser -- tests/browser/accessibility-axe.spec.ts tests/browser/accessibility-keyboard.spec.ts tests/browser/accessibility-reflow.spec.ts tests/browser/accessibility-forced-colors.spec.ts
```
The focused run on 2026-09-02 produced 24 passes and two intentional
project-profile skips: the 320 CSS px mobile case runs only in the mobile
profile, and the desktop 400% zoom-equivalent case runs only in the desktop
profile. No axe violation is suppressed. No false-positive exception is
currently recorded.
## Criterion checklist
Status meanings:
- **Automated PASS**: the current preview has repeatable browser/build evidence.
- **Manual pending**: a physical assistive-technology or visual run is required
before release.
- **N/A current surface**: the current public output does not expose the
relevant feature. Adding that feature reopens the criterion.
| WCAG 2.2 criterion | Status | Current evidence / release action |
| ----------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.1.1 Non-text Content | Automated PASS; manual pending | Decorative world/canvas/poster are hidden or empty-alt; one concise scene description is semantic. Approved project media must keep authored alt/description. |
| 1.2.1 Audio-only and Video-only (Prerecorded) | N/A current surface | Generated ambience is interactive, not prerecorded speech. Reopen for approved prerecorded media. |
| 1.2.2 Captions (Prerecorded) | N/A current surface | No cleared public video. Reopen and verify captions when a video derivative is approved. |
| 1.2.3 Audio Description or Media Alternative | N/A current surface | Video component supports an adjacent structured description; verify the final approved clip manually. |
| 1.2.4 Captions (Live) | N/A current surface | No live media. |
| 1.2.5 Audio Description (Prerecorded) | N/A current surface | Reopen for approved prerecorded video. |
| 1.3.1 Info and Relationships | Automated PASS; manual pending | Native landmarks, headings, lists, figures, captions, definition lists, and tables; confirm screen-reader output. |
| 1.3.2 Meaningful Sequence | Automated PASS; manual pending | SSR DOM order remains the reading order; decorative world is excluded. |
| 1.3.3 Sensory Characteristics | Automated PASS | Instructions and state do not depend only on location, shape, or color. |
| 1.3.4 Orientation | Automated PASS | Responsive checks do not lock orientation. |
| 1.3.5 Identify Input Purpose | N/A current surface | No personal-data form inputs. |
| 1.4.1 Use of Color | Automated PASS; visual pending | State controls use visible text and native state, not color alone. |
| 1.4.2 Audio Control | Automated PASS; manual pending | Sound starts only after explicit activation and immediately exposes Mute and Sound volume. |
| 1.4.3 Contrast (Minimum) | Automated PASS; visual pending | Axe reports no contrast violation in all named states; final visual review is required. |
| 1.4.4 Resize Text | Automated PASS | Desktop Chromium effective 320 CSS px gate represents the 400% zoom boundary. |
| 1.4.5 Images of Text | Automated PASS | Information is text/semantic HTML; project screenshots do not replace portfolio copy. |
| 1.4.10 Reflow | Automated PASS | No horizontal loss at 320 CSS px mobile or desktop zoom-equivalent width. |
| 1.4.11 Non-text Contrast | Automated PASS; visual pending | Control/focus/border visibility survives forced colors; final visual review remains. |
| 1.4.12 Text Spacing | Automated PASS | WCAG spacing override preserves all checked content and Contact. |
| 1.4.13 Content on Hover or Focus | N/A current surface | No hover/focus-triggered disclosure or tooltip. |
| 2.1.1 Keyboard | Automated PASS; manual pending | Native links/buttons/select/range and section navigation are operable by keyboard. |
| 2.1.2 No Keyboard Trap | Automated PASS; manual pending | Tab traversal reaches Contact and continues to the drive controls. |
| 2.1.4 Character Key Shortcuts | N/A current surface | No single-character shortcuts. |
| 2.2.1 Timing Adjustable | N/A current surface | No session or content timeout. |
| 2.2.2 Pause, Stop, Hide | Automated PASS; manual pending | Pause/Resume/Static controls stop decorative motion; authored video controls are required when media ships. |
| 2.3.1 Three Flashes or Below Threshold | Manual pending | Final live scene and any encoded media need release visual/flash review. No flashing project media ships currently. |
| 2.4.1 Bypass Blocks | Automated PASS; manual pending | First focusable control is the visible Skip to portfolio content link. |
| 2.4.2 Page Titled | Automated PASS | Generated document title names Luca and the hybrid role. |
| 2.4.3 Focus Order | Automated PASS; manual pending | Skip, ordered section navigation, content actions, Contact, then drive controls. |
| 2.4.4 Link Purpose (In Context) | Automated PASS; manual pending | Visible labels identify section, email, and profile destinations. |
| 2.4.5 Multiple Ways | Automated PASS | Persistent section navigation and native document scrolling provide two ways to reach content. |
| 2.4.6 Headings and Labels | Automated PASS; manual pending | Ordered headings and explicit control labels; confirm announcements. |
| 2.4.7 Focus Visible | Automated PASS; visual pending | At least 2px visible indicator or an inset main-content indicator; forced-colors gate passes. |
| 2.4.11 Focus Not Obscured (Minimum) | Automated PASS; visual pending | Focus bounds have zero intersection with unrelated fixed HUD/controls; short viewports move controls into document flow. |
| 2.5.1 Pointer Gestures | N/A current surface | No multipoint or path-based gesture. |
| 2.5.2 Pointer Cancellation | Automated PASS | Native click activation occurs on release; no custom down-only action. |
| 2.5.3 Label in Name | Automated PASS | Visible button/link labels are their accessible names. |
| 2.5.4 Motion Actuation | N/A current surface | No device-motion input. |
| 2.5.7 Dragging Movements | N/A current surface | No drag-only operation. |
| 2.5.8 Target Size (Minimum) | Automated PASS | 44×44 CSS px author-target gate on desktop and mobile; exception syntax/context is validated. |
| 3.1.1 Language of Page | Automated PASS | Generated root document declares English. |
| 3.1.2 Language of Parts | N/A current surface | No passage in another natural language. |
| 3.2.1 On Focus | Automated PASS | Focus alone does not navigate or change context. |
| 3.2.2 On Input | Automated PASS | Quality/volume changes are explicit and do not unexpectedly navigate. |
| 3.2.3 Consistent Navigation | Automated PASS | One canonical ordered section navigation is retained across states. |
| 3.2.4 Consistent Identification | Automated PASS | Motion/audio controls retain consistent names and semantics. |
| 3.2.6 Consistent Help | N/A current surface | No repeated help mechanism. |
| 3.3.1 Error Identification | Automated PASS for current controls | Audio/media failures expose concise text status without blocking content. |
| 3.3.2 Labels or Instructions | Automated PASS; manual pending | Quality and Sound volume are labeled; Start the Drive has adjacent purpose text. |
| 3.3.3 Error Suggestion | N/A current surface | No correctable data-entry error. |
| 3.3.4 Error Prevention (Legal, Financial, Data) | N/A current surface | No transaction or user-data submission. |
| 3.3.7 Redundant Entry | N/A current surface | No multi-step data entry. |
| 3.3.8 Accessible Authentication (Minimum) | N/A current surface | No authentication. |
| 4.1.2 Name, Role, Value | Automated PASS; manual pending | Native controls plus current `aria-current`, status roles, and range/select values; confirm platform output. |
| 4.1.3 Status Messages | Automated PASS; manual pending | Motion/audio/video status text is exposed without forced focus; verify it is useful and not repetitive. |
## Physical evidence log
Do not change a row to PASS without running the literal script in
`screen-reader-scripts.md` on the named platform.
| Date | Platform | Browser + version | Screen reader + version | Build/commit | States covered | Result | Notes/evidence |
| ------- | -------- | ------------------------ | ---------------------------------- | ------------- | ---------------------------------------- | ----------- | ----------------------------------------- |
| Pending | Windows | Firefox — record version | NVDA — record version | record commit | all six | **PENDING** | Physical run required |
| Pending | macOS | Safari — record version | VoiceOver + macOS — record version | record commit | all six | **PENDING** | Physical run required |
| Pending | iOS | Safari — record version | VoiceOver + iOS — record version | record commit | default, reduced, Static, audio, failure | **PENDING** | Physical touch/screen-reader run required |
Any failed manual oracle is a release blocker until fixed or, when genuinely
not applicable, documented with concrete evidence. Pending platform evidence
does not imply that the implementation test suite is failing; it means the
release checkpoint is not yet signed off.