Selenium
Advanced 18 min read Selenium

Selenium Grid & Parallel Testing

One test, many browsers. Selenium Grid routes WebDriver sessions to remote nodes so suites run in parallel across Chrome, Firefox and Edge. Learn the Router/Node architecture, run Grid with Docker, and drive parallel execution from the test runner.

Selenium Gridhubnodeparallel testingdocker-composecapabilitiesRemoteWebDriver
Introduction

What is this?

Selenium Grid is a server-side component that distributes WebDriver sessions across multiple machines and browsers. In Grid 4 a Router accepts new-session requests and forwards them to Nodes that run the actual browsers; Grid can also route to external cloud grids. Tests connect through RemoteWebDriver with a Capabilities object, and parallelism is orchestrated by the test runner (TestNG, JUnit or pytest), which opens many sessions concurrently. Grid turns a single-slot laptop into a browser farm that runs a full suite in minutes.

Motivation

Why do you need it?

  • Parallel execution across nodes cuts suite wall-clock time from hours to minutes.
  • One grid serves many teams, so tests no longer depend on per-developer browser installs.
  • A browser matrix (Chrome, Firefox, Edge, Safari) is exercised in a single run with no test changes.
  • Nodes can be added or removed without touching test code — scale by adding containers.
  • Running on remote nodes keeps browsers isolated from local state and frees developers' machines.
Think about it

Mental model

Imagine

A food-court kitchen with many cooks

Think of

Selenium Grid

Orders (sessions) are routed to whichever cook (node) is free and can make the requested dish (browser). More cooks mean more orders in parallel — you never rewrite the menu to add a cook.

Mechanics

How it works

  • The Router receives a new-session request with desired capabilities and picks a matching Node.
  • The Node spawns a WebDriver session in the requested browser and returns a session id and remote endpoint.
  • Tests create RemoteWebDriver pointing at the grid's address (e.g. http://localhost:4444) with capabilities set.
  • The test runner launches N concurrent tests, each creating a session that the grid places on a free node.
  • max-sessions and per-node browser config control how many parallel browsers a single node can host.

How a test session flows through Selenium Grid 4.

Test starts
Create session
Router
Node
Execute commands
Session ends
Reference

Key commands

docker compose up -d

Start the grid router and nodes defined in docker-compose.yml.

Container grid-router Started
docker compose up --scale node-chrome=3 -d

Scale the Chrome node service to three containers for more parallelism.

docker run -d -p 4444:4444 --name grid selenium/standalone-chrome:4.25.0

Run a single all-in-one grid node for quick local experiments.

curl http://localhost:4444/status

Check grid health and which nodes/capabilities are registered.

{"value":{"nodes":[{"id":"chrome-node","status":"UP","maxSessions":3}]}}
mvn test -Dsurefire.suiteXmlFiles=testng-parallel.xml

Run a TestNG suite whose XML declares parallel tests.

docker compose logs node-chrome

Inspect a node's session lifecycle and driver errors.

Hands-on

Examples

Point a test at the Grid with RemoteWebDriver

Point a test at the Grid with RemoteWebDriver
import java.net.URL;
import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
ChromeOptions options = new ChromeOptions();
options.setCapability("browserVersion", "stable");
options.setCapability("platformName", "linux");
WebDriver driver = new RemoteWebDriver(
new URL("http://localhost:4444"), options);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.get("https://example.com");
System.out.println(driver.getTitle());
driver.quit();

Instead of new ChromeDriver(), the test builds ChromeOptions, sets browser capabilities, and creates a RemoteWebDriver against the grid URL. The grid routes the session to a node that can serve a stable Chrome on linux. From there the test is identical to a local one — only the driver construction changes.

Real world

In production

  • Run the full regression nightly across the browser matrix with zero developer intervention.
  • Burst-scale nodes on CI: spin up five nodes for the suite, tear them down afterward.
  • Provide an internal browser farm for feature teams instead of local driver installs.
  • Route rare-browser tests (Safari via a cloud grid) through the same RemoteWebDriver code path.
Guidelines

Best practices

  • Pin browser and driver versions on every node via a fixed Docker image tag.
  • Keep max-sessions low enough to avoid starving node memory — one or two per container is typical.
  • Run one node per Docker container so a crashed browser cannot take down its neighbors.
  • Keep test code browser-agnostic: inject capabilities from config, never hard-code them.
  • Parallelize at the test-runner level (TestNG suite, pytest-xdist) instead of hand-rolled threads.
Watch out

Common mistakes

  • Running hundreds of sessions against nodes with too little memory, causing random browser crashes.
  • Hard-coding localhost in RemoteWebDriver and breaking the tests in grid or remote runs.
  • Ignoring the /status health check and blaming tests for infrastructure failures.
  • Using a single static driver with parallelism that expects one shared browser.
Root cause analysis

Common issues

Error
Unable to find a matching set of capabilities
Root cause

No registered node advertises the requested browser or version.

Fix

Check /status, align the requested capabilities with a node, or start a node that serves them.

Error
Max limit of 1 active sessions reached
Root cause

The node has no free session slots.

Fix

Raise max-sessions, add more nodes, or cap the runner's parallelism.

Error
ERR_CONNECTION_REFUSED connecting to the hub
Root cause

The grid is not running or the URL/port is wrong.

Fix

Verify containers are up and that the RemoteWebDriver URL matches the exposed port.

When things break

Debugging tips

  • Hit /status to confirm nodes are registered and inspect their browser/version capabilities.
  • Watch node containers with docker compose logs for session start/stop and driver errors.
  • Run one session serially against the grid before enabling parallelism.
  • Capture which node handled each session (session id + node id) to correlate failures.
Interviews

Interview checkpoint

Practice

Hands-on lab

Stand Up a Grid with Docker and Run Parallel Tests
40 min · advanced
In progress
Objectives
  • Run a grid router and Chrome node with Docker Compose
  • Verify registration with the /status endpoint
  • Point RemoteWebDriver tests at the grid
  • Scale nodes and observe sessions running in parallel

Stand Up a Grid with Docker and Run Parallel Tests

40 min · advanced

0/7 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which class does a test use to talk to a grid instead of a local browser?

2

Grid requires the tests to know which physical node will run them.

3

/status shows zero nodes and every session fails with 'unable to find matching capabilities'. What is the best fix?

Quick reference

Cheat sheet

Grid lifecycle
docker compose up -dStart grid router + nodes
docker compose up --scale node-chrome=3 -dScale a node service
curl http://localhost:4444/statusGrid health + capabilities
docker compose logs node-chromeNode session logs
docker compose downTear down the grid
Session capabilities
browserNamechrome, firefox, edge
browserVersionPin a browser version
platformNamelinux, windows, mac
max-sessionsConcurrent browsers per node
se:nodeMaxSessionsGrid 4 per-node session cap
Go deeper

Official documentation