Selenium performance testing in MaxoPerf
The Taurus selenium executor drives real Chrome or Firefox instances as virtual users. A JMeter or k6 VU sends raw HTTP requests. A Selenium VU loads the full page (HTML, CSS, JavaScript, web fonts, images) and runs your Python WebDriver script the way a real browser would. This is how you measure in MaxoPerf what users see.
Before you start
Section titled “Before you start”- Read Browser vs protocol load to confirm browser testing is the right approach for your goal.
- Read By engine: Selenium browser tests for executor configuration reference.
- Have a target URL that the MaxoPerf runner locations you plan to use can reach.
What the selenium executor gives you
Section titled “What the selenium executor gives you”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.
The selenium executor does not give you raw Core Web Vitals (LCP, CLS, INP) automatically. You get interaction timings. To capture web vitals, inject the web-vitals JavaScript library in your script and report the values under a custom label. See Frontend web vitals under load for the pattern.
Taurus YAML with the selenium executor
Section titled “Taurus YAML with the selenium executor”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: latestPython WebDriver script
Section titled “Python WebDriver script”Create scripts/checkout.py and upload it as a Test asset alongside the Taurus YAML:
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom 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")) )Upload and run
Section titled “Upload and run”-
In the MaxoPerf console, open the test → Files tab.
-
Upload your Taurus YAML (
checkout.yaml) as the Entrypoint. -
Upload
scripts/checkout.pyas a Test asset. The YAML pathscripts/checkout.pymust match the relative path you set when uploading. -
Save. MaxoPerf validates that the YAML references the uploaded script.
-
In the Load profile tab, confirm concurrency (e.g.
5), ramp-up (2m), and hold duration (10m). -
Click Run. The runner starts as many Chrome instances as the
concurrencyvalue. Browser VUs take longer to cold-start, so expect the first metrics 20–60 s into the run.
Using a Selenium IDE .side file
Section titled “Using a Selenium IDE .side file”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.sideScaling browser VUs: cost and resource guidance
Section titled “Scaling browser VUs: cost and resource guidance”| VU count | Use case | Runner resource estimate |
|---|---|---|
| 1–3 | Smoke / sanity check: verify the journey runs | ~1–3 GB RAM per runner |
| 5–10 | Journey performance measurement | ~5–10 GB RAM per runner |
| 10–20 | Multi-user browser stress (edge case) | Requires dedicated runner sizing |
| 20+ | Avoid; use protocol VUs for scale | Cost is prohibitive; results become unreliable |
Each Chrome VU uses 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 give you flaky results instead of load data.
Reading browser test results
Section titled “Reading browser test results”After the run finishes:
- Throughput is shown as iterations per second (completed browser flows), not HTTP RPS. A single flow may include 5 WebDriver interactions, and each one is also reported as a separate label.
- Latency is the time for each WebDriver
get(),click(), orwait_for_element()step. Read thenavigationlabel for page-load time and the finalwait_forlabel for the full journey duration. - Error rate counts WebDriver assertion failures and uncaught exceptions. A high error rate usually means an element was not found, often because of a layout change or a slow render that ran past the
WebDriverWaittimeout. - Runner health is on the Runners tab. Browser VUs saturate runners more easily. A runner in
degradedstate has run out of resources; reduce concurrency.
Do / don’t
Section titled “Do / don’t”Do:
- Keep concurrency low (2–10). Browser tests measure UX, not throughput.
- Use
headless: true. MaxoPerf runners do not support headed Chrome. - Test your script locally with
python scripts/checkout.pybefore uploading. - Use
WebDriverWaitwith 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 through environment variables.
- Compare Selenium iteration-rate numbers with JMeter RPS numbers. They measure different things.
Where to go next
Section titled “Where to go next”- Frontend web vitals under load: how to capture LCP/CLS/INP in a browser test.
- Hybrid load architecture: combine browser VUs with protocol load in one run.
- By engine: Selenium browser tests: executor reference,
.sidefiles, and thewdioalternative. - Browser vs protocol load: the tradeoffs, to confirm you chose the right approach.