The accessibility suite checks a list of pages somebody has to remember to extend #66

Closed
opened 2026-09-06 16:05:58 +00:00 by tiagoagueda · 0 comments
Owner

What exists today

tests/e2e/test_accessibility.py runs axe-core over 55 addresses in light and dark, at
WCAG 2 A and AA plus best practice, and fails on any violation. It is a good suite and it
passes.

The addresses are a Python list, written by hand. A page added tomorrow is not in it, and
nothing says so.

What is not being checked

Comparing that list against the project's URL patterns, roughly thirty pages a person can
reach are never visited by it. Among them:

  • /applications/suggestions/ — the whole review queue from #34, added after the list
    was last extended;
  • /documents/letters/new/, /documents/letters/<pk>/, /documents/letters/<pk>/edit/
    and the preview;
  • /documents/cvs/<pk>/, its edit page, and entries/add/;
  • /jobs/contacts/new/, /jobs/industries/new/, /jobs/captures/new/,
    /jobs/captures/<pk>/review/, /jobs/postings/<pk>/;
  • /applications/<pk>/events/new/, the interview edit and outcome pages, the tag forms;
  • every delete confirmation page;
  • /settings/connections/<pk>/ and the per-plugin add form;
  • /accounts/signup/, /accounts/email/, the recovery-codes and TOTP activation pages;
  • the 404 and 500 pages, which are exactly the pages somebody is on when they are
    already lost;
  • the Django admin, which #49 is about to make people use.

All of them answer 200 when asked, so this is a coverage gap and not a list of broken
pages.

Shape

Enumerate rather than list. Walk the URL resolver, keep the patterns that take no
arguments or whose arguments the fixture can fill, and check every one. Then a page added
without being checked is a failure, which is the property the current list cannot have.

  • Patterns needing an object get their argument from the furnished fixture, which already
    builds an application, a company, a contact, an interview and a reminder.
  • Anything genuinely not checkable — a file download, an .ics, a redirect — goes in a
    small named exclusion list with its reason, the way IGNORED_RULES already is.
  • The error pages are reached by asking for something that is not there and by a view that
    raises, with DEBUG off.
  • The admin is Django's, not Postulo's, so it is worth checking and worth its own
    exclusions.

What this does not fix, and should be written into the module

The suite passed, in both themes, on a sign-in page that turned out to be completely
unstyled (see the companion issue). Everything axe measures was correct. A page can be
machine-perfect and unusable, so the docstring should say what this suite is for — a
regression net for the things a machine can check — and that it is not evidence that a
page is good.

Classification

Enhancement, accessibility. Not breaking; it is test-only.

Depends on

Nothing. Better landed after the unstyled-pages fix, so the new coverage starts green.

## What exists today `tests/e2e/test_accessibility.py` runs axe-core over 55 addresses in light and dark, at WCAG 2 A and AA plus best practice, and fails on any violation. It is a good suite and it passes. The addresses are a Python list, written by hand. A page added tomorrow is not in it, and nothing says so. ## What is not being checked Comparing that list against the project's URL patterns, roughly thirty pages a person can reach are never visited by it. Among them: - **`/applications/suggestions/`** — the whole review queue from #34, added after the list was last extended; - `/documents/letters/new/`, `/documents/letters/<pk>/`, `/documents/letters/<pk>/edit/` and the preview; - `/documents/cvs/<pk>/`, its edit page, and `entries/add/`; - `/jobs/contacts/new/`, `/jobs/industries/new/`, `/jobs/captures/new/`, `/jobs/captures/<pk>/review/`, `/jobs/postings/<pk>/`; - `/applications/<pk>/events/new/`, the interview edit and outcome pages, the tag forms; - every **delete confirmation** page; - `/settings/connections/<pk>/` and the per-plugin add form; - `/accounts/signup/`, `/accounts/email/`, the recovery-codes and TOTP activation pages; - the **404 and 500** pages, which are exactly the pages somebody is on when they are already lost; - the Django **admin**, which #49 is about to make people use. All of them answer 200 when asked, so this is a coverage gap and not a list of broken pages. ## Shape **Enumerate rather than list.** Walk the URL resolver, keep the patterns that take no arguments or whose arguments the fixture can fill, and check every one. Then a page added without being checked is a failure, which is the property the current list cannot have. - Patterns needing an object get their argument from the furnished fixture, which already builds an application, a company, a contact, an interview and a reminder. - Anything genuinely not checkable — a file download, an `.ics`, a redirect — goes in a small named exclusion list **with its reason**, the way `IGNORED_RULES` already is. - The error pages are reached by asking for something that is not there and by a view that raises, with `DEBUG` off. - The admin is Django's, not Postulo's, so it is worth checking and worth its own exclusions. ## What this does not fix, and should be written into the module The suite passed, in both themes, on a sign-in page that turned out to be completely unstyled (see the companion issue). Everything axe measures was correct. A page can be machine-perfect and unusable, so the docstring should say what this suite is for — a regression net for the things a machine can check — and that it is not evidence that a page is good. ## Classification Enhancement, accessibility. Not breaking; it is test-only. ## Depends on Nothing. Better landed after the unstyled-pages fix, so the new coverage starts green.
tiagoagueda added this to the 0.2.0 milestone 2026-09-06 16:05:58 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#66
No description provided.