Skip to content

Browser testing

Use this page to choose between Sel (Selenium) and Play (Playwright) and to write selectors that work on both.

Sel (Selenium)Play (Playwright)
BrowsersChrome (default), FirefoxChromium only
Docker modeYes (agent.selenium.docker=true)No
WaitingRetries failed actions until the timeoutWaits until the element is ready, and retries every error
Shadow DOM>>>, plus an automatic search of open shadow roots>>>; css= and text= pierce open shadow roots
IframesSearched automaticallySearched automatically
Choose it whenYou need Firefox or DockerChromium is enough

Both return the same Browser object, and browser.locator(...) returns the same Locator.

Only the first line changes.

local browser = Sel.start() -- or Play.start()
browser.navigate("https://example.com/login")
browser.locator("id=username").fill("tester")
browser.locator("role=button[name=\"Sign in\"]").click()
print(browser.locator("css=h1").text())
browser.close()

Pass true to start Firefox: Sel.start(true). Call browser.close() when you are done, or Sel.close() / Play.close() to close every browser the library opened.

A selector is a prefix and a value, such as id=username. Without a prefix it is XPath if it starts with /, ./ or (, and CSS otherwise.

SelectorExampleSeleniumPlaywright
xpath=xpath=//button[@type='submit']✓✓ (does not pierce shadow DOM)
css=css=form .primary✓✓
id=id=username✓✓
name=name=email✓✓
class=class=btn✓ one class✓ several classes
tag=tag=h1✓✓
linkText=linkText=Sign in✓ exact text✓ exact text
text=text=Save✓✓
role=role=button[name="Save"]✓✓
label=label=Email✓✓
placeholder=placeholder=Email✓✓
alt=alt=Logo✓✓
title=title=Help✓✓
testid=testid=save (or testId=)✓✓
Chain >>css=form >> css=input✓✓
Shadow DOM >>>css=my-app >>> css=button✓✓
Iframeno prefix needed✓✓
  • Text matching: unquoted text is a case-insensitive substring. Quoted text (text="Log in") is an exact match.
  • Chains: each step is a selector of its own and is searched inside the elements the previous step found. >>> is short for >> shadow >>.
  • Shadow DOM: only open shadow roots can be entered. On Selenium, elements inside a shadow root are clicked with JavaScript, which skips the visibility and overlay checks.
  • Iframes: you never switch frames. A selector not found in the main page is searched in every iframe, and the first match wins.

Every action is retried every 100 ms until it succeeds or the timeout passes. The timeout comes from the project settings (10000 ms for new projects). Change it for one browser with browser.setTimeOut(ms).

When an action still fails, the script stops with an error and saves a screenshot and the page source. Call browser.stopOnFailure(false) to continue instead. Use locator.wait() or locator.exists() to wait for a condition, not sleep.

Start a selector with ? (for example browser.locator("?Email")) to look it up in the project’s locators.yaml. The file maps the page and the action to a list of candidate selectors, and the first one that exists wins. See Projects.

  • Sel and Play: start and close browsers.
  • Browser: navigation, tabs, alerts, JavaScript.
  • Locator: all element actions.