Skip to content

Selenium browser load test

Problem: You want to measure end-user experience — including JavaScript execution and page rendering — under concurrent load, using real browser instances rather than HTTP simulation.

Test type: Frontend browser performance test.

  • A MaxoPerf account and a workspace.
  • Python 3.8+ and selenium installed locally (pip install selenium) to validate your script before uploading.
  • The URL of the page you want to test (staging or a dedicated load-test environment — never production without consent).
  • Any credentials your flow needs, stored as a project secret.

Create test_homepage.py locally. This script logs in and verifies the dashboard loads:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
def test_homepage(driver):
base_url = os.environ.get("BASE_URL", "https://app.example.com")
# Load the login page
driver.get(f"{base_url}/login")
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "email"))
)
# Fill credentials — injected via MaxoPerf secrets as env vars
driver.find_element(By.ID, "email").send_keys(
os.environ.get("TEST_EMAIL", "testuser@example.com")
)
driver.find_element(By.ID, "password").send_keys(
os.environ.get("TEST_PASSWORD", "changeme")
)
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
# Assert the dashboard loaded
WebDriverWait(driver, 15).until(
EC.url_contains("/dashboard")
)
# Verify at least one key element is visible
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='dashboard-header']"))
)

The function name must be test_<anything> — Taurus’s Selenium executor discovers test functions by this prefix.

Create selenium-homepage.yml:

execution:
- executor: selenium
concurrency: 5 # 5 parallel Chrome instances — scale up slowly
ramp-up: 30s # reach full concurrency over 30 seconds
hold-for: 3m # sustain for 3 minutes
scenario: homepage-login
scenarios:
homepage-login:
script: test_homepage.py # must match the filename uploaded as a Test asset
browser: chrome # chrome (default) or firefox
settings:
env:
BASE_URL: https://staging.example.com

Credentials (TEST_EMAIL, TEST_PASSWORD) are not in the YAML — inject them as project secrets so they never appear in version control.

  1. Open your test in the MaxoPerf console and go to the Files tab.
  2. Upload selenium-homepage.yml and mark it as the Entrypoint.
  3. Upload test_homepage.py and leave it as a Test asset. MaxoPerf matches this filename to the script: key in your YAML.
  4. Click Save. MaxoPerf validates the YAML: it checks executor: selenium, confirms test_homepage.py is present as a test asset, and shows a green validation badge.
  1. Go to Project → Secrets.
  2. Add TEST_EMAIL and TEST_PASSWORD with their staging values.
  3. Return to the test and confirm the secrets are selected in the Secrets dropdown.
  1. Click Run on the test detail page.
  2. MaxoPerf bundles selenium-homepage.yml, test_homepage.py, and the injected secrets, then dispatches the bundle to a runner.
  3. The runner starts 5 Chrome instances (concurrency: 5), ramping over 30 seconds, and drives each browser through the test_homepage function in a loop for 3 minutes.

Once the run completes, check the following in the Run detail view:

  • Error rate — should be near 0%. A WebDriver TimeoutException or assertion failure counts as an error. Check the Errors tab for stack traces if you see failures.
  • Iteration time — the time to complete one full browser flow. For a login-and-dashboard load, expect 3–10 seconds depending on app performance.
  • Throughput — iterations per second. With 5 VUs and a ~5 s iteration, expect ~1 it/s.
  • Resource utilisation — check the runner CPU/memory panel. Browser tests are CPU-bound; if utilisation is above 90%, reduce concurrency before scaling up.
scenarios:
homepage-login:
script: test_homepage.py
browser: firefox

Extend the test function to navigate through checkout steps:

def test_checkout(driver):
# ... login steps ...
driver.find_element(By.LINK_TEXT, "Products").click()
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".product-card"))
)
driver.find_element(By.CSS_SELECTOR, ".product-card:first-child button").click()
driver.find_element(By.LINK_TEXT, "Checkout").click()
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".order-summary"))
)

Update scenarios.homepage-login.script to test_checkout.py and re-upload.

Use a Selenium IDE recording instead of a Python script

Section titled “Use a Selenium IDE recording instead of a Python script”

Record your flow in Selenium IDE, export as a .side file, and upload it directly as the entrypoint — MaxoPerf infers executor: selenium from the .side extension without needing a YAML wrapper:

my-recording.side → Entrypoint → engine: selenium

Or wrap it in YAML for explicit concurrency control:

execution:
- executor: selenium
concurrency: 3
hold-for: 5m
scenario: recorded-flow
scenarios:
recorded-flow:
script: my-recording.side

Automatically fail the run if the error rate exceeds 2% or iteration time exceeds 12 s:

reporting:
- module: passfail
criteria:
- error-rate > 2% for 30s: fail
- avg-rt > 12s for 1m: fail

See Failure criteria pass/fail gates for the full passfail reference.