forked from Iota-School/notebooks-for-all
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add generate function for testing axe
- Loading branch information
Showing
7 changed files
with
245 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# testing axe in python | ||
|
||
the `test_axe` module provides utilities for running `axe-core` on html document in python. it is designed for asynchronous interactive use and synchronous testing with the `pytest_axe` extension. | ||
|
||
`axe-core` is a javascript module that must be run inside of a live browser. currently, `playwright` is the only browser automation supporter, but `selenium` could be added. | ||
|
||
<!-- can we add it to robots from jupyter after that? --> | ||
|
||
## axe exceptions in python | ||
|
||
each release contains a version of axe and a set of exceptions generated for that specific version. | ||
the types are useful in accounting for expected accessibility that can be fixed later. | ||
|
||
## playwright testing | ||
|
||
it turns out the best ergonomics with working with axe from playwright are to append methods to the `Page` class. it has the following methods when `test_axe` is active: | ||
|
||
`Page.axe` | ||
: run axe and return the test results as a python dictionary | ||
|
||
`Page.test_axe` | ||
: run axe and return the test results as a python exception group | ||
|
||
`Page.aom` | ||
: an alias to the soon to be deprecated `page.accessibility.snapshot()` | ||
|
||
we have to main synchronous and asynchronous methods for playwright |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from .async_axe import * | ||
from ..browsers import Browser | ||
from .axe_exceptions import * | ||
from .ipy import load_ipython_extension, unload_ipython_extension |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import atexit | ||
from dataclasses import dataclass, field | ||
from pathlib import Path | ||
from traceback import print_exception | ||
from playwright.async_api import Browser, Playwright, async_playwright | ||
from asyncio import gather, get_event_loop | ||
|
||
from nbconvert_a11y.axe.types import AxeConfigure, AxeOptions | ||
from nbconvert_a11y.pytest_w3c import ValidatorViolation | ||
from nbconvert_a11y.axe.async_axe import validate_html | ||
|
||
|
||
def run(*args, **kwargs): | ||
from asyncio import run | ||
|
||
return run(*args, **kwargs) | ||
|
||
|
||
@dataclass | ||
class Results: ... | ||
|
||
|
||
@dataclass | ||
class Playwright: | ||
axe_options: AxeOptions = field(default_factory=AxeOptions) | ||
axe_config: AxeConfigure = field(default_factory=AxeConfigure) | ||
pw: Playwright = None | ||
browser: Browser = None | ||
|
||
def enter(self): | ||
if self.pw is None: | ||
self.pw = async_playwright() | ||
|
||
self.ctx = run(self.pw.__aenter__()) | ||
atexit.register(self.exit) | ||
if self.browser is None: | ||
self.browser = run(self.ctx.chromium.launch()) | ||
return self | ||
|
||
def exit(self): | ||
run(self.ctx.__aexit__()) | ||
|
||
def new_page(self, content): | ||
page = run(self.browser.new_page()) | ||
if isinstance(content, Path): | ||
run(page.goto(content)) | ||
elif isinstance(content, str): | ||
if content.lstrip().startswith("<"): | ||
run(page.set_content(content)) | ||
elif "://" in content: | ||
run(page.goto(content)) | ||
return page | ||
|
||
async def test_axe_page(self, page): | ||
from . import pw_test_axe | ||
|
||
return await pw_test_axe(page, '"body"', **self.axe_options.dict()) | ||
|
||
async def test_vnu_page(self, page): | ||
from . import pw_validate_html | ||
|
||
return ValidatorViolation.from_violations(await pw_validate_html(page)) | ||
|
||
def test_axe_html(self, html): | ||
return run(self.test_axe_page(self.new_page(html))) | ||
|
||
def test_vnu_html(self, html): | ||
return ValidatorViolation.from_violations(run(validate_html(html))) | ||
|
||
def axe_magic_cell(self, line, cell): | ||
from IPython.display import HTML, display | ||
|
||
page = self.new_page(cell) | ||
display(HTML(cell)) | ||
axe = self.test_axe_page(page) | ||
if isinstance(axe, Exception): | ||
print_exception(axe) | ||
|
||
def html_magic_cell(self, line, cell): | ||
axe = vnu = True | ||
from IPython.display import HTML, display | ||
|
||
display(HTML(cell)) | ||
page = self.new_page(cell) | ||
for x in run(gather(self.test_axe_page(page), self.test_vnu_page(page))): | ||
print(x) | ||
|
||
if isinstance(x, (Exception, ExceptionGroup)): | ||
print_exception(x) | ||
|
||
def vnu_magic_cell(self, line, cell): | ||
vnu = self.test_vnu_html(cell) | ||
if isinstance(vnu, Exception): | ||
print_exception(vnu) | ||
|
||
def line_magic(self, line, cell=None): | ||
pass | ||
|
||
|
||
def load_ipython_extension(shell): | ||
from traitlets import Instance | ||
|
||
if not shell.has_trait("pw"): | ||
shell.add_traits(pw=Instance(Playwright, args=())) | ||
shell.register_magic_function(shell.pw.axe_magic_cell, "cell", "axe") | ||
shell.register_magic_function(shell.pw.vnu_magic_cell, "cell", "vnu") | ||
shell.register_magic_function(shell.pw.html_magic_cell, "cell", "html") | ||
from nest_asyncio import apply | ||
|
||
apply() | ||
shell.pw.enter() | ||
|
||
|
||
def unload_ipython_extension(shell): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{ | ||
"grid": { | ||
"table": "grid", | ||
"thead": "rowgroup", | ||
"tbody": "rowgroup", | ||
"tfoot": "rowgroup", | ||
"tr": "row", | ||
"th": { | ||
"row": "rowheader", | ||
"col": "colheader" | ||
}, | ||
"td": "gridcell" | ||
}, | ||
"treegrid": { | ||
"table": "grid", | ||
"thead": "rowgroup", | ||
"tbody": "rowgroup", | ||
"tfoot": "rowgroup", | ||
"tr": "row", | ||
"th": { | ||
"row": "rowheader", | ||
"col": "colheader" | ||
}, | ||
"td": "gridcell" | ||
}, | ||
"table": { | ||
"table": "table", | ||
"thead": "rowgroup", | ||
"tbody": "rowgroup", | ||
"tfoot": "rowgroup", | ||
"tr": "row", | ||
"th": { | ||
"row": "rowheader", | ||
"col": "colheader" | ||
}, | ||
"td": "cell" | ||
}, | ||
"list": { | ||
"table": "list", | ||
"thead": "group", | ||
"tbody": "group", | ||
"tfoot": "group", | ||
"tr": "listitem", | ||
"th": { | ||
"row": "none", | ||
"col": "none" | ||
}, | ||
"td": "none" | ||
}, | ||
"region": { | ||
"table": "none", | ||
"thead": "none", | ||
"tbody": "none", | ||
"tfoot": "none", | ||
"tr": "region", | ||
"th": { | ||
"row": "none", | ||
"col": "none" | ||
}, | ||
"td": "none" | ||
}, | ||
"none": { | ||
"table": "none", | ||
"thead": "none", | ||
"tbody": "none", | ||
"tfoot": "none", | ||
"tr": "none", | ||
"th": { | ||
"row": "none", | ||
"col": "none" | ||
}, | ||
"td": "none" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,8 @@ | ||
# This file is generated by running "yarn install" inside your project. | ||
# Manual changes might be lost - proceed with caution! | ||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
# yarn lockfile v1 | ||
|
||
__metadata: | ||
version: 6 | ||
cacheKey: 8 | ||
|
||
"@deathbeds/nbconvert-a11y@workspace:.": | ||
version: 0.0.0-use.local | ||
resolution: "@deathbeds/nbconvert-a11y@workspace:." | ||
dependencies: | ||
axe-core: ^4.8.2 | ||
languageName: unknown | ||
linkType: soft | ||
|
||
"axe-core@npm:^4.8.2": | ||
version: 4.8.2 | ||
resolution: "axe-core@npm:4.8.2" | ||
checksum: 8c19f507dabfcb8514e4280c7fc66e85143be303ddb57ec9f119338021228dc9b80560993938003837bda415fde7c07bba3a96560008ffa5f4145a248ed8f5fe | ||
languageName: node | ||
linkType: hard | ||
axe-core@^4.8.2: | ||
version "4.9.1" | ||
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz" | ||
integrity sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw== |