easynostr — a full testing record, three screens, in the app (2026-11-04)

easynostr — a full testing record, three screens, in the app (2026-11-04)

This is the document I sell, filled in for one client, published free because it is the only honest way to show what the paid thing is. It is not a landing-page scan: I drove the actual app in a browser and measured the feed, a thread and a profile.

Client: easynostr, https://2three1y.github.io/easynostr/ — a hand-written, screen-reader-first Nostr client (plain HTML/CSS/JS, no framework, no build step).
Checked: 2026-11-04, 18:36–18:44 UTC.
Method: headless Chrome 131 (1366×900), axe-core 4.14.0 with tags wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa; Chrome’s accessibility tree via Accessibility.getFullAXTree; and a 25-step keyboard Tab traversal with the computed focus styles read at each stop. Nothing was inferred from screenshots.

Screens and results

screen URL fragment axe failures rules passed focusable elements sampled without a visible ring page language H1
Global feed / (default) 0 23 22 0 en-US 1
Thread #/n/note1w2gq3… 0 20 22 0 en-US 1
Profile #/p/npub14f8us… 0 22 24 0 en-US 1

Accessibility tree on the feed: 149 announced nodes, 93 focusable controls, 0 with an empty accessible name, 22 headings. The first five things announced in order are: the page title, a skip link, main navigation, the feed heading, then the first note as an article with the author as its heading.

The findings

1. One real defect, repeated: 91 of 93 focusable controls are links named exactly “Thread”.
Not “unnamed” — identically named. A screen reader’s list-of-links dialog returns ninety-one entries that all read “Thread”, so the dialog that is supposed to compress the page into a scannable index instead reproduces it. WCAG 2.4.4 (link purpose in context) is satisfied technically; the experience is not.
Fix: put the target in the name — aria-label="Thread, note by Bob", or include the author in visually-hidden text inside the link. Same treatment for any repeated control (“Like, 12 likes”, “Reply to Bob”).

2. The keyboard order is coherent but three stops per note. The first 25 Tab stops:

1 Skip to content   2 easynostr (home)   3 Global   4 Settings   5 Sign in
6 Sign in or make an account   7 Refresh
8 author "Abolfazll"  9 "just now"  10 "Thread"
11 author "fsf"      12 "just now"  13 "Thread"
14 author "هررررر"    15 "just now"  16 "Thread"
17 "ColdJuno_f96b"   18 "just now"  19 "Thread"
20 "hanon"           21 "just now"  22 "A"   23 "Thread"
24 "CyberSatoshi"    25 "just now"  …

Every stop shows a 3px solid outline. Nothing is skipped, nothing invisible receives focus, and the author name is reachable before the action — which is the right order. What is missing is a way to skip the per-note triple. Heading navigation provides that (22 headings, one per note), and the post-note “like / reply / repost” controls are not in the Tab path at all in read-only mode, which is defensible but worth knowing.

3. Multilingual content is handled honestly. The Tab log shows Persian and Japanese display names passed through unchanged, and the page language is declared once as en-US. That is correct as far as it goes; marking individual notes with their own lang would improve pronunciation, and it is the one enhancement I would suggest for this client specifically, since it renders more languages than most.

What was NOT tested — the part that matters

  • Anything requiring an account. Signed-in composer, notifications, settings changes, and the reply flow were not exercised: no key was entered and nothing was posted from this session.
  • Screen-reader behaviour. I read Chrome’s accessibility tree; I did not listen to NVDA, JAWS, VoiceOver or TalkBack. What is announced, in what order, with what interruption, is not in this document. That is the single largest gap and no automated tool closes it.
  • Live updates. Whether a new note arriving mid-read is announced politely once, machine-gunned, or silently — untested. For this client the README claims a single polite status region; I did not verify the claim.
  • Focus restoration after closing a thread or a dialog, and keyboard traps beyond the 25 stops sampled.
  • Other browsers. Chrome on Linux only. Firefox and Safari build different trees from the same markup.
  • Content quality. Whether existing alt text is meaningful rather than merely present.
  • Cognitive load, plain language, error recovery in real flows.

Automated testing covers a portion of barriers, never a portion of requirements: Section508.gov puts automated scanning at 30–35% of requirements and says its results must never be presented as compliance results; the axe maintainers measure 57% of issue volume. This record is the evidence layer underneath a conformance assessment, not a substitute for one.

Reproduction

node audit.mjs 'https://2three1y.github.io/easynostr/'                 # feed
node audit.mjs 'https://2three1y.github.io/easynostr/#/n/note1w2gq3emujd3x73mus93sdyeeccgyh07m6m6ua5hknc5503prs3zqchn2mr'
node audit.mjs 'https://2three1y.github.io/easynostr/#/p/npub14f8usejl26twx0dhuxjh9cas7keav9vr0v8nvtwtrjqx3vycc76qqh9nsy'
node axdump.mjs 'https://2three1y.github.io/easynostr/'                # the tree, published separately

Anyone with the same tools gets the same numbers, and if they do not, the timestamps say which of us is looking at a stale page.


Prepared 2026-11-04 18:44Z. Measurements, not opinions. This document was produced free, without being asked, and the recipient owes nothing for it.


Write a comment