Testland
Browse all skills & agents

selenium-grid-4-runner

Author and operate Selenium Grid 4 - self-hosted distributed WebDriver. Covers the six-component architecture (Router / Distributor / Session Map / Event Bus / New Session Queue / Node), standalone vs hub-and-node modes, the Docker-image stack (selenium/standalone-chrome, selenium/hub, selenium/node-chrome), node registration, session-queue tuning, and observability. Use for self-hosted cross-browser testing when data residency or cost-control require an on-prem grid. This is the self-hosted execution RUNNER - for the zero-infra alternative use playwright-testing browser projects (bundled engines); for managed cloud grids use cloud-grid-e2e (BrowserStack / Sauce Labs / LambdaTest); to decide WHICH browsers and tiers to run use browser-matrix-strategy-reference.

Install with skills.sh (any agent)

npx skills add testland/qa --skill selenium-grid-4-runner
View source

selenium-grid-4-runner

Overview

Selenium Grid 4 is the self-hosted distributed WebDriver infrastructure - the open-source alternative to cloud-grid SaaS providers. Per selenium.dev/documentation/grid (opens in new window).

Composes with browser-matrix-strategy-reference for matrix planning.

When to use

  • Data-residency requirements forbid cloud grids.
  • Cost: high-volume testing where cloud per-session pricing exceeds self-hosting break-even.
  • Internal-network apps where tunnel solutions (BrowserStackLocal / Sauce Connect) are insufficient.
  • Custom browser builds / non-standard configurations cloud grids don't support.

For cloud-hosted alternatives see the sibling cloud-grid-e2e.

Authoring

Six-component architecture

ComponentRole
RouterEntry point; routes WebDriver requests to the right session
DistributorAllocates new sessions to available Nodes based on capabilities
Session MapTracks active sessions (session ID → Node URL)
Event BusInternal messaging between components
New Session QueueHolds pending session requests when no Node available
NodeRuns actual browser instances; registers with the Distributor

Standalone mode (development / small teams)

All components in one JVM:

# Download from selenium.dev/downloads
java -jar selenium-server-<version>.jar standalone

Default port 4444. WebDriver clients connect to http://localhost:4444/wd/hub.

Standalone mode is suitable for a single developer's machine or a small CI runner with co-located browsers.

Hub-and-node mode (production)

Hub on one machine, Nodes on others:

# Hub
java -jar selenium-server-<version>.jar hub

# Node (on another machine)
java -jar selenium-server-<version>.jar node \
  --hub http://hub-host:4444 \
  --port 5555

For very large deployments each of the six components can run as its own process; see references/distributed-and-ci.md. Most teams run hub-and-node.

Docker stack

