Setup Playwright Automation
When to Use
- Modern web application testing
- Mobile web testing (iOS, Android)
- Fast, reliable test execution
- Parallel/async testing requirements
- Advanced browser automation features
- Automatic wait strategies
Procedure
1. Install Playwright
pip install playwright==1.36.0 pytest-playwright==0.3.0
# Download browsers
playwright install
2. Create Playwright Browser Factory
factories/browser_factory.py
from playwright.sync_api import sync_playwright, expect
from config.settings import config
from utils.logger import get_logger
logger = get_logger(__name__)
class PlaywrightBrowserFactory:
"""Factory for Playwright browser instances."""
BROWSERS = ["chromium", "firefox", "webkit"]
@staticmethod
def create_browser_context(browser_name="chromium", headless=True, **kwargs):
playwright = sync_playwright().start()
if browser_name == "chromium":
browser = playwright.chromium.launch(headless=headless, **kwargs)
elif browser_name == "firefox":
browser = playwright.firefox.launch(headless=headless, **kwargs)
elif browser_name == "webkit":
browser = playwright.webkit.launch(headless=headless, **kwargs)
else:
raise ValueError(f"Unsupported browser: {browser_name}")
context = browser.new_context(
viewport={"width": 1280, "height": 720},
ignore_https_errors=True
)
logger.info(f"Playwright {browser_name} context created (headless={headless})")
return playwright, browser, context
@staticmethod
def create_mobile_browser(device_name="iPhone 12"):
from playwright.sync_api import devices
playwright = sync_playwright().start()
browser = playwright.chromium.launch(headless=config.headless)
context = browser.new_context(**devices[device_name])
logger.info(f"Mobile browser created: {device_name}")
return playwright, browser, context
class PlaywrightPage:
"""Wrapper for Playwright Page with common methods."""
def __init__(self, page):
self.page = page
def goto(self, url):
self.page.goto(url)
def click(self, selector):
self.page.click(selector)
def fill(self, selector, text):
self.page.fill(selector, text)
def get_text(self, selector):
return self.page.text_content(selector)
def is_visible(self, selector):
return self.page.is_visible(selector)
def wait_for_load_state(self, state="networkidle"):
self.page.wait_for_load_state(state)
def screenshot(self, path):
self.page.screenshot(path=path)
def close(self):
self.page.close()
3. Create Pytest Fixtures
fixtures/playwright_fixtures.py
import pytest
from playwright.sync_api import sync_playwright
from factories.browser_factory import PlaywrightBrowserFactory, PlaywrightPage
from config.settings import config
@pytest.fixture(scope="session")
def playwright_instance():
return sync_playwright().start()
@pytest.fixture(scope="function")
def browser_context():
playwright, browser, context = PlaywrightBrowserFactory.create_browser_context(
browser_name=config.browser_type,
headless=config.headless
)
yield context
context.close()
browser.close()
playwright.stop()
@pytest.fixture(scope="function")
def page(browser_context):
page = browser_context.new_page()
yield PlaywrightPage(page)
page.close()
@pytest.fixture(scope="function")
def mobile_page():
playwright, browser, context = PlaywrightBrowserFactory.create_mobile_browser("iPhone 12")
page = context.new_page()
yield PlaywrightPage(page)
page.close()
context.close()
browser.close()
playwright.stop()
@pytest.fixture(params=["chromium", "firefox", "webkit"])
def multi_browser_page(request):
playwright, browser, context = PlaywrightBrowserFactory.create_browser_context(request.param)
page = context.new_page()
yield PlaywrightPage(page)
page.close()
context.close()
browser.close()
playwright.stop()
4. Create Base Page
pages/playwright_base_page.py
from utils.logger import get_logger
logger = get_logger(__name__)
class PlaywrightBasePage:
def __init__(self, page):
self.page = page
self.timeout = 10000
def goto(self, url):
self.page.goto(url)
def click(self, selector):
self.page.click(selector)
def fill(self, selector, text):
self.page.fill(selector, text)
def get_text(self, selector):
return self.page.text_content(selector)
def is_visible(self, selector):
return self.page.is_visible(selector)
def wait_for_selector(self, selector):
self.page.wait_for_selector(selector)
def wait_for_load_state(self, state="networkidle"):
self.page.wait_for_load_state(state)
def screenshot(self, filename):
self.page.screenshot(path=f"reports/screenshots/{filename}.png")
def get_page_title(self):
return self.page.title()
def get_current_url(self):
return self.page.url
5. Advanced Features
Trace Recording
@pytest.fixture
def context_with_tracing(browser_context):
browser_context.tracing.start(screenshots=True, snapshots=True, sources=True)
yield browser_context
browser_context.tracing.stop(path="trace.zip")
Network Interception
def mock_api(page):
page.route("**/api/**", lambda route: route.fulfill(
status=200, json={"status": "ok"}
))
Performance Metrics
def get_performance_metrics(page):
return page.evaluate("() => JSON.stringify(window.performance)")
6. Run Commands
pytest tests/ui/ -m playwright
BROWSER=firefox pytest tests/ui/
HEADLESS=False pytest tests/ui/
pytest tests/ui/ -m mobile
pytest tests/ui/ --tracing on
pytest tests/ui/ -n 4
Best Practices
- Use automatic wait strategies — no
time.sleep() - Leverage trace recording for debugging
- Use contexts for test isolation
- Intercept networks to mock APIs
- Run multi-browser via parametrized fixtures