github / github/accessibility-scanner

Scanner does not wait for client-side rendering before running axe scan

Ouverte
#201 2 commentaires 2 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
TypeScript
Étoiles
369
Forks
40
Merge moyen
1 j 9 h
PR mergées (30 j)
10

Description

## Problem

When scanning single-page applications (React, Vue, Angular, etc.), the scanner runs the axe scan immediately after `page.goto()` resolves (which waits for the `load` event). At that point, the JavaScript bundles are loaded but the framework hasn't finished rendering the DOM yet. This means axe scans a nearly-empty `

` instead of the actual page content.

This leads to:
- **False positives**: Document-level violations like `landmark-one-main` and `page-has-heading-one` are reported because the landmarks and headings haven't been rendered yet.
- **False negatives**: Element-level violations like `button-name` are missed because the elements don't exist in the DOM yet.
- **Misleading screenshots**: Screenshots are taken *after* axe runs (inside `addFinding`), by which time React has finished rendering. So the screenshots show the correct, fully-rendered page — even though axe scanned a different DOM state.

## Steps to reproduce

1. Set up the scanner against any React/SPA application
2. Run a scan on a page that has proper `` landmarks and `

` headings rendered by the framework
3. Observe that `landmark-one-main` and `page-has-heading-one` violations are reported
4. Run axe dev tools manually in the browser on the same page — these violations are not found
5. Observe that element-level violations found by axe dev tools (e.g. `button-name`) are not reported by the scanner

## Root cause

In [`findForUrl.ts`](https://github.com/github/accessibility-scanner/blob/main/.github/actions/find/src/findForUrl.ts):

```ts
await page.goto(url)
// axe runs immediately — no wait for client-side rendering
const rawFindings = await new AxeBuilder({page}).analyze()
```

`page.goto()` resolves on the `load` event, which fires when HTML/CSS/JS resources are loaded — but before the JS framework has executed and rendered the DOM.

## Suggested fix

Add a wait for the page to be idle before running the axe scan. For example:

```ts
await page.goto(url)
await page.waitForLoadState('networkidle')
// or: await page.waitForTimeout(2000)
// or: await page.waitForFunction(() => document.querySelector('[data-testid]') !== null)
const rawFindings = await new AxeBuilder({page}).analyze()
```

`waitForLoadState('networkidle')` waits until there are no network connections for at least 500ms, which is a reasonable heuristic for "the SPA has finished its initial API calls and rendered."

## Environment

- `github/accessibility-scanner@v2` (SHA: `7866232dda98e447fed8ec0d7798b322d888fd27`)
- React 19 application with Mantine UI, served from Docker containers via Caddy
- Authenticated via `auth_context` input with session cookies

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Start in .github/actions/find/src/findForUrl.ts and inspect the sequence from page.goto(url) to AxeBuilder.analyze(). Reproduce the scan against a client-rendered React page and verify that axe observes the rendered DOM rather than the initial root element; done means the reported findings and scan timing match the fully rendered page.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
playwright, react, typescript
Domaine
accessibility, frontend, testing-qa
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
Calme
Clarté
Plutôt claire
Accessibilité débutants
58/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.