July 21, 2026
Selenium Cheatsheet
A practical Selenium cheatsheet covering setup, navigation, element locators, waits, assertions, windows, frames, screenshots, and debugging commands for Selenium WebDriver users.
Selenium remains one of the most widely used browser automation stacks because it is explicit, language-friendly, and backed by the WebDriver standard and the official Selenium documentation. That combination is useful for teams that want direct control over browser interactions, especially when they need to integrate browser tests into existing application code, CI pipelines, and test reporting systems.
This cheatsheet is meant to be compact but practical. It focuses on the commands and patterns that show up repeatedly in real suites, setup, navigation, elements, waits, assertions, windows, frames, screenshots, and debugging. It also calls out common failure modes, because Selenium is less about memorizing API calls and more about understanding where browser automation tends to become brittle.
The core skill with Selenium is not “clicking things,” it is building tests that can tolerate asynchronous UI behavior, dynamic locators, and environment differences without turning maintenance into a second job.
What Selenium is good at, and where it tends to cost more
Selenium is a browser automation API, not a full test platform. That distinction matters.
It is a strong fit when your team wants:
- code-first tests in Python, Java, C#, JavaScript, Ruby, or another supported language
- direct control over locators, waits, browser sessions, and test orchestration
- compatibility with existing CI/CD, test runners, and reporting tools
- vendor-neutral browser automation that maps closely to the WebDriver standard
The tradeoff is that Selenium gives you primitives, not a suite of higher-level maintenance workflows. Teams often need to build, or assemble, their own layers for:
- stable locator conventions
- retry and flake handling
- screenshot and trace collection
- parallel execution infrastructure
- reporting and historical analysis
- environment setup for local and cloud browsers
That is why some teams eventually look at alternatives such as Endtest vs Selenium, especially when they want browser automation, reports, cloud execution, and maintenance workflows without building the surrounding framework. Endtest is a relevant option when the team prefers agentic AI-assisted, low-code or no-code test creation with editable platform-native steps, rather than a fully hand-coded framework.
Selenium setup checklist
Before writing tests, confirm the following pieces are in place:
- a language binding for your stack
- a browser installed locally or a remote browser provider available
- the matching driver strategy, preferably via Selenium Manager in recent Selenium versions, or a managed grid if you need scale
- a test runner such as pytest, JUnit, NUnit, or Mocha
- a consistent way to manage test data and base URLs
For Python, a minimal install often looks like this:
pip install selenium pytest
A basic browser session in Python:
from selenium import webdriver
browser = webdriver.Chrome() browser.get(“https://example.com”) print(browser.title) browser.quit()
Practical setup notes:
- Use
quit()in teardown, not onlyclose(), becauseclose()can leave the driver process around. - Prefer explicit browser options in CI, for example headless mode, fixed window size, and downloads disabled unless needed.
- Keep test data isolated. Browser automation becomes hard to debug when the app state depends on previously executed tests.
Selenium WebDriver commands: the core object model
Most Selenium examples revolve around the driver and web elements.
Common driver commands
get(url), navigate to a pagecurrent_url, read the current URLtitle, read the page titleback(),forward(),refresh()quit(), end the session
Example:
browser.get("https://example.com/login")
print(browser.current_url)
print(browser.title)
browser.refresh()
Finding elements
Use one locator strategy consistently, and prefer the one that reflects user-facing behavior.
Typical locators:
By.IDBy.NAMEBy.CSS_SELECTORBy.XPATHBy.CLASS_NAMEBy.TAG_NAMEBy.LINK_TEXTBy.PARTIAL_LINK_TEXT
Example:
from selenium.webdriver.common.by import By
username = browser.find_element(By.ID, “username”) password = browser.find_element(By.NAME, “password”) submit = browser.find_element(By.CSS_SELECTOR, “button[type=’submit’]”)
Practical guidance:
- Prefer IDs when they are stable and intentionally exposed for automation.
- Prefer CSS selectors over XPath when you only need structural selection.
- Use XPath when you need relationships, text matching, or complex traversal, but avoid fragile expressions that depend on page layout details.
- Avoid locating by visible text if that text changes frequently due to localization or A/B tests.
The most maintainable locator is usually the one tied to a stable product contract, not to presentation details that frontend refactors are likely to change.
Selenium examples for common element actions
Once you have a web element, typical interactions are straightforward.
python username.send_keys(“alice”) password.send_keys(“correct horse battery staple”) submit.click()
Useful methods:
click()send_keys()clear()textget_attribute(name)is_displayed()is_enabled()is_selected()
Example with attribute checks:
checkbox = browser.find_element(By.CSS_SELECTOR, "input[type='checkbox']")
if not checkbox.is_selected():
checkbox.click()
value = checkbox.get_attribute(“value”)
Common failure modes:
- the element is present but not interactable because it is offscreen, covered, or disabled
- the element exists in the DOM before it is visually ready
- the test targets a stale element after a rerender
- the click hits a different layer due to overlays or animations
When that happens, the fix is often not another sleep, but a better wait condition or a more robust locator.
Selenium waits: the part that prevents most flake
Waits are one of the most important parts of a Selenium cheatsheet because most browser test failures are timing problems disguised as element problems.
Implicit wait
An implicit wait tells WebDriver to poll for element lookup failures for a period of time.
browser.implicitly_wait(10)
Use it sparingly. Implicit waits apply broadly and can obscure where timing issues originate. Many teams prefer explicit waits instead, because they can define the exact condition being waited for.
Explicit wait
Explicit waits are usually the better default.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(browser, 10) login_button = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, “button[type=’submit’]”)) ) login_button.click()
Useful expected conditions include:
presence_of_element_locatedvisibility_of_element_locatedelement_to_be_clickabletext_to_be_present_in_elementurl_containstitle_containsalert_is_present
What to wait for
Wait for the app state that actually matters:
- a spinner disappears
- a toast appears
- the URL changes
- a result list contains at least one item
- a button becomes clickable
Do not wait for arbitrary time unless there is no reliable signal. Fixed sleeps are the easiest way to make a suite slow and flaky at the same time.
A common explicit wait pattern
python wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, “.loading-spinner”))) wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, “.success-banner”)))
Selenium assertions: keep them close to the user outcome
Assertions are often more important than actions. Good assertions verify something the user can observe or something the application contract depends on.
Basic assertion examples
assert "Dashboard" in browser.title
assert browser.current_url.endswith("/dashboard")
heading = browser.find_element(By.CSS_SELECTOR, “h1”) assert heading.text == “Dashboard”
Practical assertion checklist
- verify navigation by URL or page title when that is meaningful
- verify visible text on critical user paths
- verify state changes, such as a selected checkbox or an enabled button
- verify error messages for negative paths
- verify one or two key attributes, not every attribute on the page
Avoid over-asserting
A fragile test suite often checks too much detail. For example, asserting exact CSS classes, full markup structure, or the precise order of every element can create failures that do not represent user-visible regressions.
A better pattern is to assert the contract that matters:
banner = browser.find_element(By.CSS_SELECTOR, ".flash-success")
assert banner.is_displayed()
assert "saved" in banner.text.lower()
Windows and tabs
Modern applications often open new tabs for auth flows, documentation, or downloads. Selenium can switch between windows using window handles.
original = browser.current_window_handle
browser.find_element(By.LINK_TEXT, "Open help").click()
for handle in browser.window_handles: if handle != original: browser.switch_to.window(handle) break
assert “Help” in browser.title browser.close() browser.switch_to.window(original)
Practical notes:
- always record the original window handle before opening a new one
- close the temporary window if the test no longer needs it
- do not assume a new tab is always the second handle, because ordering can differ across browsers or providers
Frames and iframes
Frames are a frequent source of confusion because Selenium commands target the active browsing context.
browser.switch_to.frame("payment-frame")
card_number = browser.find_element(By.ID, "card-number")
card_number.send_keys("4111111111111111")
browser.switch_to.default_content()
You can also switch by web element:
frame = browser.find_element(By.CSS_SELECTOR, "iframe[data-test='checkout']")
browser.switch_to.frame(frame)
Common frame mistakes:
- trying to locate frame content before switching into the frame
- forgetting to switch back to
default_content() - assuming nested frames behave like a single context
If a page suddenly looks empty to Selenium but not to a human, check whether the target lives inside an iframe.
Screenshots and visual debugging
Screenshots are valuable because they capture the page state at the point of failure.
browser.save_screenshot("artifacts/login-failure.png")
Useful practices:
- save screenshots on failure, not only on success
- name files with test and timestamp information
- pair screenshots with page source or console logs when possible
You can also capture the DOM source:
with open("artifacts/page.html", "w", encoding="utf-8") as f:
f.write(browser.page_source)
For teams that need stronger visual validation, Visual AI is one of the alternatives to consider. It is relevant when the question is not only “did the button exist,” but “did the UI render the way a human would judge it,” which is a different kind of assertion than Selenium usually provides out of the box.
Debugging commands and signals that save time
A useful Selenium cheatsheet should include the debugging primitives that help isolate failures.
Inspect state quickly
print(browser.current_url)
print(browser.title)
print(browser.page_source[:1000])
Check element state before interacting
el = browser.find_element(By.CSS_SELECTOR, "button[type='submit']")
print(el.is_displayed(), el.is_enabled(), el.text)
Use structured logs in the test
python print(“Waiting for dashboard banner”) wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, “.dashboard-banner”))) print(“Dashboard banner visible”)
When a click fails
Typical causes:
- the element is hidden behind an overlay
- the element is disabled until async work finishes
- a stale reference was reused after DOM replacement
- the locator matched the wrong element
Debugging strategy:
- confirm the locator matches the intended element
- check visibility and enabled state
- wait for overlays or loaders to disappear
- reacquire the element after DOM updates
If a test fails intermittently on click, treat it as a synchronization problem first, not as a Selenium problem.
Example: a compact login flow
This is the kind of test many teams use as a baseline for application smoke coverage.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome() wait = WebDriverWait(browser, 10)
try: browser.get(“https://example.com/login”) browser.find_element(By.ID, “username”).send_keys(“alice”) browser.find_element(By.ID, “password”).send_keys(“secret”) browser.find_element(By.CSS_SELECTOR, “button[type=’submit’]”).click()
wait.until(EC.url_contains("/dashboard"))
assert "Dashboard" in browser.title finally:
browser.quit()
A few details matter here:
tryandfinallyensure cleanup even when the assertion fails- the explicit wait watches for a state change after submit
- the assertion validates the user-facing result, not just that the click happened
Selenium versus higher-level test platforms
Selenium is strongest when your team wants control, extensibility, and direct coding access. It is less attractive when most of the engineering cost is not in writing assertions, but in maintaining the scaffolding around them.
That maintenance burden usually shows up in a few places:
- flaky locator repairs
- browser grid configuration
- artifact collection and failure triage
- test authoring standards across teams
- platform integrations for reports and reruns
For teams that want browser automation plus built-in reports, cloud execution, and maintenance workflows, an agentic AI platform such as Endtest can be a practical alternative. Its migrating from Selenium documentation is relevant if a team is evaluating whether to keep a code-heavy framework or move toward editable platform steps. Endtest also positions AI Assertions for cases where classic element-by-element assertions become overly brittle, because the check can be expressed in plain language and scoped to the page, cookies, variables, or logs.
That does not make Selenium obsolete. It means the decision should be based on where the real cost lies:
- if your team needs fine-grained code control, Selenium is a strong fit
- if your team is paying more for framework upkeep than for test logic, a maintained platform can be worth evaluating
Common selection criteria for teams
When deciding whether Selenium is the right baseline, use criteria that map to real operating cost.
Choose Selenium when
- the engineering team wants code-first tests in its primary language
- tests need deep integration with app code or custom fixtures
- your organization already has runner, reporting, and infra patterns in place
- you need portability across multiple browsers and environments
Reconsider Selenium when
- most failures come from locator drift and environment setup
- test ownership is spread across multiple teams with uneven coding depth
- your suite needs a lot of maintenance work that does not directly test product behavior
- the team spends too much time rebuilding tooling that other platforms already provide
Minimal reference list
Browser navigation
browser.get("https://example.com")
browser.back()
browser.forward()
browser.refresh()
Locate elements
browser.find_element(By.ID, "search")
browser.find_elements(By.CSS_SELECTOR, ".result")
Interact
python el.click() el.send_keys(“text”) el.clear()
Wait
python wait.until(EC.visibility_of_element_located((By.ID, “status”)))
Assert
assert "Done" in browser.find_element(By.ID, "status").text
Switch context
browser.switch_to.window(handle)
browser.switch_to.frame(frame_element)
browser.switch_to.default_content()
Capture artifacts
browser.save_screenshot("artifact.png")
Final practical notes
A good Selenium suite is usually less about clever code and more about discipline:
- use stable locators
- wait for the right condition
- assert outcomes that matter to users
- isolate test state
- collect artifacts when things fail
- keep browser automation infrastructure simple enough to operate
If your organization wants that level of control, Selenium remains a dependable choice. If the surrounding work is becoming the main product of the test effort, not the tests themselves, it is reasonable to compare it with alternatives that bundle maintenance workflows, cloud execution, and reporting into the platform.
For a deeper comparison, see the Endtest vs Selenium overview and the broader browser testing pages on this site.