Enterprise-grade test automation framework featuring native W3C WebDriver BiDi accessibility locators with intelligent fallback strategies
This framework revolutionizes Selenium automation by providing native accessibility-based element location that mirrors how users actually interact with web applications. It seamlessly integrates W3C WebDriver BiDi protocol with intelligent fallback mechanisms for maximum compatibility and future-proofing.
- π― W3C BiDi Native Support: First-class implementation of
browsingContext.locateNodes - π Natural ARIA Locators: Find elements by roles and accessible names
- π§ Zero-Setup Installation: Auto-extends WebDriver with new methods
- π Intelligent Fallback: BiDi β CDP β DOM cascade for 100% compatibility
- ποΈ Enterprise Architecture: Production-ready with comprehensive error handling
- π Performance Optimized: Caching and strategy pattern implementation
- π Quick Start
- ποΈ Architecture Overview
- π BiDi Accessibility Locators
- βοΈ Implementation Details
- π§ͺ Testing & Debugging
- π Command Reference
- π Browser Support
- π Project Structure
- π§ Advanced Usage
# Clone repository
git clone <repository-url>
cd python-se
# Create virtual environment (recommended)
python -m venv se-python-env
source se-python-env/bin/activate # Windows: se-python-env\Scripts\activate
# Install dependencies
pip install -r requirements.txtimport utils # π Auto-enables ARIA methods on WebDriver!
# Natural element location (just like native Selenium)
username = driver.find_element_by_role("textbox", name="Username")
submit_btn = driver.find_element_by_role("button", name="Submit")
all_links = driver.find_elements_by_role("link")from utils import ARIARole, LocatorConfig
# Use enums for IDE support and safety
email_field = driver.find_element_by_role(ARIARole.TEXTBOX, name="Email")
login_button = driver.find_element_by_role(ARIARole.BUTTON, name="Login")
# Configure advanced options
config = LocatorConfig(
bidi_priority=True, # Prefer BiDi when available
cdp_fallback=True, # Enable CDP fallback
debug_mode=True # Detailed logging
)Our framework implements a sophisticated cascading fallback system:
graph TD
A[ARIA Locator Request] --> B{BiDi Available?}
B -->|Yes| C[W3C BiDi browsingContext.locateNodes]
B -->|No| D{CDP Available?}
D -->|Yes| E[Chrome DevTools Protocol]
D -->|No| F[DOM CSS Selectors + Accessibility Tree]
C --> G{Elements Found?}
E --> G
F --> G
G -->|Yes| H[Return WebElements]
G -->|No| I[Graceful Fallback/Exception]
| Component | Purpose | Technology |
|---|---|---|
| BiDiAccessibilityLocator | W3C BiDi native implementation | browsingContext.locateNodes |
| CDPAccessibilityBridge | Chrome DevTools fallback | Accessibility.getFullAXTree |
| DOMAccessibilityParser | Universal DOM fallback | CSS selectors + ARIA parsing |
| WebDriverExtensions | Seamless API integration | Dynamic method injection |
- Intelligent Caching: Context IDs and availability checks
- Strategy Pattern: Modular execution methods
- Lazy Loading: Components initialized on-demand
- Error Chaining: Comprehensive debugging information
WebDriver BiDi (Bidirectional Protocol) is the next-generation W3C standard that enables two-way communication between test scripts and browsers. Our framework leverages BiDi's browsingContext.locateNodes command for native accessibility-based element location.
- π― Native Performance: Direct browser communication
- π‘οΈ Future-Proof: W3C standard implementation
- π True Accessibility: Authentic accessibility tree traversal
- π Cross-Browser: Consistent behavior across all browsers
from utils.bidi_locators import BiDiAccessibilityLocator
# Direct BiDi usage
locator = BiDiAccessibilityLocator(driver)
# Check BiDi availability
if locator.is_available():
elements = locator.find_elements(
role="button",
name="Submit",
max_count=10
)# Enable BiDi in your WebDriver
chrome_options.set_capability("webSocketUrl", True) # Essential!
firefox_options.set_capability("webSocketUrl", True)
edge_options.set_capability("webSocketUrl", True)| Role | Description | Additional Attributes |
|---|---|---|
textbox |
Input fields, textareas | placeholder, required |
button |
Buttons, submit elements | pressed, disabled |
checkbox |
Checkbox inputs | checked, disabled |
radio |
Radio button inputs | checked, disabled |
link |
Anchor elements | href |
heading |
Headers (h1-h6) | level |
listitem |
List items | setsize, posinset |
tab |
Tab elements | selected |
dialog |
Modal dialogs | modal |
class BiDiAccessibilityLocator:
def _execute_bidi_command(self, method: str, params: Dict[str, Any]) -> Dict[str, Any]:
execution_strategies = [
self._try_native_browsing_context, # Selenium 4.15+
self._try_direct_bidi_command, # Future versions
self._try_legacy_bidi_connection, # Legacy support
self._try_cdp_bridge # CDP fallback
]
for strategy in execution_strategies:
try:
result = strategy(method, params)
if result is not None:
return result
except Exception as e:
logger.debug(f"Strategy failed: {strategy.__name__}: {e}")
continueclass BiDiAccessibilityLocator:
def __init__(self, driver: WebDriver) -> None:
self.driver = driver
self._context_id: Optional[str] = None # Cache context ID
self._bidi_available: Optional[bool] = None # Cache availability# Exception chaining for better debugging
except WebDriverException as e:
raise BiDiNotAvailableError(f"Context error: {e}") from e-
BiDi Native (
_try_native_browsing_context):driver.browsing_context.locate_nodes( context=context_id, locator={"type": "accessibility", "value": {"role": "button"}}, max_node_count=1000 )
-
CDP Bridge (
_try_cdp_bridge):driver.execute_cdp_cmd("Accessibility.enable", {}) tree_result = driver.execute_cdp_cmd("Accessibility.getFullAXTree", {})
-
DOM Fallback:
driver.find_elements(By.CSS_SELECTOR, 'button, [role="button"]')
Our comprehensive test suite validates all implementation layers:
class TestBiDiIntegration:
def test_bidi_availability_check(self, driver):
"""Verify BiDi detection works correctly"""
def test_bidi_direct_usage_when_available(self, driver):
"""Test direct BiDi implementation"""
def test_priority_order_works(self, driver):
"""Verify BiDi β CDP β DOM cascade"""
def test_error_handling(self, driver):
"""Test robust error scenarios"""Enable detailed logging to understand execution flow:
from utils import LocatorConfig
config = LocatorConfig(debug_mode=True)Debug Output Example:
DEBUG Using native BiDi accessibility locators
DEBUG -> {"method": "browsingContext.locateNodes", "params": {...}}
DEBUG <- {'id': 1, 'result': {'nodes': []}, 'type': 'success'}
DEBUG BiDi accessibility found 0 elements
DEBUG CDP accessibility tree found 2 elements
DEBUG DOM search found 2 elements
def test_performance_comparison(self, driver):
"""Compare BiDi vs CDP vs DOM performance"""
# Measure execution times
bidi_time = measure_execution_time(bidi_locator.find_elements)
cdp_time = measure_execution_time(cdp_locator.find_elements)
dom_time = measure_execution_time(dom_locator.find_elements)# Run all tests (default: Chrome)
pytest tests/ -v
# Test specific browser
pytest tests/ --browser chrome -v
pytest tests/ --browser firefox -v
pytest tests/ --browser edge -v
# Run specific test file
pytest tests/test_bidi_integration.py -v
pytest tests/test_get_by_role.py -v# Test BiDi functionality across all browsers
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_bidi_direct_usage_when_available --browser=chrome -v
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_bidi_direct_usage_when_available --browser=firefox -v
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_bidi_direct_usage_when_available --browser=edge -v
# Test priority system (BiDi β CDP β DOM)
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_priority_order_works -v
# Test with debug logging
pytest tests/test_bidi_integration.py -v -s --log-cli-level=DEBUG# Enable verbose debug output
pytest tests/ -v -s --log-cli-level=DEBUG
# Run single test with maximum verbosity
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_locator_config_debug_mode -v -s --log-cli-level=DEBUG
# Generate HTML test report
pytest tests/ --html=report.html --self-contained-html
# Run tests and show performance metrics
pytest tests/test_bidi_integration.py::TestBiDiIntegration::test_performance_comparison -v -s# Install in development mode
pip install -e .
# Run linting (if configured)
flake8 utils/ tests/
# Type checking (if configured)
mypy utils/
# Run tests with coverage
pytest tests/ --cov=utils --cov-report=html# Test BiDi availability detection
python -c "
from selenium import webdriver
from utils.bidi_locators import is_bidi_accessibility_available
from selenium.webdriver.chrome.options import Options
options = Options()
options.set_capability('webSocketUrl', True)
driver = webdriver.Chrome(options=options)
print(f'BiDi Available: {is_bidi_accessibility_available(driver)}')
driver.quit()
"
# Test error handling scenarios
python -c "
from selenium import webdriver
from utils.bidi_locators import BiDiAccessibilityLocator, BiDiNotAvailableError
driver = webdriver.Chrome() # No webSocketUrl
locator = BiDiAccessibilityLocator(driver)
try:
locator.find_element('button')
except BiDiNotAvailableError as e:
print(f'Expected error: {e}')
driver.quit()
"
# Manual BiDi testing
python -c "
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from utils.bidi_locators import BiDiAccessibilityLocator
options = Options()
options.set_capability('webSocketUrl', True)
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
locator = BiDiAccessibilityLocator(driver)
print(f'BiDi Available: {locator.is_available()}')
# Try direct BiDi usage
try:
elements = locator.find_elements('button')
print(f'Found {len(elements)} buttons via BiDi')
except Exception as e:
print(f'BiDi error: {e}')
driver.quit()
"| Browser | BiDi Native | CDP Fallback | DOM Fallback | Status |
|---|---|---|---|---|
| Chrome 118+ | β | β | β | Fully Supported |
| Firefox 119+ | β | β | β | Fully Supported |
| Edge 118+ | β | β | β | Fully Supported |
| Safari | β³ | β | β | DOM Only |
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.set_capability("webSocketUrl", True) # Enable BiDi
chrome_options.add_argument("--headless") # Optional
chrome_options.add_argument("--no-sandbox") # CI/CD
chrome_options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=chrome_options)from selenium.webdriver.firefox.options import Options
firefox_options = Options()
firefox_options.set_capability("webSocketUrl", True) # Enable BiDi
firefox_options.add_argument("--headless") # Optional
driver = webdriver.Firefox(options=firefox_options)from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.set_capability("webSocketUrl", True) # Enable BiDi
edge_options.add_argument("--headless") # Optional
driver = webdriver.Edge(options=edge_options)python-se/
βββ π tests/ # Test suite
β βββ conftest.py # pytest configuration & fixtures
β βββ test_bidi_integration.py # π― BiDi integration tests
β βββ test_get_by_role.py # ARIA locator tests
β βββ test_login_page.py # Example test scenarios
βββ π utils/ # Core framework
β βββ __init__.py # Package initialization
β βββ aria_locators.py # π Main ARIA implementation
β βββ bidi_locators.py # π W3C BiDi implementation
β βββ webdriver_extensions.py # WebDriver method injection
βββ π requirements.txt # Python dependencies
βββ π readme.md # This documentation
βββ π BLOG_POST.md # Technical blog post
βββ π SELENIUM_ISSUE_UPDATE.md # BiDi implementation notes
BiDiAccessibilityLocator: Main BiDi locator class- Strategy pattern for execution methods
- Intelligent caching and error handling
- Full W3C
browsingContext.locateNodessupport
- Multi-tier locator strategy (BiDi β CDP β DOM)
- ARIARole enum definitions
- LocatorConfig for advanced options
- Performance optimization
- Dynamic method injection into WebDriver
find_element_by_role()/find_elements_by_role()- Zero-setup auto-installation
- BiDi availability testing
- Cross-browser compatibility validation
- Priority system verification
- Performance benchmarking
from utils import LocatorConfig
# Advanced configuration
config = LocatorConfig(
bidi_priority=True, # Prefer BiDi when available
cdp_fallback=True, # Enable CDP fallback
dom_fallback=True, # Enable DOM fallback
debug_mode=True, # Detailed logging
timeout=10, # Element timeout (seconds)
retry_count=3, # Retry attempts
cache_results=True # Cache element lookups
)
# Apply configuration globally
driver.aria_config = configfrom utils.bidi_locators import BiDiAccessibilityLocator
# Direct BiDi usage (advanced)
bidi_locator = BiDiAccessibilityLocator(driver)
if bidi_locator.is_available():
# Find with custom parameters
elements = bidi_locator.find_elements(
role="button",
name="Submit",
max_count=5, # Limit results
pressed=False, # Button state
disabled=False # Accessibility state
)
# Single element with validation
try:
submit_btn = bidi_locator.find_element("button", name="Submit")
except NoSuchElementException:
print("Submit button not found")import time
from utils import LocatorConfig
# Performance testing
config = LocatorConfig(debug_mode=True)
start_time = time.time()
elements = driver.find_elements_by_role("button")
execution_time = time.time() - start_time
print(f"Found {len(elements)} elements in {execution_time:.3f}s")from utils.bidi_locators import BiDiNotAvailableError
from selenium.common.exceptions import NoSuchElementException
try:
# Attempt element location
element = driver.find_element_by_role("button", name="Submit")
element.click()
except BiDiNotAvailableError:
# BiDi not available, but fallback should work
print("BiDi unavailable, using fallback methods")
except NoSuchElementException:
# Element genuinely not found
print("Submit button not found on page")
except Exception as e:
# Unexpected error
print(f"Unexpected error: {e}")We welcome contributions! This framework represents cutting-edge Selenium automation with W3C BiDi integration.
git clone <repository-url>
cd python-se
python -m venv dev-env
source dev-env/bin/activate
pip install -r requirements.txt
pip install -e .# Full test suite
pytest tests/ -v
# BiDi-specific tests
pytest tests/test_bidi_integration.py -v
# With coverage
pytest tests/ --cov=utils --cov-report=htmlMIT License - Feel free to use in your projects!
- W3C BiDi Native: First framework with production-ready BiDi accessibility locators
- Future-Proof: Built on emerging W3C standards
- Enterprise-Ready: Production-tested architecture patterns
- Zero Setup: Import and use immediately
- Natural API: Familiar Selenium-style methods
- Type Safety: Full IDE support with enums
- Comprehensive Docs: Extensive documentation and examples
- Intelligent Fallbacks: Never fails due to technology limitations
- Cross-Browser: Consistent behavior across all major browsers
- Performance Optimized: Caching and strategy patterns
- Error Resilient: Comprehensive error handling and debugging
| Aspect | Traditional Selenium | This Framework |
|---|---|---|
| Locator Strategy | CSS/XPath selectors | Accessibility-based |
| Brittleness | High (layout changes break) | Low (semantic stability) |
| Readability | Poor (By.XPATH, "//div[@class='btn']") |
Excellent (role="button") |
| Future-Proof | No (legacy selectors) | Yes (W3C standards) |
| Performance | Variable | Optimized with caching |
| Browser Support | Manual configuration | Auto-detection + fallbacks |
π― Ready to revolutionize your Selenium automation? Get started with W3C BiDi accessibility locators today!