Below are several practical examples showcasing different browser-testing use cases in LoadForge. All scripts inherit from PlaywrightUser
and use the Locust-Playwright integration found in locust_plugins.users.playwright
.
1. Basic Navigation & Timing
Navigate through a site and record timings for key page loads.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw, event
class NavUser(PlaywrightUser):
@task
@pw
async def home_to_articles(self, page: PageWithRetry):
async with event(self, "Home"):
await page.goto("/")
async with event(self, "Articles"):
async with page.expect_navigation():
await page.click('a:has-text("Articles")')
2. Clicking Elements – Different Strategies
Demonstrates clicking links via text, CSS selector, XPath, and nth-child()
.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw
class ClickUser(PlaywrightUser):
@task
@pw
async def click_examples(self, page: PageWithRetry):
await page.goto("/")
# By link text
await page.click('text=Features')
# By CSS id
await page.click('#signup-button')
# By nth-child
await page.click('nav ul li:nth-child(3) a')
# By XPath
await page.click('//footer//a[contains(., "Contact")]')
Login form submission and verification of successful navigation using an assertion.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw
class LoginUser(PlaywrightUser):
@task
@pw
async def login(self, page: PageWithRetry):
await page.goto("/login")
await page.fill('input[name="email"]', 'test@example.com')
await page.fill('input[name="password"]', 'password123')
async with page.expect_navigation():
await page.click('button:has-text("Log in")')
assert await page.locator('text=Dashboard').is_visible(), "Login failed"
4. Performance Metric – Largest Contentful Paint (LCP)
Throttle network, load page, and fire a custom request event marking pass/fail based on LCP.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw, event
import time
class LCPUser(PlaywrightUser):
LCP_THRESHOLD = 1200 # ms
@task
@pw
async def check_lcp(self, page: PageWithRetry):
cdp = await self.browser_context.new_cdp_session(page)
await cdp.send('Network.enable')
await cdp.send('Network.emulateNetworkConditions', {
'offline': False,
'downloadThroughput': (1*1024*1024)/8,
'uploadThroughput': (1*1024*1024)/8,
'latency': 50,
})
start = time.time()
async with event(self, "Load home"):
await page.goto("/")
await page.wait_for_timeout(1000)
lcp = await page.evaluate("""
new Promise(r => {
new PerformanceObserver(l => r(l.getEntries().at(-1).startTime))
.observe({type:'largest-contentful-paint', buffered:true});
})
""")
self.environment.events.request.fire(
request_type="LCP",
name=f"LCP {'PASS' if lcp<=self.LCP_THRESHOLD else 'FAIL'}",
start_time=start,
response_time=lcp,
response_length=0,
context={**self.context()},
url="lcp_metric",
exception=None if lcp<=self.LCP_THRESHOLD else Exception(f"LCP {lcp:.0f}ms > {self.LCP_THRESHOLD}ms"),
)
5. Screenshot on Failure
Take a screenshot if a critical element is not visible.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw
class ScreenshotUser(PlaywrightUser):
@task
@pw
async def critical_check(self, page: PageWithRetry):
await page.goto("/")
if not await page.locator('text=Pricing').is_visible():
await page.screenshot(path="/tmp/pricing_missing.png", full_page=True)
6. Accessibility (Axe) Scan
Run an Axe accessibility scan directly from the browser context.
from locust import task
from locust_plugins.users.playwright import PlaywrightUser, PageWithRetry, pw, event
import json, time
AXE_SCRIPT_URL = "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.8.2/axe.min.js"
class AxeUser(PlaywrightUser):
@task
@pw
async def axe_scan(self, page: PageWithRetry):
async with event(self, "Axe scan"):
await page.goto("/")
await page.add_script_tag(url=AXE_SCRIPT_URL)
results = await page.evaluate("axe.run()")
violations = results.get('violations', [])
if violations:
msg = json.dumps(violations[:3], indent=2) # limit output
raise Exception(f"Accessibility issues found: {msg}")
These scripts should provide a solid starting point for common browser-testing scenarios. Modify selectors, thresholds, and URLs to match your application.