aria-testing
December 11, 2025 ยท View on GitHub
Accessibility-focused DOM testing library for tdom, built with modern Python 3.14+.
๐ Full Documentation | ๐ฆ * PyPI Package* | ๐ * GitHub Repository*
Overview
aria-testing is a Python DOM testing library that provides accessibility-focused query functions for tdom. It follows
the DOM Testing Library philosophy: "The more your tests resemble the way your software is used, the more confidence
they can give you."
Features
- โจ Modern Python 3.14+ - Uses structural pattern matching, PEP 695 generics, and modern type hints
- ๐ฏ Accessibility-first - Query by role, label text, and semantic attributes
- โก High performance - Optimized traversal with early-exit strategies
- ๐ Type-safe - Full type annotations with strict type checking
- ๐งช Well-tested - 179 tests, 100% passing, comprehensive coverage
Installation
uv add --dev aria-testing
Quick Start
from tdom.processor import html
from aria_testing import get_by_role, get_by_text, get_by_label_text
# Create a tdom structure
document = html(t"""<div>
<h1>Welcome</h1>
<nav>
<a href="/home">Home</a>
</nav>
<form>
<label>Email
<input type="email" />
</label>
<button>Submit</button>
</form>
</div>""")
# Find elements using accessibility patterns
heading = get_by_role(document, "heading", level=1)
nav = get_by_role(document, "navigation")
link = get_by_role(document, "link", name="Home")
email_input = get_by_label_text(document, "Email")
button = get_by_text(document, "Submit")
Query Types
Queries are prioritized by accessibility best practices:
1. By Role โญ (Most Recommended)
Find elements by their ARIA role - mirrors how screen readers interact with your app.
button = get_by_role(document, "button")
heading = get_by_role(document, "heading", level=1)
link = get_by_role(document, "link", name="Home")
2. By Label Text โญ
Find form elements by their associated label - how users identify form fields.
username = get_by_label_text(document, "Username")
email = get_by_label_text(document, "Email Address")
3. By Text
Find elements by their text content.
button = get_by_text(document, "Click me")
heading = get_by_text(document, "Welcome")
4. By Test ID
Find elements by data-testid attribute - useful when semantic queries aren't possible.
component = get_by_test_id(document, "user-menu")
5. By Tag Name
Find elements by HTML tag name - use sparingly, prefer semantic queries.
all_links = get_all_by_tag_name(document, "a")
6. By ID & By Class
Find elements by HTML attributes - available but less recommended.
element = get_by_id(document, "main-content")
buttons = get_all_by_class(document, "btn-primary")
Query Variants
Each query type comes in four variants for different use cases:
| Variant | Returns | Not Found | Multiple Found |
|---|---|---|---|
get_by_* | Single element | โ Raises error | โ Raises error |
query_by_* | Element or None | โ Returns None | โ Raises error |
get_all_by_* | List of elements | โ Raises error | โ Returns all |
query_all_by_* | List (possibly empty) | โ
Returns [] | โ Returns all |
When to Use Each
get_by_*: When element MUST exist and be unique (most common)query_by_*: When checking if element existsget_all_by_*: When multiple elements MUST existquery_all_by_*: When finding zero or more elements
Assertion Helpers
Frozen dataclass-based assertion helpers for deferred execution in dynamic systems. Create assertions up front, apply them later when the DOM is available.
from aria_testing import GetByRole, GetAllByRole
# Define assertion early (no DOM needed yet)
assert_button = GetByRole(role="button").text_content("Save")
# Apply later when container becomes available
def verify_component(container):
assert_button(container) # Raises AssertionError if fails
Use Cases:
- Component testing frameworks that render components dynamically
- Story-based testing where assertions are defined separately from execution
- Test fixtures that verify DOM structure after setup
- Reusable assertion sets applied across multiple test scenarios
Key Features:
- Immutable frozen dataclasses
- Fluent API:
.not_(),.text_content(),.with_attribute() - List operations:
.count(),.nth() - Type-safe with full IDE support
๐ See full documentation โ
Modern Python Features
Built with cutting-edge Python 3.14+ features:
- Structural pattern matching (
match/case) for clean conditionals - PEP 695 generic functions for type-safe query factories
- Modern type hints (
X | Yunions, built-in generics) - Keyword-only arguments for clear, readable APIs
- Walrus operator (
:=) for concise, performant code
Performance
aria-testing is optimized for speed with multiple performance strategies:
Query Performance (200-element DOM on Python 3.14t free-threaded):
- Average query time: 3.99ฮผs โก (21% faster than regular Python!)
- Role queries: 2.85ฮผs
- Text queries: 12.18ฮผs
- Class/tag queries: 2.34ฮผs
Test Suite:
- 179 tests complete in 0.78 seconds (parallel mode)
- Average: 4.4ms per test
Free-Threading Advantage: Python 3.14t (no-GIL) is 21% faster than regular Python 3.14, even in single-threaded code, due to reduced GIL overhead and optimized reference counting for interned strings.
Key Optimizations
- Early-exit strategies - Stops searching after finding matches
- Iterative traversal - Non-recursive DOM traversal for large trees
- String interning - Fast identity-based comparisons for common roles
- Set-based class matching - O(1) class lookups
- Free-threading compatible - Full Python 3.14+ free-threading support (PEP 703)
Thread Safety & Concurrency
aria-testing is fully thread-safe and designed for Python 3.14's free-threaded (no-GIL) interpreter:
โ
No shared mutable state - All operations use function-local variables
โ
Immutable data structures - Module constants use MappingProxyType
โ
No locking required - Lock-free design for maximum performance
โ
Parallel test execution - Works with pytest-xdist and concurrent.futures
The library was designed from the ground up for concurrent execution. Previous caching mechanisms were intentionally removed to ensure race-condition-free operation in multi-threaded environments.
๐ See detailed benchmarks โ
Run benchmarks yourself:
just benchmark # Performance benchmark
just profile-queries # Detailed profiling
Requirements
- Python 3.14+
- tdom
Documentation
๐ Read the full documentation on GitHub Pages โ
The documentation includes:
- Complete API reference for all query functions
- Detailed guides on accessibility testing patterns
- Performance optimization techniques
- Type safety and modern Python features
- Advanced usage examples and best practices
License
MIT