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 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:

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 exists

  • get_all_by_*: When multiple elements MUST exist

  • query_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 | Y unions, 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 MappingProxyTypeNo 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

Documentation Guide

This documentation is organized into focused sections for different needs:

Getting Started

Start here if you’re new to aria-testing:

  • README (above) - Quick start and overview

  • Query Reference - All query types and their usage

  • Assertion Helpers - Deferred execution for dynamic testing systems

Practical Guides

Learn by example:

  • Examples - Real-world testing patterns and use cases

  • Best Practices - Guidelines for writing effective, accessible tests

Reference

Complete API documentation:

  • API Reference - Full function signatures, parameters, and return types

Advanced Topics

Deep dives for advanced users and contributors:

  • Architecture - System design, query factory pattern, role mapping

  • Benchmarks - Performance measurements, optimization strategies

  • Contributing - Development setup, code standards, how to contribute

Philosophy

aria-testing follows the DOM Testing Library philosophy:

“The more your tests resemble the way your software is used, the more confidence they can give you.”

This means:

  • Query by role (how screen readers see your app)

  • Query by label text (how users identify form fields)

  • Query by text (what users see)

  • ❌ Avoid querying by test IDs, CSS classes, or implementation details

Project Info

  • License: MIT

  • Python: 3.14+

  • Dependencies: tdom