Docker images are published as selenium/* on Docker Hub. Pin one Grid version across every image via a single SE_VERSION variable (examples use 4.21.0); keep it identical on the Hub and all Nodes.

# docker-compose.yml   (set SE_VERSION=4.21.0 in .env or the environment)
services:
  selenium-hub:
    image: selenium/hub:${SE_VERSION}
    ports: ["4442:4442", "4443:4443", "4444:4444"]

  chrome:
    image: selenium/node-chrome:${SE_VERSION}
    shm_size: 2gb
    depends_on: [selenium-hub]
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=2

  firefox:
    image: selenium/node-firefox:${SE_VERSION}
    shm_size: 2gb
    depends_on: [selenium-hub]
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443

  edge:
    image: selenium/node-edge:${SE_VERSION}
    shm_size: 2gb
    depends_on: [selenium-hub]
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443

shm_size: 2gb is required for Chrome (shared-memory bloat with many tabs).

Standalone Docker (simpler)

docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" \
  selenium/standalone-chrome:${SE_VERSION}

Port 7900 exposes noVNC (browser at http://localhost:7900) for live-session viewing.

Running

Connect a WebDriver client

from selenium import webdriver

driver = webdriver.Remote(
    command_executor="http://grid-router:4444/wd/hub",
    options=webdriver.ChromeOptions(),
)
driver.get("https://example.com")
# ...
driver.quit()

For Kubernetes-deployed Grid use the cluster-internal DNS: http://selenium-router.test-ns.svc.cluster.local:4444/wd/hub.

Capabilities

Standard W3C - no grid-specific options needed:

{
  "browserName": "chrome",
  "browserVersion": "stable",
  "platformName": "linux"
}

Session-queue tuning

Key knobs:

SettingEffect
--session-request-timeoutHow long a queued session waits before failing (default 300s)
--session-retry-intervalPolling interval for matching capabilities (default 5s)
SE_NODE_MAX_SESSIONSMax concurrent sessions per Node (default 1)
SE_NODE_SESSION_TIMEOUTInactive session cleanup (default 300s)

Tune SE_NODE_MAX_SESSIONS per Node's CPU + memory budget; typical: 2 Chrome / 1 Firefox per 2-core / 4 GB Node.

Observability

Grid 4 exposes:

  • GraphQL endpoint at /graphql for session inspection
  • Status endpoint at /status for ready-check
  • Prometheus metrics at /wd/hub/status (Grid health, session counts)

For production add a Grafana dashboard polling Prometheus.

Parsing results

Grid 4 doesn't add session videos / HAR by default - that's the test client's responsibility (or via a sidecar like selenoid + selenoid-ui for Grid 3-style recording).

Logs at /var/log/seluser/ inside Docker containers, exportable via volume mount.

CI integration

Boot the grid, gate on /status ready before running tests, and always tear down. Full GitHub Actions workflow: references/distributed-and-ci.md.

Anti-patterns

Anti-patternWhy it failsFix
shm_size default (64 MB) on Chrome nodeChrome crashes mid-sessionAlways shm_size: "2g"
SE_NODE_MAX_SESSIONS too highOOM / CPU thrashingConservative: 2 per 2-core Node
Hub-and-node without health checkFailed nodes silently drop sessionsWait for /status ready before tests start
Standalone in productionNo HA; single point of failureHub-and-node minimum for prod
Manually allocating ports for NodesConflictsLet Docker assign + use service DNS
No session-queue timeoutSessions wait forever; CI hangsSet --session-request-timeout bounded
Mixing Selenium versions across Hub + NodesCapability negotiation breaksPin same Grid version across all components

Limitations

  • No real-device support out of box. Mobile testing needs Appium server + emulators / real devices - significant additional infrastructure.
  • Browser-version matrix is self-managed. Cloud grids ship 3000+ combinations; self-hosted ≤ what your team builds.
  • HA + scaling is your problem. Cloud grids handle it; on self-hosted you do.
  • macOS / iOS Safari requires actual macOS hosts. Linux can run Chrome / Firefox / Edge but not Safari.

References

Selenium Grid 4 - fully-distributed layout and CI

View source (opens in new window)

Selenium Grid 4 - fully-distributed layout and CI

Deep-dive extensions to selenium-grid-4-runner. Standalone and hub-and-node (both in the parent SKILL.md) cover almost every team; reach for these only when the grid must scale past a single hub or run in CI.

Fully-distributed mode (all components separated)

For very large deployments, run each of the six components as its own process instead of one hub JVM. Most teams do NOT need this - hub-and-node is the default.

# Event Bus
java -jar selenium-server.jar event-bus --port 5557

# New Session Queue
java -jar selenium-server.jar sessionqueue --port 5559

# Session Map
java -jar selenium-server.jar sessions --port 5556

# Distributor
java -jar selenium-server.jar distributor --port 5553 \
  --sessions http://sessions-host:5556 \
  --sessionqueue http://queue-host:5559 \
  --bind-bus-events false \
  --publish-events tcp://event-bus-host:4442 \
  --subscribe-events tcp://event-bus-host:4443

# Router
java -jar selenium-server.jar router --port 4444 \
  --sessions http://sessions-host:5556 \
  --distributor http://distributor-host:5553 \
  --sessionqueue http://queue-host:5559

# Node(s)
java -jar selenium-server.jar node \
  --publish-events tcp://event-bus-host:4442 \
  --subscribe-events tcp://event-bus-host:4443

CI integration (GitHub Actions)

Boot the grid, gate on /status ready before running tests, and always tear down:

on: pull_request
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Start Selenium Grid
        run: docker-compose -f selenium-grid.yml up -d
      - name: Wait for Grid ready
        run: |
          for i in {1..30}; do
            curl -s http://localhost:4444/wd/hub/status | grep -q '"ready":true' && break
            sleep 2
          done
      - name: Run E2E tests
        run: pytest tests/e2e/ --grid-url=http://localhost:4444/wd/hub
      - name: Tear down Grid
        if: always()
        run: docker-compose -f selenium-grid.yml down

Related skills

browser-matrix-strategy-reference

Pure-reference for designing and reviewing a browser / OS / device test matrix from traffic data - the T1/T2/T3 tier-membership heuristics (T1 >=5% traffic, T2 1-5% or statutory, T3 <1% with customer demand), the traffic-share sources (own analytics, StatCounter, MDN browser-compat-data), a worked matrix template with tier-change log, the matrix review checklist (staleness, T1 oversize, below-threshold T1 entries, missing real-device coverage), how to justify dropping a legacy browser (IE11, old iOS Safari), and the compatibility budget (tier caps, CI cost formula, published support statement) in references/compatibility-budget.md. Use when designing an initial matrix, capping or publishing a support policy, running a quarterly re-tier review, or making the case to drop a browser. This is the WHAT-to-test strategy reference - to execute the matrix use playwright-testing browser projects (bundled engines), selenium-grid-4-runner (self-hosted), or cloud-grid-e2e (managed grids).

cloud-grid-e2e

Author and run E2E tests on a cloud browser grid - BrowserStack Automate, Sauce Labs, or LambdaTest. All three follow one pattern: username + access-key env vars, a W3C WebDriver hub URL, a vendor options dict inside the capabilities (bstack:options / sauce:options / LT:Options), a local tunnel binary for internal apps, session pass/fail reporting, and a CI matrix throttled to the plan's parallel-session limit. Worked example uses BrowserStack; per-vendor deltas live in references/. Use for cross-browser regression on real devices + browsers beyond the engines bundled on the local machine - distinct from a local matrix runner and from self-hosted Selenium Grid.

cypress-testing

Authors and improves Cypress E2E tests - installs Cypress, configures `cypress.config.ts`, authors `cy.*` command chains, refactors existing specs (`cy.wait(ms)` sleeps into assertions, repeated flows into `cy.session` custom commands), and debugs with the time-travel GUI; Cypress Cloud for parallel runs and recording. Use for both greenfield test authoring and improving hand-written specs already in the codebase. For automated refactor of raw Cypress Studio recordings specifically, use a dedicated codegen-review pass.

playwright-testing

Authors and remediates Playwright E2E tests across Chromium, Firefox, WebKit - `npm init playwright@latest` scaffolding, `playwright.config.ts` browser projects, accessibility-first locators (`getByRole`/`getByLabelText`) to replace brittle CSS selectors, web-first assertions to eliminate `waitForTimeout` flakiness, Page Object pattern, trace viewer debugging, sharded parallel execution with merged HTML reporting, mobile-web emulation via the `devices` catalog (viewport / DPR / touch per-device projects), the cross-browser matrix with branded channels (chrome / msedge) in references/browser-matrix.md, and GitHub Actions CI integration. Use for new test authoring, flakiness remediation, mobile-breakpoint regression, cross-browser matrix setup, and CI setup; for reviewing codegen output specifically, use a dedicated codegen-review pass.

selenium-testing

Authors Selenium WebDriver tests in any of its 6+ supported languages (Java, Python, JavaScript, C#, Ruby, Kotlin, PHP) - picks the appropriate language binding, configures WebDriver per browser, uses `By.*` locators with the team's accessibility-first preference where supported, runs locally + via Selenium Grid for distributed execution, parses results to JUnit XML. Use for legacy Selenium-locked stacks; new projects pick Playwright or Cypress.

web-e2e-overview

Teaches web end-to-end testing from first principles: what browser-driven E2E covers and how it differs from unit and integration tests, a decision table for choosing between Playwright, Cypress, Selenium WebDriver, WebdriverIO, Puppeteer, TestCafe and the BrowserStack / Sauce Labs / LambdaTest cloud grids based on files already present in the repo, install and first-run commands for each, and the flakiness traps (fixed sleeps, CSS and XPath selectors, state shared between tests) that sink new suites. Use when a web application has no E2E coverage yet, when picking or replacing an E2E framework, or when a first browser test needs to go green end to end.

webdriverio-testing

Authors WebdriverIO E2E tests - `npm init wdio@latest` scaffolding, services architecture (sauce, browserstack, appium, devtools), reporters (spec, allure, junit), built-in Mocha/Jasmine/Cucumber framework integrations. WebdriverIO sits between Selenium (W3C protocol) and Playwright (modern API) - Selenium-protocol-compatible with rich plugin ecosystem. Use when the team needs WebDriver protocol + service-based device-farm integration.