Docs/SDK/Expect API

Expect API

A fluent testing and assertion framework for verifying page state with semantic queries. Perfect for end-to-end tests, validation, and quality assurance.

Overview

The Expect API provides a clean, readable syntax for making assertions about page elements using semantic queries. It's designed for:

expect()

Creates an assertion builder for fluent testing with semantic queries.

Function Signature

from sentience import expect

expect(browser, selector)

Parameters

Assertion Methods

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 sentience import SentienceBrowser, expect

browser = SentienceBrowser()
browser.start()
browser.page.goto("https://example.com")

# Assert button exists (waits up to 5 seconds)
expect(browser, "role=button text='Submit'").to_exist()

# Custom timeout (wait up to 10 seconds)
expect(browser, "role=button text='Submit'").to_exist(timeout=10.0)

browser.close()

.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)

Basic Examples

Verifying Page Elements

from sentience import SentienceBrowser, expect

browser = SentienceBrowser()
browser.start()
browser.page.goto("https://example.com")

# Verify critical elements exist
expect(browser, "role=heading text='Welcome'").to_exist()
expect(browser, "role=button text='Get Started'").to_exist()
expect(browser, "role=link text='Learn More'").to_exist()

# Verify elements are visible
expect(browser, "role=heading").to_be_visible()
expect(browser, "role=button text='Sign Up'").to_be_visible()

browser.close()

Testing Dynamic Content

from sentience import SentienceBrowser, expect, click, find, snapshot

browser = SentienceBrowser()
browser.start()
browser.page.goto("https://example.com")

# Click a button
snap = snapshot(browser)
button = find(snap, "role=button text~'Load More'")
click(browser, button.id)

# Verify new content appears (wait up to 10 seconds)
expect(browser, "role=article").to_have_count(20, timeout=10.0)

# Verify success message
expect(browser, "role=alert text~'Success'").to_be_visible(timeout=5.0)

browser.close()

E2E Test Example

Complete end-to-end test for a login flow:

from sentience import SentienceBrowser, expect, snapshot, find, type_text, click, press

def test_login_flow():
    browser = SentienceBrowser()
    browser.start()

    # Navigate to login page
    browser.page.goto("https://example.com/login")

    # Verify login form elements exist
    expect(browser, "role=textbox text~'email'").to_exist()
    expect(browser, "role=textbox text~'password'").to_exist()
    expect(browser, "role=button text~'Sign In'").to_exist()

    # Fill in credentials
    snap = snapshot(browser)
    email_field = find(snap, "role=textbox text~'email'")
    password_field = find(snap, "role=textbox text~'password'")

    type_text(browser, email_field.id, "user@example.com")
    type_text(browser, password_field.id, "password123")

    # Submit form
    submit_btn = find(snap, "role=button text~'Sign In'")
    click(browser, submit_btn.id)

    # Verify successful login (dashboard appears)
    expect(browser, "role=heading text~'Dashboard'").to_exist(timeout=10.0)
    expect(browser, "role=button text~'Logout'").to_be_visible()

    # Verify user info is displayed
    expect(browser, "text~'user@example.com'").to_exist()

    browser.close()
    print("✅ Login flow test passed!")

# Run test
test_login_flow()

Error Handling

Assertions throw exceptions when they fail:

from sentience import SentienceBrowser, expect

browser = SentienceBrowser()
browser.start()
browser.page.goto("https://example.com")

try:
    # This will timeout if button doesn't exist
    expect(browser, "role=button text='NonExistent'").to_exist(timeout=3.0)
except AssertionError as e:
    print(f"❌ Test failed: {e}")
    # Continue with error handling or cleanup

browser.close()

Integration with Testing Frameworks

pytest (Python)

import pytest
from sentience import SentienceBrowser, expect

@pytest.fixture
def browser():
    browser = SentienceBrowser()
    browser.start()
    yield browser
    browser.close()

def test_homepage_elements(browser):
    browser.page.goto("https://example.com")

    # All assertions use pytest's assert mechanism
    expect(browser, "role=heading text='Welcome'").to_exist()
    expect(browser, "role=button text='Get Started'").to_be_visible()
    expect(browser, "role=link").to_have_count(5)

def test_search_functionality(browser):
    browser.page.goto("https://example.com")

    # Verify search box exists
    expect(browser, "role=textbox text~'search'").to_exist()

    # ... rest of test

Jest (TypeScript)

# Not applicable for Python example

Best Practices

1. Use Semantic Selectors

Prefer 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()

2. Set Appropriate Timeouts

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)

3. Combine with Other APIs

Use expect() alongside other Sentience 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()

4. Test Critical Paths

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()

Use Cases

1. Regression Testing

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()

2. Accessibility Testing

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()

3. Form Validation

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)

4. Dynamic Content Verification

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)

Next Steps