crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

AccessibilityTesting.md (6824B)


      1 # Testing the grid's VoiceOver support
      2 
      3 How to verify the Phase 1 grid accessibility work (see PLAN.md): synthetic
      4 per-cell VoiceOver elements over the Canvas-drawn grid, two-way focus/cursor
      5 sync, and double-tap activation.
      6 
      7 There are two tiers. The Simulator can only verify *structure* — it cannot run
      8 VoiceOver. Focus behaviour, the typing echo, and trait announcements need a
      9 physical device.
     10 
     11 ## Tier 1: Simulator + Accessibility Inspector (structure)
     12 
     13 The synthetic elements are normally built only while VoiceOver is running, and
     14 Accessibility Inspector doesn't set that flag — so debug builds accept a
     15 launch argument that forces them on.
     16 
     17 1. In Xcode: Product → Scheme → Edit Scheme… → Run → Arguments, and add
     18    `-ForceGridAccessibility` to "Arguments Passed On Launch". Without it the
     19    grid exposes nothing in the Simulator, by design.
     20 2. Run the app in the Simulator and open a puzzle.
     21 3. Xcode menu → Open Developer Tool → **Accessibility Inspector**.
     22 4. In the Inspector's top-left target dropdown, pick the Simulator.
     23 5. Click the crosshair (inspection pointer) button, then hover/click over grid
     24    cells in the Simulator. For each open cell, check:
     25    - **Label** reads like "5 Across, letter 2 of 7; 3 Down, letter 4 of 5"
     26      (one half only when the cell isn't part of a crossing word; "circled" /
     27      "shaded" suffixes on special cells).
     28    - **Value** reads "Empty", "R", "R, draft", "R, revealed", "R, incorrect",
     29      and in a shared game "R, filled by Alice" / "filled by you".
     30    - The **frame highlight** sits exactly on the drawn cell.
     31 6. Use the Inspector's next/previous element arrows to step through elements —
     32    this approximates VoiceOver's flick order. It should walk the grid row by
     33    row, skipping blocks entirely. Enable the speak option to hear it.
     34 
     35 This proves elements exist, frames line up, strings are right, and blocks are
     36 gaps. It does **not** exercise VoiceOver's focus engine.
     37 
     38 ## Tier 2: iPhone/iPad + real VoiceOver (behaviour)
     39 
     40 No launch argument needed — real VoiceOver enables the elements.
     41 
     42 **Setup — do this first.** Settings → Accessibility → Accessibility Shortcut →
     43 VoiceOver. Triple-clicking the side button now toggles VoiceOver, so you can
     44 always bail out. (Or tell Siri "turn VoiceOver on/off".)
     45 
     46 **Gesture primer** (VoiceOver changes every gesture):
     47 
     48 - **Drag a finger** — touch exploration: speaks whatever is under it.
     49 - **Flick right / left** — next / previous element.
     50 - **Double-tap anywhere** — activate the focused element.
     51 - **Three-finger swipe** — scroll.
     52 
     53 **Checklist** — open a puzzle, then verify in order:
     54 
     55 1. **Touch exploration.** Slowly drag a finger across the grid. Each open cell
     56    speaks its label/value as your finger crosses it; blocks are silent gaps.
     57    The boundaries you hear must match the cells you see.
     58 2. **Flick navigation.** Flick right repeatedly: cells in row-major order, and
     59    the clue bar follows your flicks (focus → selection sync).
     60 3. **Selected trait.** The cell matching the app's cursor is read with
     61    "selected", and it tracks as the cursor moves.
     62 4. **Double-tap.** On the focused cell this toggles Across/Down. With
     63    Phase 2 in place this is no longer silent: the toggle announces the new
     64    word — "5 Down: <clue text>. 5 letters, 2 filled".
     65 5. **Typing echo — the big one.** Flick to the on-screen keyboard, double-tap
     66    a letter key. VoiceOver focus should jump back to the grid on the *next*
     67    cell and read it. This is the open risk flagged in PLAN.md
     68    (`accessibilityFocused` inside an `accessibilityChildren` synthetic
     69    hierarchy is not a documented pattern). **If focus stays on the keyboard
     70    key instead**, the fallback is to switch the synthetic children to a real
     71    clear, non-hit-testable overlay of per-cell views — a small, mechanical
     72    change.
     73 
     74 **Phase 2 checklist** — continue on device:
     75 
     76 6. **Clue announcements.** Flick (or double-tap a next-word key) so the
     77    cursor crosses into a different word: after the landed cell reads, you
     78    should hear "5 Across: <clue text>. 7 letters, 3 filled" — once per word
     79    change, silent while moving within a word. Listen for the announcement
     80    *colliding* with the cell reading (talking over it or cutting it off);
     81    if it does, note it — the fix is lowering the announcement priority.
     82 7. **Rotors.** With focus on a grid cell, **twist two fingers on the screen**
     83    (like turning a dial) — the rotor menu should include "Across clues",
     84    "Down clues", and "Incomplete clues" alongside the system entries. Pick
     85    one, then **flick up / down** (not left/right) to jump between clues.
     86    Each jump should land focus on the word's first cell with the direction
     87    set to match, and fire the clue announcement.
     88 8. **Incomplete rotor narrows.** Fill a word completely, return to the
     89    "Incomplete clues" rotor: that clue should be gone. (On a puzzle with
     90    deliberate gap cells, a word whose only empty square is a gap counts as
     91    complete.)
     92 
     93 **Phase 3 checklist** — the last two items need a second device on a shared
     94 game:
     95 
     96 9. **Custom actions.** Focus a grid cell, then **swipe up or down with one
     97    finger** to cycle its actions: "Switch Direction", and — unless the
     98    puzzle is solved — "Check Square", "Check Word", "Reveal Square".
     99    Double-tap to run the highlighted one. Check announces its verdict
    100    ("Correct", "1 square incorrect", "No mistakes, 1 square empty");
    101    reveal announces the letter ("Revealed R").
    102 10. **Completion announcements.** Fill the last square of a puzzle with a
    103     mistake somewhere: you should hear "The grid is full, but something
    104     isn't right". Fix it: "Puzzle solved. Congratulations!" — listen for
    105     collision with the success panel's own appearance.
    106 11. **Peer fills (two devices).** With the puzzle open on this device, have
    107     the co-player type a word on the other. About 2 seconds after they
    108     stop you should hear one coalesced low-priority announcement — "Alice
    109     filled 3 squares in 5 Across", or "Alice filled 5 Across" if they
    110     completed it — never one announcement per letter, and never
    111     interrupting your own typing echo mid-word.
    112 12. **Local edits stay silent.** Type and delete letters yourself,
    113     including undo/redo: no "filled" announcements should fire for your
    114     own activity. (Known gap: a peer *clearing* squares is silent too.)
    115 
    116 Tip: Accessibility Inspector can also target a physical device for the
    117 structural checks, but the focus/typing behaviour only shows up under genuine
    118 VoiceOver. The rotor, custom actions, and announcements cannot be exercised
    119 from the Inspector at all — device only.
    120 
    121 For the eventual end-to-end test (Phase 2's exit criterion — a full solve with
    122 the screen off): triple-tap with three fingers toggles Screen Curtain while
    123 VoiceOver is running.