#!/usr/bin/env python3
"""
Comprehensive Demo of Playwright-style WebSocket Browser Control
Shows both backward-compatible and new Playwright-style APIs.
"""
import asyncio
import logging
import sys
import os
from datetime import datetime
from client import Browser, Playwright, browser
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
async def demo_basic_navigation():
"""Demo basic navigation features"""
print("\n=== Basic Navigation Demo ===")
# Create browser instance
browser_instance = Browser("ws://localhost:8765")
await browser_instance.connect()
try:
# Create a page
page = await browser_instance.new_page()
# Navigate to a website
print("Navigating to example.com...")
await page.goto("https://example.com")
await asyncio.sleep(2)
# Get page info
title = await page.title()
url = await page.url()
print(f"Title: {title}")
print(f"URL: {url}")
# Navigate to another page
print("\nNavigating to Python.org...")
await page.goto("https://www.python.org")
await asyncio.sleep(2)
# Go back
print("Going back...")
await page.go_back()
await asyncio.sleep(2)
# Go forward
print("Going forward...")
await page.go_forward()
await asyncio.sleep(2)
# Reload
print("Reloading page...")
await page.reload()
await asyncio.sleep(2)
finally:
await browser_instance.close()
async def demo_playwright_style():
"""Demo Playwright-style API usage"""
print("\n=== Playwright-Style API Demo ===")
# Using Playwright launcher
playwright = Playwright()
browser_instance = await playwright.chromium.launch(ws_endpoint="ws://localhost:8765")
try:
# Create context and page
context = await browser_instance.new_context()
page = await context.new_page()
# Navigate and wait for load
print("Navigating with Playwright-style API...")
await page.goto("https://www.wikipedia.org")
await page.wait_for_load_state("load")
# Use locators
print("Using locators to find elements...")
search_box = page.locator('input[name="search"]')
# Type into search box
print("Typing 'Python programming' into search...")
await search_box.type("Python programming", delay=50)
await asyncio.sleep(1)
# Press Enter
print("Pressing Enter...")
await search_box.press("Enter")
await page.wait_for_load_state("load")
await asyncio.sleep(2)
# Take screenshot
print("Taking screenshot...")
screenshot_data = await page.screenshot()
with open("wikipedia_search.png", "wb") as f:
f.write(screenshot_data)
print("Screenshot saved as wikipedia_search.png")
finally:
await browser_instance.close()
async def demo_form_interaction():
"""Demo form interaction capabilities"""
print("\n=== Form Interaction Demo ===")
async with browser(ws_endpoint="ws://localhost:8765") as browser_instance:
page = await browser_instance.new_page()
# Create a test form
html_content = """
Test Form
Test Form
Form Submitted!
"""
# Set the content
print("Loading test form...")
await page.set_content(html_content)
# Fill the form using different methods
print("\nFilling form fields...")
# Method 1: Using fill()
await page.fill("#name", "John Doe")
# Method 2: Using type() for more realistic typing
await page.type("#email", "john.doe@example.com", delay=50)
# Method 3: Using locator
country_select = page.locator("#country")
await country_select.select_option("us")
# Check checkbox
print("Checking newsletter checkbox...")
await page.check("#newsletter")
# Select radio button
print("Selecting gender radio button...")
await page.click('input[name="gender"][value="male"]')
# Fill textarea
print("Adding comments...")
comments_field = page.locator("#comments")
await comments_field.fill("This is a test comment\nWith multiple lines\nUsing Playwright-style API")
# Submit form
print("Submitting form...")
await page.click('button[type="submit"]')
await asyncio.sleep(1)
# Check if result is visible
result_div = page.locator("#result")
is_visible = await result_div.is_visible()
print(f"Result visible: {is_visible}")
# Get the result content
result_text = await page.inner_text("#resultContent")
print("Form submission result:")
print(result_text)
# Take a screenshot of the filled form
await page.screenshot()
print("Screenshot taken of submitted form")
async def demo_element_queries():
"""Demo element querying and manipulation"""
print("\n=== Element Query Demo ===")
browser_instance = Browser("ws://localhost:8765")
await browser_instance.connect()
try:
page = await browser_instance.new_page()
# Create a test page with multiple elements
html_content = """
Element Query Test
Element Query Test
Item 1
Item 2
Item 3 (Hidden)
Item 4
"""
await page.set_content(html_content)
print("Test page loaded")
# Query single element
print("\nQuerying single element...")
first_item = await page.query_selector(".item")
if first_item:
text = await first_item.inner_text()
print(f"First item text: {text}")
# Query all elements
print("\nQuerying all items...")
all_items = await page.query_selector_all(".item")
print(f"Found {len(all_items)} items")
# Check visibility
print("\nChecking visibility of items...")
for i, item in enumerate(all_items):
is_visible = await item.is_visible()
print(f"Item {i+1} visible: {is_visible}")
# Get attributes
print("\nGetting data attributes...")
for item in all_items:
data_id = await item.get_attribute("data-id")
print(f"Item has data-id: {data_id}")
# Click toggle button to show hidden item
print("\nClicking toggle button...")
await page.click("#toggleBtn")
await asyncio.sleep(0.5)
# Check visibility again
hidden_item = page.locator('[data-id="3"]')
is_visible_after = await hidden_item.is_visible()
print(f"Hidden item visible after toggle: {is_visible_after}")
# Click highlight button
print("\nClicking highlight button...")
await page.click("#highlightBtn")
await asyncio.sleep(0.5)
# Use evaluate to check if highlighting worked
has_highlight = await page.evaluate("""
() => {
const items = document.querySelectorAll('.item.highlight');
return items.length;
}
""")
print(f"Number of highlighted items: {has_highlight}")
finally:
await browser_instance.close()
async def demo_wait_conditions():
"""Demo various wait conditions"""
print("\n=== Wait Conditions Demo ===")
async with browser(ws_endpoint="ws://localhost:8765") as browser_instance:
page = await browser_instance.new_page()
# Create a dynamic page
html_content = """
Dynamic Content Test
Dynamic Content Test
Content will appear here...
"""
await page.set_content(html_content)
print("Dynamic page loaded")
# Click load button
print("\nClicking load button...")
await page.click("#loadBtn")
# Wait for content to change
print("Waiting for content to load...")
await page.wait_for_function("""
() => {
const content = document.getElementById('content');
return content && content.classList.contains('loaded');
}
""", timeout=5000)
print("Content loaded!")
# Wait for extra content
print("Waiting for extra content...")
extra_content = await page.wait_for_selector("#extraContent", timeout=5000)
if extra_content:
extra_text = await extra_content.inner_text()
print(f"Extra content appeared: {extra_text}")
# Wait with timeout
print("\nWaiting for 2 seconds...")
await page.wait_for_timeout(2000)
print("Wait completed")
async def demo_javascript_execution():
"""Demo JavaScript execution capabilities"""
print("\n=== JavaScript Execution Demo ===")
browser_instance = Browser("ws://localhost:8765")
await browser_instance.connect()
try:
page = await browser_instance.new_page()
# Navigate to a simple page
await page.goto("https://example.com")
await asyncio.sleep(2) # Wait for page to load
# Execute simple JavaScript
print("\nExecuting simple JavaScript...")
try:
result = await page.evaluate("1 + 2")
print(f"1 + 2 = {result}")
except Exception as e:
print(f"Error executing simple math: {e}")
# Get page dimensions
try:
dimensions = await page.evaluate("""
() => {
return {
width: window.innerWidth,
height: window.innerHeight,
devicePixelRatio: window.devicePixelRatio || 1
}
}
""")
print(f"Page dimensions: {dimensions}")
except Exception as e:
print(f"Error getting dimensions: {e}")
# Modify page content
print("\nModifying page content...")
try:
await page.evaluate("""
() => {
const h1 = document.querySelector('h1');
if (h1) {
h1.style.color = 'red';
h1.textContent = 'Modified by Playwright-style API!';
}
}
""")
print("Page modified successfully")
except Exception as e:
print(f"Error modifying page: {e}")
# Create new elements
try:
await page.evaluate("""
() => {
const div = document.createElement('div');
div.id = 'custom-div';
div.style.cssText = 'position: fixed; top: 10px; right: 10px; ' +
'background: yellow; padding: 20px; ' +
'border: 2px solid black; z-index: 9999;';
div.textContent = 'Created via JavaScript!';
document.body.appendChild(div);
}
""")
print("New element created")
except Exception as e:
print(f"Error creating element: {e}")
await asyncio.sleep(2)
# Pass arguments to JavaScript
print("\nPassing arguments to JavaScript...")
try:
greeting = await page.evaluate(
"(name) => `Hello, ${name}!`",
"Playwright User"
)
print(f"Greeting: {greeting}")
except Exception as e:
print(f"Error with argument passing: {e}")
except Exception as e:
print(f"Error in demo: {e}")
finally:
await browser_instance.close()
async def demo_event_handling():
"""Demo event handling capabilities"""
print("\n=== Event Handling Demo ===")
browser_instance = Browser("ws://localhost:8765")
await browser_instance.connect()
# Set up event listeners
events_received = []
def on_browser_ready(data):
events_received.append(("browser_ready", data))
print(f"Event: Browser ready - {data}")
def on_load_started(data):
events_received.append(("load_started", data))
print(f"Event: Load started - {data.get('url', 'unknown')}")
def on_load_finished(data):
events_received.append(("load_finished", data))
print(f"Event: Load finished - {data.get('url', 'unknown')}")
def on_title_changed(data):
events_received.append(("title_changed", data))
print(f"Event: Title changed - {data.get('title', 'unknown')}")
# Register event listeners
browser_instance.on("browser_ready", on_browser_ready)
browser_instance.on("load_started", on_load_started)
browser_instance.on("load_finished", on_load_finished)
browser_instance.on("title_changed", on_title_changed)
try:
page = await browser_instance.new_page()
print("\nNavigating to trigger events...")
await page.goto("https://www.python.org")
await asyncio.sleep(2)
print(f"\nTotal events received: {len(events_received)}")
# Navigate to another page
print("\nNavigating to another page...")
await page.goto("https://example.com")
await asyncio.sleep(2)
print(f"Total events received: {len(events_received)}")
finally:
await browser_instance.close()
async def demo_backward_compatibility():
"""Demo backward compatible API usage"""
print("\n=== Backward Compatibility Demo ===")
browser_instance = Browser("ws://localhost:8765")
await browser_instance.connect()
try:
page = await browser_instance.new_page()
# Old-style commands still work
print("Using backward-compatible commands...")
# navigate command
result = await browser_instance._send_command({
"command": "navigate",
"url": "https://example.com"
})
print(f"Navigate result: {result}")
await asyncio.sleep(2)
# execute_js command
result = await browser_instance._send_command({
"command": "execute_js",
"script": "document.title"
})
print(f"Page title via execute_js: {result}")
# simulate_typing command
result = await browser_instance._send_command({
"command": "simulate_typing",
"selector": "h1",
"text": "Hello",
"delay": 0.1
})
print(f"Simulate typing result: {result}")
# get_info command
info = await browser_instance._send_command({
"command": "get_info"
})
print(f"Browser info: {info}")
finally:
await browser_instance.close()
async def run_all_demos():
"""Run all demo functions"""
demos = [
demo_basic_navigation,
demo_playwright_style,
demo_form_interaction,
demo_element_queries,
demo_wait_conditions,
demo_javascript_execution,
demo_event_handling,
demo_backward_compatibility
]
print("=" * 60)
print("Playwright-style WebSocket Browser Control Demo")
print("=" * 60)
print("\nMake sure the browser server is running on ws://localhost:8765")
print("Start it with: python browser_server_playwright.py")
input("\nPress Enter to start demos...")
for demo in demos:
try:
await demo()
await asyncio.sleep(2) # Pause between demos
except Exception as e:
logger.error(f"Error in {demo.__name__}: {e}")
import traceback
traceback.print_exc()
print("\n" + "=" * 60)
print("All demos completed!")
print("=" * 60)
# Individual demo runners for testing
async def main():
"""Main entry point"""
if len(sys.argv) > 1:
demo_name = sys.argv[1]
demos = {
"navigation": demo_basic_navigation,
"playwright": demo_playwright_style,
"form": demo_form_interaction,
"elements": demo_element_queries,
"wait": demo_wait_conditions,
"javascript": demo_javascript_execution,
"events": demo_event_handling,
"compatibility": demo_backward_compatibility,
"all": run_all_demos
}
if demo_name in demos:
await demos[demo_name]()
else:
print(f"Unknown demo: {demo_name}")
print(f"Available demos: {', '.join(demos.keys())}")
else:
await run_all_demos()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nDemo interrupted by user")
except Exception as e:
logger.error(f"Fatal error: {e}")
import traceback
traceback.print_exc()