Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 9 additions & 32 deletions manage_breast_screening/core/utils/acessibility.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,20 @@
import json

from axe_playwright_python.base import AxeResults
from django.conf import settings
from playwright.sync_api import Page
from axe_playwright_python.sync_playwright import Axe

AXE_VIOLATIONS_EXCLUDE_LIST = [
"region", # 'Some page content is not contained by landmarks' https://github.com/alphagov/govuk-frontend/issues/1604
"aria-allowed-attr", # 'ARIA attribute is not allowed: aria-expanded="false"' https://github.com/alphagov/govuk-frontend/issues/979
]


class AxeAdapter:
def __init__(
self,
page: Page,
script_path=settings.BASE_DIR.parent
/ "node_modules"
/ "axe-core"
/ "axe.min.js",
options=None,
):
self.script_path = script_path
self.options = options or {
class AxeAdapter(Axe):
def __init__(self):
self.default_options = {
"rules": {id: {"enabled": False} for id in AXE_VIOLATIONS_EXCLUDE_LIST}
}
self.page = page
self._install(page)

def _install(self, page: Page):
"""
Add the axe script to a playwright Page.
The script will be re-executed any time the page or it's frames are navigated.
"""
page.add_init_script(path=self.script_path)
super().__init__()

def run(self) -> AxeResults:
"""
Run axe on the whole document
"""
options = json.dumps(self.options)
response = self.page.evaluate(rf"axe.run({options})")
return AxeResults(response)
def run(self, page, context=None, options=None) -> AxeResults:
return super().run(
page=page, context=context, options=options or self.default_options
)
4 changes: 2 additions & 2 deletions manage_breast_screening/tests/system/system_test_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def setUp(self):
self.context = self.browser.new_context()
self.page = self.context.new_page()
self.page.set_default_timeout(5000)
self.axe = AxeAdapter(self.page)
self.axe = AxeAdapter()
settings.BASE_URL = self.live_server_url

def tearDown(self):
Expand Down Expand Up @@ -138,7 +138,7 @@ def then_the_accessibility_baseline_is_met(self, require_unique_link_text=True):
any interactive elements that appear close together, and avoiding any non-specific
links like "click here".
"""
results = self.axe.run()
results = self.axe.run(page=self.page)
self.assertEqual(results.violations_count, 0, results.generate_report())

if require_unique_link_text:
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
"@types/eslint": "^9.6.1",
"@types/jest": "^30.0.0",
"@types/node": "^24.10.1",
"axe-core": "^4.11.0",
"babel-jest": "^30.2.0",
"concurrently": "^9.2.1",
"eslint": "^9.37.0",
Expand Down
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.