forked from ChelseaKR/habitable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_site_axe.py
More file actions
87 lines (73 loc) · 3.26 KB
/
Copy pathtest_site_axe.py
File metadata and controls
87 lines (73 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright 2026 Chelsea Kelly-Reif
"""axe-core scan of the Pages-deployed static site (P1-6, A11Y-01/02).
Before this test existed, `site/index.html` (and the committed sample packet
under `site/sample-packet/`) were the one Pages-deployed, publicly reachable
surface scanned by nothing: `tests/test_htmlpacket.py` covers a *freshly
generated* packet.html, not this literal committed static copy, and nothing
covered the landing page at all. Same pattern as `test_htmlpacket.py`: real
Chromium + axe-core, skip cleanly if the browser isn't installed.
"""
from __future__ import annotations
from pathlib import Path
import pytest
_SITE_ROOT = Path(__file__).resolve().parent.parent / "site"
def _run_axe(html_path: Path) -> list[dict[str, object]]:
pytest.importorskip("playwright.sync_api")
pytest.importorskip("axe_playwright_python.sync_playwright")
from axe_playwright_python.sync_playwright import Axe
from playwright.sync_api import Error as PlaywrightError
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
try:
browser = p.chromium.launch()
except PlaywrightError as exc:
pytest.skip(f"Chromium not available: {exc}")
try:
page = browser.new_page()
page.goto(html_path.as_uri(), wait_until="load")
results = Axe().run(page)
finally:
browser.close()
return [
v
for v in results.response.get("violations", [])
if v.get("impact") in {"moderate", "serious", "critical"}
]
@pytest.mark.a11y
def test_landing_page_passes_axe() -> None:
html_path = _SITE_ROOT / "index.html"
assert html_path.is_file(), "site/index.html not found — has the landing page moved?"
blocking = _run_axe(html_path)
assert not blocking, [v["id"] for v in blocking]
@pytest.mark.a11y
@pytest.mark.parametrize(
"relative_path",
[
"how-it-works/index.html",
"documentation-checklist/index.html",
"guides/preserve-maintenance-request-records/index.html",
"guides/housing-inspection-records/index.html",
"tenant-unions/index.html",
"templates/tenant-union-building-condition-survey/index.html",
"legal-aid-reviewers/index.html",
"inspectors-code-enforcement/index.html",
"trust-limitations/index.html",
"review/index.html",
"review/changes/index.html",
],
)
def test_public_content_guides_pass_axe(relative_path: str) -> None:
html_path = _SITE_ROOT / relative_path
assert html_path.is_file(), f"public content guide not found: {relative_path}"
blocking = _run_axe(html_path)
assert not blocking, [v["id"] for v in blocking]
@pytest.mark.a11y
def test_committed_sample_packet_passes_axe() -> None:
"""The committed static sample under site/sample-packet/ is a separate artifact
from the freshly-generated packet tests/test_htmlpacket.py checks — it can drift
from the generator (e.g. after a template change) without that test catching it."""
html_path = _SITE_ROOT / "sample-packet" / "packet.html"
assert html_path.is_file(), "site/sample-packet/packet.html not found."
blocking = _run_axe(html_path)
assert not blocking, [v["id"] for v in blocking]