Skip to content

Accessibility Audit 1.1.0: the dry submit tests forms with no data sent - #1

Merged
HosseinKarami merged 1 commit into
mainfrom
feat/dry-submit
Oct 26, 2026
Merged

HosseinKarami merged 1 commit into
mainfrom
feat/dry-submit

Conversation

@HosseinKarami

Copy link
Copy Markdown
Member

Summary

Until now, the engine did not type or submit on production, so the form error tests (3.3.1, 3.3.3) ran only in a process on staging. This change adds the dry submit: the engine submits each form on the sample pages and tests the errors that the page shows, while a guard in the browser keeps the data from leaving.

The plan is in FORMS.md. It has three parts: the dry submit (built here), real submits on staging (a checklist for each site), and a test account for the sign-in.

What the dry submit does

  • On each sample page, at the first width, the engine finds the forms. A form needs a text field and a submit control. Search forms are skipped. The limit is three forms on each page, and a form that repeats on many pages is tested once.
  • Submission A: the form empty. Submission B: each text field filled with a11y-dry-submit. B runs only when A showed errors. Each submission has its own render.
  • The tests: error-not-in-text, error-not-linked (3.3.1), error-without-suggestion (3.3.3), the new error-not-announced (4.1.3), then the state tests on the error state.
  • A form that tried to send and showed no error checks on the server only. The coverage lists it, and its page is not counted as tested for 3.3.1 and 3.3.3.

The guard

After the guard starts, the browser blocks:

  • each request that is not GET or HEAD
  • each page, frame, fetch, XHR, beacon, or event stream request
  • each script request with no .js path
  • each request to another host
  • each address that contains a typed value

Service workers are blocked, and a WebSocket cannot send.

Proof

  • tests/dry-submit.mjs (now in npm test) uses 11 ways to send a form: fetch POST, POST form, GET form, fetch GET, JSONP to the site and to another host, beacon, new window, frame, pixel, and WebSocket.
    • A control run with no guard shows that each way reaches the test server.
    • With production settings, the server gets nothing.
    • It also checks the seeded faults F59 (3.3.1) and F61 (3.3.3) with no process.
  • npm test passes. The full seeded detection finds 74 of 74, with no new side findings.
  • A short audit of refact.co/contact: the form uses the browser's own check on purpose, so the dry submit reported "native", and no request was blocked after the click.

Other changes

  • The setting interaction.dry_submit (default true) and coverage.forms_tested in the summary.
  • The form tests accept "Enter ..." as the suggestion for an empty field. This removed two false questions from the seeded run.
  • Rule texts for the AI review and the report, and updates to the docs (PLAN.md, README.md, SKILL.md).
  • Version 1.1.0 in the package and the plugin.

Not in this PR

Part 2 (a safe staging for each site) and part 3 (test accounts) are setup tasks on the sites, listed in FORMS.md.

The engine clicks the submit button of each form on the sample pages, first
empty, then with an incorrect value in each text field, and tests the errors
that the page shows: 3.3.1, 3.3.3, and a new 4.1.3 rule for errors that a
screen reader does not announce. A guard in the browser blocks each request
that can carry the data, so the dry submit is safe on production.

- FORMS.md: the plan for the form tests (dry submit, real submit on staging,
  test account for the sign-in).
- src/own/dry-submit.ts: the form finder, the guard, and the submission test.
- tests/dry-submit.mjs: eleven ways to send a form, a control run with no
  guard, and the seeded faults F59 and F61 with production settings. In
  npm test.
- The setting interaction.dry_submit (default true) and coverage.forms_tested.
- The form tests accept "Enter ..." as the suggestion for an empty field.
@HosseinKarami
HosseinKarami merged commit f4c92e2 into main Oct 26, 2026
1 check passed
@HosseinKarami
HosseinKarami deleted the feat/dry-submit branch October 26, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant