Skip to content

Selenium performance testing in MaxoPerf

The Taurus selenium executor drives real Chrome or Firefox instances as virtual users. Where a JMeter or k6 VU sends raw HTTP requests, a Selenium VU loads the full page — HTML, CSS, JavaScript, web fonts, images — and executes your Python WebDriver script as a real browser would. This is how you measure what users actually see in MaxoPerf.

When MaxoPerf runs a selenium executor job:

  • Each VU is a fully isolated Chrome (or Firefox) process.
  • The browser navigates to your target, executes your script, and reports every WebDriver interaction as a labeled timing measurement.
  • Errors include HTTP failures, assertion failures, and uncaught JavaScript exceptions.
  • Results appear in the standard MaxoPerf run-detail view alongside any other metrics from the same run.

You do not get raw Core Web Vitals (LCP, CLS, INP) automatically from the selenium executor — you get interaction timings. To capture web vitals, inject the web-vitals JavaScript library in your script and report the values via a custom label. See Frontend web vitals under load for the pattern.

execution:
- executor: selenium
concurrency: 5 # one Chrome process per VU — keep low
ramp-up: 2m
hold-for: 10m
scenario: checkout-journey
scenarios:
checkout-journey:
script: scripts/checkout.py # Python WebDriver script, uploaded as test asset
browser: chrome # chrome (default) or firefox
headless: true # always true on MaxoPerf runners
modules:
selenium:
chromedriver:
version: latest

Create scripts/checkout.py and upload it as a Test asset alongside the Taurus YAML:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def test_checkout_journey(driver):
"""
Full checkout journey: home → product → cart → order summary.
Each step is a separate Selenium label in MaxoPerf results.
"""
# Step 1: Load homepage
driver.get("https://app.example.com/")
WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".product-grid"))
)
# Step 2: Open a product
driver.find_element(By.CSS_SELECTOR, ".product-grid .product-card:first-child").click()
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "add-to-cart"))
)
# Step 3: Add to cart
driver.find_element(By.ID, "add-to-cart").click()
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".cart-count[data-count='1']"))
)
# Step 4: Open cart and proceed to checkout
driver.find_element(By.CSS_SELECTOR, ".cart-icon").click()
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.LINK_TEXT, "Proceed to checkout"))
).click()
# Step 5: Assert order summary page loaded
WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".order-summary"))
)
  1. In the MaxoPerf console, open the test → Files tab.

  2. Upload your Taurus YAML (checkout.yaml) as the Entrypoint.

  3. Upload scripts/checkout.py as a Test asset. The YAML path scripts/checkout.py must match the relative path you set when uploading.

  4. Save. MaxoPerf validates that the YAML references the uploaded script.

  5. In the Load profile tab, confirm concurrency (e.g. 5), ramp-up (2m), and hold duration (10m).

  6. Click Run. The runner starts Chrome instances equal to the concurrency value. Browser VUs are slower to cold-start — expect the first metrics to appear 20–60 s into the run.

If your team recorded flows with Selenium IDE, you can upload the .side file directly as the entrypoint — MaxoPerf infers the selenium executor from the file extension:

my-flow.side → Entrypoint → engine: selenium (auto-detected)

To control concurrency and duration, wrap the .side file in a Taurus YAML:

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

Scaling browser VUs — cost and resource guidance

Section titled “Scaling browser VUs — cost and resource guidance”
VU countUse caseRunner resource estimate
1–3Smoke / sanity check — verify the journey runs~1–3 GB RAM per runner
5–10Journey performance measurement~5–10 GB RAM per runner
10–20Multi-user browser stress (edge case)Requires dedicated runner sizing
20+Avoid — use protocol VUs for scaleCost is prohibitive; results become unreliable

Each Chrome VU consumes roughly 500 MB–1 GB of RAM and 1–2 CPU cores under load. MaxoPerf runners are sized for protocol VUs; browser tests at high concurrency may exhaust runner resources and produce flaky results rather than load data.

After the run finishes:

  • Throughput — shown as iterations per second (completed browser flows), not HTTP RPS. A single flow may include 5 WebDriver interactions — each is also reported as a separate label.
  • Latency — the time for each WebDriver get(), click(), or wait_for_element() step. Focus on the navigation label for page-load time and the final wait_for label for the full journey duration.
  • Error rate — WebDriver assertion failures and uncaught exceptions. A high error rate usually means an element was not found — often caused by a layout change or a slow render that exceeded the WebDriverWait timeout.
  • Runner health — check the Runners tab. Browser VUs are more likely to saturate runners. A runner in degraded state indicates resource exhaustion; reduce concurrency.

Do:

  • Keep concurrency low (2–10) — browser tests measure UX, not throughput.
  • Use headless: true — headed Chrome is not supported on MaxoPerf runners.
  • Test your script locally with python scripts/checkout.py before uploading.
  • Use WebDriverWait with meaningful timeouts that reflect real user expectations.

Don’t:

  • Use browser tests to generate high load — use protocol VUs for that.
  • Put real credentials in the script — use Manage test secrets and inject them via environment variables.
  • Compare Selenium iteration-rate numbers to JMeter RPS numbers — they measure different things.