A fluent testing and assertion framework for verifying page state with semantic queries. Perfect for end-to-end tests, validation, and quality assurance.
The Expect API provides a clean, readable syntax for making assertions about page elements using semantic queries. It's designed for:
Creates an assertion builder for fluent testing with semantic queries.
from predicate import expect
expect(browser"role=button text='Submit'")All assertion methods support an optional timeout parameter (default: 5.0 seconds).
.to_exist(timeout=5.0)Assert that an element matching the selector exists.
from predicate import PredicateBrowser, expect
browser = PredicateBrowser()
browser.start()
browser.page.goto("https://example.com")
# Assert button exists (waits up to 5 seconds)
expect(browser, "role=button text='Submit'").to_be_visible(timeout=5.0)Assert that an element is visible in the viewport.
# Assert element is visible
expect(browser, "role=heading").to_be_visible()
# Assert with custom timeout
expect(browser, "role=heading").to_be_visible(timeout=3.0).to_have_text(text, timeout=5.0)Assert that an element contains specific text.
# Assert button has exact text
expect(browser, "role=button").to_have_text("Submit")
# Assert with custom timeout
expect(browser, "role=button").to_have_text("Submit", timeout=10.0).to_have_count(n, timeout=5.0)Assert that a query returns exactly N elements.
# Assert exactly 10 links exist
expect(browser, "role=link").to_have_count(10)
# Assert with custom timeout
expect(browser, "role=link").to_have_count(10, timeout=8.0)from predicate import PredicateBrowser, expect
browser = PredicateBrowser()
browser.start()
browser.page.goto("https://example.com")
# Verify critical elements exist
expect(browser, "role=heading text='Welcome'")from predicate import PredicateBrowser, expect, click, find, snapshot
browser = PredicateBrowser()
browser.start()
browser.page.goto("https://example.com")
# Click a button
snap =Complete end-to-end test for a login flow:
from predicate import PredicateBrowser, expect, snapshot, find, type_text, click, press
def test_login_flow():
browser = PredicateBrowser()
browser.start()
# Navigate to login pageAssertions throw exceptions when they fail:
from predicate import PredicateBrowser, expect
browser = PredicateBrowser()
browser.start()
browser.page.goto("https://example.com")
try:
# This will timeout if button doesn't exist
expect(browser,import pytest
from predicate import PredicateBrowser, expect
@pytest.fixture
def browser():
browser = PredicateBrowser()
browser.start()
yield browser# Not applicable for Python examplePrefer semantic queries over brittle CSS selectors:
# ✅ Good - semantic, resilient to HTML changes
expect(browser, "role=button text~'Submit'").to_exist()
# ❌ Bad - brittle CSS selector
# page.locator('#submit-btn-123').is_visible()Adjust timeouts based on expected page behavior:
# Fast assertion for static content
expect(browser, "role=heading").to_exist(timeout=2.0)
# Longer timeout for dynamic content (AJAX, loading)
expect(browser, "role=article").to_have_count(10, timeout=15.0)Use expect() alongside other Predicate APIs:
# Take snapshot first for complex queries
snap = snapshot(browser)
button = find(snap, "role=button importance>800")
# Then assert element is still visible
expect(browser, f"role=button id={button.id}").to_be_visible()Focus on user-critical flows:
def test_checkout_flow():
# 1. Product page
expect(browser, "role=button text~'Add to Cart'").to_exist()
# 2. Cart page
expect(browser, "role=button text~'Checkout'").to_be_visible()
# 3. Payment page
expect(browser, "role=button text~'Place Order'").to_exist()Verify UI elements don't disappear after code changes:
def test_navigation_menu():
browser.page.goto("https://example.com")
# Verify all navigation links exist
expect(browser, "role=link text='Home'").to_exist()
expect(browser, "role=link text='Products'").to_exist()
expect(browser, "role=link text='About'").to_exist()
expect(browser, "role=link text='Contact'").to_exist()Check that ARIA roles are properly assigned:
# Verify button roles
expect(browser, "role=button").to_have_count(5)
# Verify heading hierarchy
expect(browser, "role=heading").to_be_visible()Test form validation messages:
# Submit empty form
click(browser, submit_button.id)
# Verify error messages appear
expect(browser, "role=alert text~'required'").to_be_visible(timeout=3.0)Test AJAX-loaded content:
# Click "Load More" button
click(browser, load_more_btn.id)
# Wait for new items to appear
expect(browser, "role=article").to_have_count(20, timeout=10.0)wait_for()