Accessibility-focused DOM testing library for tdom
Project description
aria-testing
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 caching and early-exit strategies
- 🔒 Type-safe - Full type annotations with strict type checking
- 🧪 Well-tested - 144 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
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 highly optimized for speed with multiple performance strategies:
Optimization Techniques
- Two-level caching - Element list and role computation caching
- 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) instead of O(n) for class queries
Benchmark Results
Measured on December 10, 2024 - Apple M-series CPU, Python 3.14
Test Suite Performance:
- 154 tests complete in 0.08 seconds ⚡
Query Performance (200-element DOM, 100 iterations per query):
| Query Type | Without Caching | With Caching | Speedup |
|---|---|---|---|
| Role queries | 4.3μs | 1.8μs | 2.4x faster |
| Text queries | 13.6μs | 11.2μs | 1.2x faster |
| Class queries | 3.2μs | 0.7μs | 4.3x faster |
| Tag queries | 3.5μs | 3.1μs | 1.1x faster |
| Average | 5.8μs | 3.7μs | 1.55x faster |
Cache Efficiency:
- Element list cache: 99.8% hit rate
- Role cache: 99.5% hit rate
Run benchmarks yourself:
just benchmark # General performance
just benchmark-cache # Caching comparison
Performance Tips
- Reuse containers - Query the same DOM multiple times to benefit from caching
- Use appropriate queries -
query_all_*gets full caching benefits - Let caching work - Caches auto-clear between pytest tests
See CACHING_IMPLEMENTATION.md for detailed performance analysis.
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aria_testing-0.1.2.tar.gz.
File metadata
- Download URL: aria_testing-0.1.2.tar.gz
- Upload date:
- Size: 22.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63714931ce5cb278b9808c7bb0a1d0a186ca96fa92d55a953655068e48910d2f
|
|
| MD5 |
82343fdc74de3d1a450c81f39f4a4f6e
|
|
| BLAKE2b-256 |
5d718f86fe4fbdabffb5d7858a72782e41b81d627ccba8ab6c5acdf70906bf88
|
File details
Details for the file aria_testing-0.1.2-py3-none-any.whl.
File metadata
- Download URL: aria_testing-0.1.2-py3-none-any.whl
- Upload date:
- Size: 28.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1745351eb0c87f8d1b3acdcfa0cabe7c7ceee11be05d71a784cfb41a1fe870bd
|
|
| MD5 |
1c68543f99bda4e8206bc6ba6bf264a0
|
|
| BLAKE2b-256 |
1f7a9957519dfff1e7d7d7a2b71ef1988984cb97f9ec02a66d5bed0772afdb15
|