Selenium Rules for AI Assistants
These rules help AI coding assistants generate correct, idiomatic Selenium code. They cover the modern Selenium 4 API across all official language bindings.
Core Principles
Never use time.sleep() / Thread.sleep() / sleep(). Use explicit waits.
Never hardcode driver paths or versions. Selenium Manager resolves them automatically.
Always call driver.quit() in a finally block or equivalent to release browser resources.
Prefer CSS selectors over XPath for readability and speed. Prefer id and name first.
Use Page Object Model (POM) to separate page structure from test logic.
Installation
| Language | Command / Config |
|---|
| Python | pip install selenium |
| Java | Maven: selenium-java artifact, group org.seleniumhq.selenium |
| JavaScript | npm install selenium-webdriver |
| Ruby | gem install selenium-webdriver |
| .NET | dotnet add package Selenium.WebDriver |
Selenium Manager (bundled since Selenium 4.6) automatically downloads the correct browser driver. No webdriver-manager, chromedriver-binary, or manual driver setup is needed.
Starting a Browser
Python
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
Java
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
JavaScript (Node.js)
const { Builder } = require('selenium-webdriver');
const driver = await new Builder().forBrowser('chrome').build();
await driver.get('https://example.com');
Ruby
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.navigate.to 'https://example.com'
.NET (C#)
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com");
Always Quit the Driver
Python
try:
driver.get("https://example.com")
finally:
driver.quit()
Java
try {
driver.get("https://example.com");
} finally {
driver.quit();
}
JavaScript
try {
await driver.get('https://example.com');
} finally {
await driver.quit();
}
Ruby
begin
driver.navigate.to 'https://example.com'
ensure
driver.quit
end
.NET
using (IWebDriver driver = new ChromeDriver()) {
driver.Navigate().GoToUrl("https://example.com");
}
Locating Elements
Priority order: id > name > css > link_text > xpath
Python
from selenium.webdriver.common.by import By
driver.find_element(By.ID, "username")
driver.find_element(By.CSS_SELECTOR, "input[name='q']")
driver.find_elements(By.CSS_SELECTOR, "ul > li")
Java
import org.openqa.selenium.By;
driver.findElement(By.id("username"));
driver.findElement(By.cssSelector("input[name='q']"));
driver.findElements(By.cssSelector("ul > li"));
JavaScript
const { By } = require('selenium-webdriver');
await driver.findElement(By.id('username'));
await driver.findElement(By.css("input[name='q']"));
await driver.findElements(By.css('ul > li'));
Ruby
driver.find_element(id: 'username')
driver.find_element(css: "input[name='q']")
driver.find_elements(css: 'ul > li')
.NET
driver.FindElement(By.Id("username"));
driver.FindElement(By.CssSelector("input[name='q']"));
driver.FindElements(By.CssSelector("ul > li"));
Explicit Waits (REQUIRED — never use sleep)
Wait for a specific condition before interacting with an element.
Python
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, timeout=10)
element = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
element.click()
Java
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));
element.click();
JavaScript
const { until } = require('selenium-webdriver');
const element = await driver.wait(until.elementIsVisible(
driver.findElement(By.id('submit'))
), 10000);
await element.click();
Ruby
wait = Selenium::WebDriver::Wait.new(timeout: 10)
element = wait.until { driver.find_element(id: 'submit') }
element.click
.NET
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var element = wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("submit")));
element.Click();
Common Expected Conditions
| Condition | Python | Java |
|---|
| Element visible | visibility_of_element_located | ExpectedConditions.visibilityOf |
| Element clickable | element_to_be_clickable | ExpectedConditions.elementToBeClickable |
| Text present in element | text_to_be_present_in_element | ExpectedConditions.textToBePresentInElement |
| Alert present | alert_is_present | ExpectedConditions.alertIsPresent |
| URL contains | url_contains | ExpectedConditions.urlContains |
| Title contains | title_contains | ExpectedConditions.titleContains |
| Element staleness | staleness_of | ExpectedConditions.stalenessOf |
Browser Options & Capabilities
Run headless (Python example)
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
Other common Chrome options
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-gpu")
Set implicit wait (use sparingly — prefer explicit waits)
driver.implicitly_wait(5)
Do not mix implicit and explicit waits — this causes unpredictable timeouts.
Page Object Model
Encapsulate page structure in dedicated classes to improve maintainability.
Python example
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
URL = "https://example.com/login"
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def open(self):
self.driver.get(self.URL)
return self
def login(self, username, password):
self.wait.until(EC.element_to_be_clickable((By.ID, "username"))).send_keys(username)
self.driver.find_element(By.ID, "password").send_keys(password)
self.driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
return self
Actions (Mouse & Keyboard)
Python
from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(element).click().perform()
ActionChains(driver).double_click(element).perform()
ActionChains(driver).context_click(element).perform()
ActionChains(driver).drag_and_drop(source, target).perform()
from selenium.webdriver.common.keys import Keys
element.send_keys("Hello World")
element.send_keys(Keys.RETURN)
element.clear()
Handling Alerts, Frames, and Windows
Alerts (Python)
alert = driver.switch_to.alert
alert.accept()
alert.dismiss()
alert.send_keys("text")
Frames
driver.switch_to.frame("frame-id")
driver.switch_to.default_content()
Multiple Windows/Tabs
main_window = driver.current_window_handle
driver.switch_to.new_window('tab')
driver.switch_to.window(main_window)
driver.close()
driver.switch_to.window(main_window)
Taking Screenshots
driver.save_screenshot("screenshot.png")
element.screenshot("element.png")
JavaScript Execution
Use sparingly — prefer native Selenium interactions when possible.
result = driver.execute_script("return document.title;")
driver.execute_script("arguments[0].click();", element)
driver.execute_script("arguments[0].scrollIntoView(true);", element)
Working with Selects and Dropdowns
Python
from selenium.webdriver.support.select import Select
select = Select(driver.find_element(By.ID, "dropdown"))
select.select_by_visible_text("Option 1")
select.select_by_value("opt1")
select.select_by_index(0)
options = select.options
Selenium Grid
Run tests in parallel across different browsers and machines.
from selenium import webdriver
driver = webdriver.Remote(
command_executor="http://localhost:4444",
options=webdriver.ChromeOptions()
)
Start a local Grid (requires Java):
selenium-manager --grid
java -jar selenium-server.jar standalone
BiDi (WebDriver BiDirectional Protocol)
Selenium 4 supports real-time browser events via BiDi.
Python: Listen for console logs
from selenium import webdriver
from selenium.webdriver.common.bidi.console import Console
driver = webdriver.Chrome()
with driver.bidi_connection() as conn:
session = conn.session
Selenium Manager CLI
Selenium Manager is also a standalone CLI tool for driver and browser management.
selenium-manager --browser chrome
selenium-manager --browser firefox --browser-version 120
selenium-manager --init-skills
selenium-manager --init-rules
Common Errors & Fixes
| Error | Cause | Fix |
|---|
NoSuchElementException | Element not in DOM yet | Use explicit wait |
StaleElementReferenceException | DOM updated after element was found | Re-locate the element |
ElementNotInteractableException | Element hidden or covered | Scroll into view or wait for visibility |
TimeoutException | Condition never met in wait | Increase timeout or check selector |
WebDriverException: chrome not reachable | Browser crashed or closed | Check browser startup options |
SessionNotCreatedException | Driver/browser version mismatch | Let Selenium Manager resolve the driver |
Anti-Patterns to Avoid
❌ time.sleep(5) — use WebDriverWait instead
❌ driver.find_element(By.XPATH, "/html/body/div[3]/span[2]") — fragile absolute XPath
❌ Hardcoding driver paths like ChromeDriver("/usr/bin/chromedriver") — let Selenium Manager handle it
❌ Mixing implicit and explicit waits
❌ Not calling driver.quit() — causes zombie browser processes
❌ driver.get() inside a loop without proper cleanup
❌ Using execute_script to click elements that are interactable natively
Resources