Your Grid is running. Now you need to connect your tests to it. The switch from local execution to Grid execution requires one change in your test code: replace webdriver.Chrome() with webdriver.Remote(), pointing to the Grid URL and specifying the desired browser capabilities. Everything else — your page objects, your assertions, your test structure — stays exactly the same. This seamless transition is one of Grid’s most powerful features.
Remote WebDriver — Connecting Tests to Grid
Remote WebDriver sends commands over HTTP to the Grid Router instead of to a local browser driver. The API is identical to the local driver — your tests do not need to know whether they are running locally or on a remote Grid node.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
GRID_URL = "http://localhost:4444/wd/hub"
# ── Connect to Grid — Chrome ──
def create_remote_chrome():
options = ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
driver = webdriver.Remote(
command_executor=GRID_URL,
options=options,
)
return driver
# ── Connect to Grid — Firefox ──
def create_remote_firefox():
options = FirefoxOptions()
options.add_argument("--headless")
options.add_argument("--width=1920")
options.add_argument("--height=1080")
driver = webdriver.Remote(
command_executor=GRID_URL,
options=options,
)
return driver
# ── Configurable fixture for pytest ──
# conftest.py
import pytest
import os
GRID_URL_ENV = os.getenv("GRID_URL", "http://localhost:4444/wd/hub")
BROWSER = os.getenv("BROWSER", "chrome")
@pytest.fixture
def browser():
if BROWSER == "firefox":
options = FirefoxOptions()
options.add_argument("--headless")
else:
options = ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
# If GRID_URL is set, use Remote; otherwise use local
grid_url = os.getenv("GRID_URL")
if grid_url:
driver = webdriver.Remote(command_executor=grid_url, options=options)
else:
if BROWSER == "firefox":
driver = webdriver.Firefox(options=options)
else:
driver = webdriver.Chrome(options=options)
yield driver
driver.quit()
# ── Run locally vs on Grid — same test code ──
# Local: pytest tests/ (uses local Chrome)
# Grid: GRID_URL=http://grid:4444/wd/hub pytest tests/ (uses remote Chrome)
# Firefox: BROWSER=firefox GRID_URL=http://grid:4444/wd/hub pytest tests/
# ── Platform capabilities (request specific OS) ──
def create_chrome_on_linux():
options = ChromeOptions()
options.set_capability("platformName", "linux")
# Grid routes to a Node that matches: Chrome + Linux
return webdriver.Remote(command_executor=GRID_URL, options=options)
print("Remote WebDriver Connection")
print("=" * 55)
print(f" Grid URL: {GRID_URL}")
print(f" Local: driver = webdriver.Chrome(options=options)")
print(f" Remote: driver = webdriver.Remote(grid_url, options=options)")
print(f"\n The API is IDENTICAL — tests do not change.")
print(f"\n Run modes:")
print(f" $ pytest tests/ → local Chrome")
print(f" $ GRID_URL=http://grid:4444/wd/hub pytest tests/ → Grid Chrome")
print(f" $ BROWSER=firefox GRID_URL=... pytest tests/ → Grid Firefox")
command_executor URL can be either http://grid:4444/wd/hub (Grid 3 compatibility) or http://grid:4444 (Grid 4 native). Both work with Grid 4. Cloud providers use their own URLs: https://USER:KEY@hub.browserstack.com/wd/hub for BrowserStack, https://USER:KEY@ondemand.saucelabs.com/wd/hub for Sauce Labs. The same webdriver.Remote() call works with self-hosted Grid, BrowserStack, Sauce Labs, and LambdaTest — only the URL and credentials change.GRID_URL is set, use webdriver.Remote(); when it is not set, use webdriver.Chrome() locally. This lets developers run tests locally during development (fast feedback) and on Grid in CI/CD (parallel execution) without changing any code. The environment drives the configuration, not the test.--no-sandbox in Chrome options when running inside Docker containers. Chrome’s sandbox requires specific Linux kernel capabilities that Docker does not provide by default. Without --no-sandbox, Chrome fails to start inside containers with cryptic errors about namespace cloning. This flag is safe in containerised environments because Docker itself provides the isolation that Chrome’s sandbox normally handles.Common Mistakes
Mistake 1 — Hardcoding the Grid URL in test files
❌ Wrong: driver = webdriver.Remote("http://192.168.1.50:4444/wd/hub", options) in every test file — breaks when the Grid IP changes.
✅ Correct: Reading the URL from an environment variable or configuration file: webdriver.Remote(os.getenv("GRID_URL"), options). Different environments (local, CI, staging) use different Grid URLs.
Mistake 2 — Not setting window size for headless remote browsers
❌ Wrong: Running headless Chrome on Grid without setting window size — defaults to 800×600, causing responsive layout tests to fail.
✅ Correct: Always setting --window-size=1920,1080 in Chrome options for consistent, full-desktop rendering in headless mode.