AI Features in Cypress & Selenium
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Playwright ships its AI features as part of the tool: an MCP server, a command line for agents and test-writing agents (see Playwright MCP & CLI and Playwright Test Agents). Cypress and Selenium took different routes. Cypress built AI into the test runner and its cloud service: a command that turns English into Cypress commands, an assertion recommender in Studio, summaries in Cypress Cloud, and a set of tools that expose the running app and the recorded runs to an external coding agent. Selenium, which is a protocol implementation rather than a product with a cloud, published guidance: a documentation page that tells a coding agent how to write current Selenium code, and no AI features of its own. This page covers both, written against Cypress 16.2.0 and Selenium 4.51.0 (Playwright 1.64 is the baseline of the sibling pages) and checked on 25 October 2026 against the official documentation.
Everything that can run without a Cypress Cloud account was run against the
Bookshelf application: the cypress tap command line against
a real cypress open session (Chrome 155 on macOS), and a Selenium Python verification script with the BiDi console and error
handlers. cy.prompt, Studio AI, the Cloud summaries and the Cloud MCP server all need a Cypress Cloud account, which was not
available, so they are documented from the official pages and were not run; each section says so. No coding agent
(Claude Code or another) drove the runs described here: the commands were typed one at a time in the order an agent follows,
which is stated again where it matters. The general mechanics of agents that drive browsers are in
How AI Agents Drive Browsers; this page is about what the
two tools themselves provide.
Two meanings of "AI in a test tool"
Cypress’s own overview page splits its AI features into two halves, and the split is useful for Selenium too.
| Question | AI writes the test | The tool is made legible to an agent |
|---|---|---|
Who is the author? |
The tool turns plain language or recorded clicks into test code; you review it. |
Your coding agent writes the test; the tool gives it accurate context. |
What needs a network service? |
Usually a vendor cloud that calls a large language model for you. |
Often nothing: skills and local commands run on your machine. |
Cypress |
|
AI skills, |
Selenium |
Nothing official |
The "Using AI coding agents with Selenium" page and |
Playwright (for comparison) |
Test agents (planner, generator, healer), codegen |
Playwright MCP, Playwright CLI, |
Most teams use both halves. The first half is a convenience for authoring; the second half decides whether an agent that already writes your tests writes good ones, and that is where the effort pays off. The security consequences of connecting an agent to a browser or to your CI data are the subject of Securing Browser Agents and, for the underlying theory, of Excessive Agency and Tool Security.
Cypress
cy.prompt: natural-language steps
cy.prompt(steps, options) is a Cypress command that accepts an array of English strings, asks a model to interpret each
step, evaluates the page DOM to pick selectors, generates ordinary Cypress commands and runs them. It exists since Cypress
15.4.0. It is for end-to-end tests only (not component tests) and runs in Chromium-based browsers (Chrome and Edge).
interface PromptCommand {
(
steps: string[],
options?: {
// dynamic or sensitive inputs, ignored for cache identity and never sent to the model
placeholders?: { [key: string]: string }
}
): void
}
Source: cy.prompt() API reference
The command yields whatever the last generated Cypress command yielded, so cy.prompt([...]).closest('form') works when the
last step is a click. A spec written against Bookshelf looks like this. It combines a search, a placeholder for the term and a
placeholder for the expected text, so the step strings stay identical across iterations (see below). It is written from the
documentation and was not run, because cy.prompt needs a Cypress Cloud account.
describe('Catalogue search (cy.prompt)', () => {
const searches = [
{ term: 'quiet', expected: '1 book found' },
{ term: 'compiler', expected: '1 book found' },
]
searches.forEach(({ term, expected }) => {
it(`finds "${term}"`, () => {
cy.prompt(
[
'visit /books',
'type "{{term}}" in the search field',
'click the search button',
'verify the result count shows "{{expected}}"',
],
{ placeholders: { term, expected } },
)
})
})
})
Source: Generate tests with cy.prompt
{{term}} and {{expected}} are replaced when the step executes. Because the strings never change, the second iteration
reuses the code that the first one generated.
What a step can say
The command reference lists the supported verbs: navigate (visit, navigate to), click, double and right click, type,
write and fill, clear, focus and blur, select, check and uncheck, toggle, submit, scroll into view, keyboard (press "Tab"),
hover, assertions (verify, expect, make sure, should, ensure) with existence, visibility, text, value, class, state,
URL and count forms, viewport changes (set the viewport to 400x600), waits (wait 2 seconds, wait for @alias) and two
command options, force and timeout ('force click the submit button', 'go to "/users" with a timeout of 10 seconds').
The guidance for writing steps is short and reliable:
-
Start with an imperative verb and do one action per step. A step such as
click buttonis ambiguous;click the "Add review" button in the book panelis not. -
Quoted text resolves to
cy.contains(text)(the text is the identifier, so the test fails if the text changes). An unquoted description resolves tocy.get(selector)(the structure is the identifier, so a changed label does not matter). Choose the one that is more stable in your app. -
Use absolute URLs, or relative ones with
baseUrlset. -
Gherkin-style
Given/When/Then/Andsteps are accepted; no step-definition files are involved. -
If a step cannot be interpreted, the App shows a dialog asking for a more specific step and saves your wording into the spec.
Selectors, caching and self-healing
For each step Cypress picks a selector by priority rules; Cypress.ElementSelector.defaults({ selectorPriority: [...] }) in
the support file sets the order, which is how a project that uses data-testid makes the generated code use it (the default
priority already prefers data-cy, data-test, data-testid and data-qa before name, id, class, tag and nth-child).
The generated code is cached, and the cache is shared across machines and environments including CI, so a prompt that has been
resolved once does not call the model again until the step text or the DOM invalidates it.
Self-healing is that invalidation handled for you. If a cached selector no longer matches, Cypress regenerates the commands for that step on the next run and tags it in the Command Log. There are two flavours: self-healed via cache (the existing cache entry resolved to another element, no model call) and self-healed via AI (no cache entry matched, so the model was called). A self-heal is visible in the Command Log (test, prompt and step levels), in the Cloud runs list, run overview, run properties and Test Replay, and the DevTools console of the App prints the resolved element and the cached candidates. The documentation is explicit that self-healing is meant for occasional UI changes. A step whose target changes on every run (generated class names) heals on every run, which costs model calls and defeats the cache; point such a step at visible text, a placeholder or a different selector priority instead.
Workflows: generate once, or keep it running
The documentation describes two workflows, and they are a real design decision, not a detail:
| Workflow | What you commit | Trade-off |
|---|---|---|
Generate once, commit the code |
The plain Cypress commands copied out of the Command Log’s Code button (each command is preceded by a |
Predictable, reviewable, no model dependency at run time. You own the maintenance again, like any other test. |
Continuous self-healing |
The |
Less maintenance when the UI moves, but every cache miss is a model call, a Cloud dependency in CI, and a test whose code can change between runs. |
The Code button is available even for failing tests. For a whole run, the Cloud Properties tab has a cy.prompt section with a Download report action (JSON, YAML or Markdown) listing every prompt, grouped by spec and test, with the natural-language steps and the generated code, which is the practical way to audit AI-generated code across a CI build. Treating the generated commands as a pull-request diff that a person reviews is the safe default; a test that cannot be read in code review is a test nobody can trust or debug.
Placeholders and sensitive data
Placeholders have two jobs. They keep the step string constant so the cache stays valid (the example above), and they keep
values out of the model request: placeholder values are never sent to the AI. Read secrets with cy.env() and pass them
as placeholders; do not hardcode them in the step.
cy.env(['READER_PASSWORD']).then(({ readerPassword }) => {
cy.prompt(
[
'visit /signin',
'type "reader" in the username field',
'type {{password}} in the password field',
'click the sign in button',
],
{ placeholders: { password: readerPassword } },
)
})
This snippet was not run for the reason above. The password comes from the environment variable CYPRESS_READER_PASSWORD; in
Cypress 16 Cypress.env() is gone, so cy.env() and Cypress.expose() are the replacements (see
Cypress: Sessions, Authentication & Cross-Origin).
Separately, the DOM that is sent to the model has the values of password inputs, credit-card inputs with the standard
autocomplete attributes and hidden inputs removed; their structure still identifies them. A string you write into a step
('type "hunter2" in the password field') is part of your test code and is not protected, which is why placeholders exist.
Limits
The command reference lists these limitations, which matter more than the feature list:
-
Requirements: a Cypress Cloud account (logged in, or
--recordwith a valid--key); it is available on every plan including the free Starter plan. -
Scope: E2E only; Chromium-based browsers only; optimized for English (other languages are not guaranteed).
-
Not supported: canvas and iframe elements,
cy.request()and other API steps, clearing cookies or sessions, scrolling to elements as a goal, assertions on several elements at once, andnot.existassertions from a free-form description (they work when the step gives an exact CSS selector or quoted text, for example'verify #error-message does not exist'). -
Rates: the Cloud AI page lists 100 prompts and 500 steps per user per hour on the free plan and 600 and 3,000 on paid plans. cy.prompt executions are also metered per organization, with a grace period that the Cloud FAQ describes.
-
Governance: AI capabilities are on by default and organization owners and admins can turn them off in the organization settings. Prompts are not used to train models, according to the documentation.
Status: beta or generally available?
The two official pages disagree at the check date. The command’s API page still labels cy.prompt beta, with the history entries
"15.13.0 cy.prompt moves to beta" (the experimentalPromptCommand flag was removed) and "15.4.0 introduced"; the Cypress AI
page’s release-status table lists cy.prompt as Generally Available (and Studio AI recommendations, Cloud CLI and cypress tap
as Beta). This page treats it as generally available according to the Cloud AI features page and still labelled beta on the
command’s API page; check the release notes of the version you install.
Studio AI: assertion recommendations
Cypress Studio records your clicks, typing and selections into a spec (click, type, check, uncheck, select), and a
right-click adds manual assertions. Studio AI is the opt-in layer on top: as you record, it compares the DOM before and after
each interaction and recommends an assertion with a one-line comment about what it validates. The assertion code is inserted
immediately (collapsed), so you can save and run the test before deciding; each recommendation has Accept and Reject buttons,
Accept all and Reject all, and hovering shows the before and after DOM snapshots with the asserted element highlighted.
Recommended kinds are visibility, existence, text, length, form values and states, attributes (classes, ARIA) and URL and title.
The model sees only the visible UI changes; it has no access to application code or business rules.
Requirements and limits at the check date: Cypress 15.11.0 or later, a Cloud account and linked project for the recommendations (the recording itself needs neither), sourcemaps enabled, a trial of six accepted recommendations per browser session without logging in, 60 recommendations per hour on a free account and 300 on a paid one. Studio supports E2E only and cannot record across origins, in iframes or in Shadow DOM; recommendations are disabled while the test is failing and can be affected by animations or very large pages. Studio AI is labelled Beta and is included at no extra charge during the beta. It was not run here (no Cloud account). The Studio basics are in Cypress: Debugging, Studio, Plugins & Reporters.
Cypress Cloud AI: summaries and coverage tests
Three more AI capabilities live in Cypress Cloud rather than in the App, all enabled by default and none needing a paid plan except the last:
-
Test Intent Summaries: AI-generated descriptions of what a test checks, in the test details sidebar (Generally Available).
-
Error Summaries: plain-language explanations of what led to a failed attempt, next to the stack trace (Generally Available).
-
UI Coverage Test Generation: generates a test scaffold from a coverage gap found in code review; it comes with a UI Coverage subscription.
See Cypress Cloud for the product around them. These features were not exercised because no account was available.
Cloud MCP: run data for your agent
Cloud MCP is a remote Model Context Protocol server hosted by Cypress at https://mcp.cypress.io/mcp. It does not drive a
browser and cannot run or edit tests. It lets an agent read Cypress Cloud data: recorded runs, per-spec and per-test results,
failures with stack traces and Test Replay links, flaky tests, failure screenshots, and Accessibility and UI Coverage reports.
It reached general availability on 20 May 2026 and is included on every Cloud plan at no extra cost.
| Tool | What the agent gets |
|---|---|
|
The projects in the organization (to find a |
|
Run summaries for a project, run URL or branch, filterable by status: number, status, URL, tags, test counts, commit author, duration, CI build id. |
|
Per-spec results of a run (up to 25 per page) with durations. |
|
Per-test results at any status, including skipped and pending, with a Test Replay link. |
|
Attempt details, error, stack trace and Test Replay link for failures (no artifacts). |
|
The flaky tests of a run. |
|
Failure and |
|
Violation counts by severity, the worst views, and the failing elements for one rule (needs Cypress Accessibility). |
|
Coverage score, riskiest views and untested interactive elements (needs UI Coverage). |
|
Sends feedback to Cypress from the agent. |
Source: Cloud MCP
The access model matters for the threat model. An organization admin enables the integration; each user then authenticates with OAuth (recommended: the client opens a browser sign-in and the session lasts 30 days) or a personal access token generated in the profile page (shown once, with a chosen expiry). The server is read-only and user-scoped: it cannot modify test code or delete runs, and an agent sees only what the signed-in user may see. It uses the standard MCP authorization (OAuth 2.0) over streamable HTTP, and is limited to 100 tool requests per hour per user on every plan. Disabling the integration on the organization’s Integrations page revokes every user’s access immediately. For Claude Code the documented commands are below (documented, not run: no Cloud account was available); the other clients in the documentation (Claude Desktop, Cursor, VS Code, Copilot CLI, Codex, Antigravity) use the same URL.
# OAuth: Claude Code opens a browser window to sign in the first time
claude mcp add cypress-cloud https://mcp.cypress.io/mcp --transport http
# Personal access token instead, kept in an environment variable and not in the file
claude mcp add cypress-cloud https://mcp.cypress.io/mcp --transport http \
--header "Authorization: Bearer $CYPRESS_MCP_TOKEN"
Source: Cloud MCP, Claude Code (CLI)
The documentation’s example prompts are good templates: "Check Cypress Cloud for the latest run on this branch. Give me a
high-level summary of any failures." or "Find the failing tests for [Run URL]. For each failure, look at the stack trace and the
failure screenshot, check my local code, and propose a fix." Two practical points from its troubleshooting section: say "Cypress
Cloud" in the prompt so the agent chooses these tools, and point the agent at a run by branch, commit, run number or URL because a
red CI job still has a recorded run. For terminal-only agents the Cloud CLI (cy-cloud, package @cypress/cloud, JSON output,
Beta) is the scriptable counterpart and is covered in the Cypress Cloud page. How MCP servers, hosts and transports work in
general is explained in MCP Architecture and
Connecting MCP Hosts, and how to test them in
MCP Testing & Debugging.
AI skills: teaching an agent Cypress
The Cypress AI Toolkit (https://github.com/cypress-io/ai-toolkit, MIT licence) publishes five skills, which are instruction files that a coding agent loads when the task matches. They are free, need no Cloud account and have no usage limits.
| Skill | What it makes the agent do |
|---|---|
|
Create, update and fix E2E and component tests: reads the config, |
|
Explain and critique existing tests: intent, structure, hidden dependencies, brittle selectors, timing assumptions, missing assertions, misleading titles. |
|
Drive |
|
Triage recorded Cloud runs through |
|
Look things up in docs.cypress.io through its |
Source: Cypress AI Skills
Install them from the GitHub repository with the skills CLI or the GitHub CLI; the toolkit is also published as an agent plugin
(a Claude plugin marketplace entry and a Cursor plugin are described in its README). There is no npm package to install the
toolkit: do not look for one, and treat any package that claims to be a Cypress "AI toolkit" on a registry as unrelated.
# all five skills, into the project's agent configuration
npx skills add cypress-io/ai-toolkit
# one skill
npx skills add https://github.com/cypress-io/ai-toolkit --skill cypress-author
# update later (tracks project-level installs only)
npx skills update
# alternative with the GitHub CLI
gh skill install cypress-io/ai-toolkit
Source: Install Cypress AI Skills
These commands were not run (they modify an agent configuration, and no coding agent was used for this page). A skill is a prompt that you can read before you install it; do that, as for any third-party instruction file that will steer an agent with shell access (see Prompt Injection).
cypress tap: an agent on a live Cypress session
cypress tap (Cypress 15.21.0 or later, Beta, free, no Cloud account) is a subcommand of the cypress CLI that attaches to a
running cypress open session and exposes what the App shows: run a spec, read the reporter and Command Log, and inspect the
application-under-test as it was at a given command. An agent that can run shell commands (Claude Code, Cursor, Copilot, Codex and
others) can then verify its own test instead of reporting a bare pass or fail. It works only with open mode (not cypress run)
and only with Chromium-based browsers, including Electron. If the CLI and the session are on incompatible versions it stops and
says so.
| Command | What it does |
|---|---|
|
Lists the reachable |
|
The run stage: |
|
Lists runnable specs, most recently modified first. |
|
Requests a run of a project-relative spec path and returns immediately; launches a browser if none is open. |
|
Spec overview with test ids ( |
|
One Command Log entry: snapshots and the console properties DevTools would show. |
|
Shows a past command’s DOM snapshot as the live page so that |
|
HTML of the page or of one element (output capped at 30,000 characters by default). |
|
The accessibility tree (200 nodes by default). |
|
Tag, attributes, accessibility node, box model and a fixed subset of about two dozen computed styles. |
All commands accept --session <pid> (-s) when several sessions run, --json (what scripts and agents should prefer) and
--timeout <ms> (30,000 by default). Four rules from the documentation matter for any agent loop: only passed and failed are
verdicts; a finished run stays readable until the next one starts, so record startedAt before re-running and wait for a verdict
with a different startedAt; a spec that fails to build sits in loading forever, so the poller needs its own timeout; and
passed does not prove tests ran (an empty spec passes with zero results). Do not touch the Cypress window while an agent drives
it, because a pin is the same state the Command Log click changes.
The following transcript was recorded against Bookshelf (on its own port) with a cypress open --e2e --browser chrome session and
Cypress 16.2.0. The spec has one correct test and one that uses a stale locator on purpose, the situation an agent has to repair.
The commands were typed by hand in the order that the cypress-tap skill prescribes; no agent or skill was involved. The project
path is shortened to <workspace>.
$ npx cypress tap sessions
SESSIONS (1)
PID PROJECT TYPE BROWSER
54407 <workspace>/e2e/cy e2e —
$ npx cypress tap run cypress/e2e/catalogue.cy.ts
● cypress/e2e/catalogue.cy.ts is running
use tap status to check progress
$ npx cypress tap status --json
{
"status": "failed",
"browserAttached": true,
"browserName": "Chrome",
"spec": "cypress/e2e/catalogue.cy.ts",
"startedAt": "2026-10-25T21:54:49.418Z",
"totalTests": 2,
"results": { "passed": 1, "failed": 1, "pending": 0, "skipped": 0 }
}
$ npx cypress tap reporter
cypress/e2e/catalogue.cy.ts (started at 10:54:49 PM)
✓ 1 ✖ 1 ○ -- 00:02
Catalogue search
r3 ✓ finds a book by title 190ms
r4 ✖ shows the empty state (stale locator on purpose) 2s
Source: cypress tap
The first call to run started a Chrome window by itself (the session had no browser). The agent then asks for the failing test
and, with dom, aria and inspect, for what is really on the page:
$ npx cypress tap reporter --test-id r4
✖ Catalogue search > shows the empty state (stale locator on purpose) failed
TEST BODY · r4
1 visit /books
2 get [data-testid=search-box] ✖
✖ AssertionError
Timed out retrying after 2000ms: Expected to find element: `[data-testid=search-box]`, but never found it.
cypress/e2e/catalogue.cy.ts:10:8
> 10 | cy.get('[data-testid=search-box]', { timeout: 2000 }).type('zzz{enter}');
| ^
$ npx cypress tap aria --max-nodes 12
...
main
heading Catalogue
search
LabelText
searchbox Search books
$ npx cypress tap inspect --selector "[data-testid=search-input]"
ATTRIBUTES (5)
id q
name q
value
data-testid search-input
type search
ACCESSIBILITY
role searchbox
name Search books
$ npx cypress tap pin --test-id r4 --command-id 2
⚲ PINNED - (1/1)
$ npx cypress tap pin --test-id r4 --command-id 2 --clear
⚲ PIN CLEARED
The page answers the question the agent actually had: the element exists, with the test id search-input, not search-box. After
the locator was patched the same command sequence reported passed with ✓ 2 and a new startedAt. Compare this with the
equivalent loop of the Playwright healer in
Playwright Test Agents: both end in a failing test read from
structured evidence, a patch, and a re-run, but Cypress exposes it through a CLI attached to the open App rather than through MCP
tools. Cypress itself says cypress tap is the local counterpart to Cloud MCP and the Cloud CLI: tap gives the agent your machine
while you are writing the test; the others give it recorded CI runs afterwards.
Which Cypress feature for which job
| You want to… | Use | Needs |
|---|---|---|
Draft a flow quickly from a description |
|
Cloud account (any plan) |
Add assertions while recording |
Studio AI |
Cloud account, Cypress 15.11.0+ |
Keep an agent’s tests idiomatic |
AI skills ( |
Nothing |
Let an agent run and debug specs locally |
|
Cypress 15.21.0+, open mode, Chromium |
Let an agent investigate CI failures |
Cloud MCP, or Cloud CLI plus |
Cloud account, integration enabled |
Understand a suite you did not write |
|
Nothing / Cloud account |
Selenium
Official guidance: "Using AI coding agents with Selenium"
Selenium added a documentation page called Using AI coding agents with Selenium (the documentation tree has a top-level AI Agents entry; the page was added on 28 September 2026 and announced in a blog post of 29 September 2026). Its premise is an observation about training data: much of what models learned about Selenium describes Selenium 2 and 3, whose APIs were removed years ago, and the most repeated patterns (sleeping to wait, downloading driver binaries, XPath copied from DevTools) were never good practice. The page does not add a feature. It tells you what to give the agent and what to correct.
Give the agent the current documentation. In order: https://www.selenium.dev/llms.txt (a curated index following the
llmstxt.org convention, which deliberately leaves out the legacy Selenium 2 and 3 pages and the Chrome DevTools Protocol pages),
the documentation, the examples directory of the documentation repository (every code tab on the site links into code that is
compiled and executed against current releases), the API documentation of each binding, and the changelogs. The llms.txt file
also carries a short block of generation notes at the top: Selenium Manager resolves drivers, prefer explicit waits, BiDi is the
supported route for events and network, desired capabilities were removed. The page recommends a negative instruction as well: if
an API is not in the current documentation or API reference, it does not exist.
Write the project rules down. The page provides a block for AGENTS.md, CLAUDE.md or another rules file. This adapted
excerpt keeps the structure and sets the baseline of this page (the official template names the version of the day, 4.49.0 at
publication); replace the placeholders with your commands.
## Browser automation
This project uses Selenium 4.51.0.
### Docs
- Index: https://www.selenium.dev/llms.txt
- Reference: https://www.selenium.dev/documentation/
- Fetch the relevant page before using an API you are not certain about.
- If an API is not in the current documentation or API reference, it does not exist.
### Drivers and browsers
- Selenium Manager downloads and caches drivers. Do not add a driver-manager
dependency and do not set a path to a driver binary.
- Browser configuration goes in that browser's Options class. Do not use
DesiredCapabilities. Headless is a browser argument: `--headless=new`.
### Waiting
- Never sleep in a test. Use an explicit wait for the condition the next line needs.
- Do not mix implicit and explicit waits in the same session.
- When a test is flaky, find the condition that was not yet true. Do not raise a timeout.
### Locators and sessions
- Prefer `id` and `name`, then CSS on a stable attribute such as `data-testid`.
- No absolute XPath, no generated class names.
- One fresh session per test; always `quit` the driver in teardown.
### Events and network
- Use WebDriver BiDi for console logs, JavaScript errors and network interception.
Do not use the Chrome DevTools Protocol.
### Running tests
- A single test: <your command>
- If you are unsure whether a locator or a flow works, write a throwaway script
and run it against the application instead of guessing.
The page then lists, for Java, Python, C#, Ruby, JavaScript and Kotlin, the removals models get wrong most often. Python’s
list is representative: find_element_by_* helpers were removed in 4.3 (use find_element(By.ID, "...")); the
executable_path and desired_capabilities keyword arguments were removed in 4.10 (pass service= and options=);
options.headless = True was removed (use --headless=new); switch_to_alert() was removed (use switch_to.alert); and
webdriver-manager must not be installed. The long-form explanations are the part worth reading before you review agent
output: Selenium Manager (4.6 and later) finds the browser and the matching driver and, since 4.11, can download the browser;
DesiredCapabilities predates the W3C standard and unprefixed non-standard capabilities can fail a session; sleeping is the
main source of flakiness, and an agent that "fixes" an intermittent test by raising a timeout is hiding a race, not removing it;
Grid 4 is started with standalone, hub and node subcommands rather than the Grid 3 -role flags. The same facts appear in
this section’s sibling pages:
Selenium: Drivers, Browsers & Options,
Selenium Waits & Expected Conditions and
Selenium IDE, Legacy Components & Upgrading to Selenium 4.
Let the agent drive a real browser: throwaway scripts
The page’s recommended first step for browser access "needs nothing new": tell the agent it may write a throwaway Selenium script, run it and print what it finds. The script navigates, dumps candidate elements, tries a locator and reports back, and because it uses the same stack the real test will use, it cannot disagree with the test about what Selenium sees. This is the same observe-then-write loop that an MCP browser tool provides, with the advantage that no extra dependency enters the project. The script below is what such a verification looks like for the Bookshelf catalogue; it was run (Python 3.13, Selenium 4.51.0, headless Chrome 155, against the application on its own port), printing the evidence an agent needs before writing the test.
"""Throwaway verification script: check a locator against the running application.
Not part of the suite. Run it, read the output, then write the real test.
"""
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
BASE_URL = os.environ.get("BASE_URL", "http://localhost:3000")
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.enable_bidi = True # BiDi, not CDP, for console and error events
driver = webdriver.Chrome(options=options)
console, errors = [], []
driver.script.add_console_message_handler(console.append)
driver.script.add_javascript_error_handler(errors.append)
try:
driver.get(f"{BASE_URL}/books")
wait = WebDriverWait(driver, 10)
# 1. Which test ids exist on the page?
ids = sorted({e.get_attribute("data-testid") for e in driver.find_elements(By.CSS_SELECTOR, "[data-testid]")})
print("data-testid values:", ids)
# 2. Does the candidate locator work, and what does it match?
box = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='search-input']")))
box.send_keys("quiet")
driver.find_element(By.CSS_SELECTOR, "[data-testid='search-submit']").click()
wait.until(lambda d: len(d.find_elements(By.CSS_SELECTOR, "[data-testid='book-card']")) == 1)
print("result-count:", driver.find_element(By.CSS_SELECTOR, "[data-testid='result-count']").text)
print("titles:", [e.text for e in driver.find_elements(By.CSS_SELECTOR, "[data-testid='book-title']")])
# 3. Anything noisy in the browser while that happened?
print("console entries:", [(c.level, c.text) for c in console])
print("javascript errors:", [e.text for e in errors])
finally:
driver.quit()
Its output, unedited:
data-testid values: ['book-author', 'book-card', 'book-list', 'book-title', 'brand', 'main-nav', 'nav-signin', 'page-indicator', 'page-next', 'page-prev', 'pagination', 'result-count', 'search-input', 'search-submit', 'site-header', 'theme-toggle']
result-count: 1 book found
titles: ['The Quiet Compiler']
console entries: []
javascript errors: []
Source: WebDriver BiDi Logging Features
The script was written and run by hand here; the page describes the pattern, and an agent following the rules file above would
produce something similar. Note the explicit wait on the number of cards instead of a sleep, the data-testid locators and the
BiDi handlers (the console and JavaScript-error handlers need enable_bidi, which asks the driver for the webSocketUrl
capability). A script like this, which also checks for console and JavaScript errors, is a cheap guard against an agent
declaring a flow "working" while the page logs an exception.
No official MCP server
The Selenium project does not publish an MCP server. The guide says so in one sentence: there are community-maintained Model Context Protocol servers that expose Selenium as tools an agent can call (open a browser, click, type, take screenshots), they are third-party projects and are to be evaluated like any other dependency. That is a statement about trust, not about quality. Such a server executes browser commands on behalf of a model, so the questions to ask are those of Excessive Agency and Tool Security: who maintains it, what does it expose (arbitrary script evaluation? file access?), does it run in an isolated profile, and what happens when a page tries to steer the agent. If you want an MCP-driven browser with a project behind it, the maintained choices are Playwright MCP & CLI and Chrome DevTools for Agents; the throwaway script above often removes the need for any of them in a Selenium project.
BiDi as the standard surface
For anything an agent needs beyond clicking (console messages, JavaScript errors, network observation or interception, script
evaluation, screenshots of a browsing context), the Selenium documentation and llms.txt point at WebDriver BiDi, the W3C
standard (Working Draft of 8 October 2026) created by the Selenium project together with the browser vendors. It is the
cross-browser replacement for the Chrome DevTools Protocol, which the documentation now treats as a temporary measure, keeps out
of llms.txt, and tells agents not to use as a basis for new code. This is what makes Selenium’s agent story coherent: the
protocol that carries the agent’s debugging information is a standard that Chrome, Firefox and the other BiDi browsers implement
themselves, not a vendor-specific channel. The detail of the API, with Python and Java examples, is in
Selenium: WebDriver BiDi; the background of how it differs from classic
WebDriver and CDP is in How Browser Automation Works.
A workflow that works
The guide ends with a workflow that applies to any tool, and it is worth adopting almost verbatim:
-
Have the agent open the feature under test and propose locators, with a throwaway script or an MCP server. Review the locators before any test is written.
-
Let it write the test, following the rules file and fetching documentation pages as needed.
-
Have it run that one test, not the suite, and iterate until it passes.
-
Run the test several times. A test that passes once has not been shown to be free of races (see Flaky Tests & Reliability).
-
Review the diff for sleeps, driver paths and absolute XPath, which survive review most often because they work on the machine where they were written.
Handing the agent the real exception rather than "the test failed" is the other lever: Selenium’s exceptions are specific
(NoSuchElementException, StaleElementReferenceException, ElementClickInterceptedException, SessionNotCreatedException)
and the documentation has a page for each; a screenshot taken at the moment of failure usually explains an intercepted click
faster than the stack trace does.
Comparing the three
| Capability | Playwright | Cypress | Selenium |
|---|---|---|---|
Natural-language test generation in the tool |
Test agents (planner, generator, healer) and codegen; the model comes from your agent |
|
None |
Agent drives a browser through the tool |
Playwright MCP and CLI (official) |
Not offered by Cypress itself; |
Throwaway scripts; third-party MCP servers |
Agent reads recorded CI results |
Trace viewer and HTML report files |
Cloud MCP and Cloud CLI (read-only) |
Whatever your CI and Grid expose; no vendor service |
Instructions for coding agents |
Agent definition files written by |
AI skills in |
"Using AI coding agents with Selenium", |
Account or cloud needed |
No |
For |
No |
Standard protocol for agent debugging data |
Playwright’s own protocol |
Cypress runs inside the browser; DOM and Command Log via |
WebDriver BiDi |
In practice the choice of tool decides how much AI you get for free, but not how much you should trust it. All three produce code that must be reviewed like any other change, and all three leave the hard problems (stable test data, isolation, meaningful assertions) with you; see Test Design & Page Objects. For the question of how an agent should test a feature when no test is written at all, see Script-less Testing with AI Agents, and for the choice among the tools, Choosing a Tool.
Pitfalls and good practice
-
Treat generated code as a pull request. Export
cy.promptoutput, review recommended Studio assertions and review any agent-written Selenium test for sleeps and absolute XPath. A recommended assertion that merely mirrors what changed is not the same as one that protects a requirement. -
Do not leave
cy.promptin CI by accident. Continuous self-healing makes your pipeline depend on a hosted model, rate limits (per user and per organization) and a cache. Decide per spec whether it is the generate-once or the self-healing workflow. -
Keep secrets out of step strings. Use placeholders (and
cy.env()), not literals, incy.prompt; keep tokens for Cloud MCP in environment variables or the client’s secret store, and prefer OAuth so there is no long-lived token to leak. -
Read the skill before you install it. Skills, rules files and
AGENTS.mdsteer an agent that can run shell commands. They are instructions from a third party, with the same supply-chain considerations as a dependency. -
Poll for a fresh verdict with
cypress tap. A stalepassedfrom the previous run, a spec stuck inloadingand an empty spec that passes are the three ways an agent convinces itself a fix worked. -
Do not give an agent more than it needs. Cloud MCP is read-only for good reason; if you add write-capable servers beside it, the agent’s reach is the union of both. See Human-in-the-Loop and Testing & Debugging with AI.
-
Version-pin the guidance. The Selenium template names a version, the Cypress skills detect the installed version: keep both current, and regenerate when you upgrade (see What’s Changed and Upgrading).
What changed recently
-
Cypress 15.4.0:
cy.promptintroduced (experimental flag). 15.11.0: Studio AI requires this version or later. 15.13.0:cy.promptmoved to beta and theexperimentalPromptCommandflag was removed. 15.21.0:cypress tapavailable (Beta). -
Cypress 16.0.0 (1 September 2026):
Cypress.env()removed in favour ofcy.env()andCypress.expose(), which is the form the placeholder examples use; 16.2.0 (13 October 2026) is the version this page was checked against. -
20 May 2026: Cloud MCP generally available on all Cloud plans.
-
2026: the AI skills are published in the open-source
cypress-io/ai-toolkitrepository (five skills, an agent plugin and an MCP configuration, last updated 23 October 2026); the Cloud CLI andcypress tapare labelled Beta, Studio AI recommendations Beta,cy.prompt, Test Intent and Error Summaries, AI skills and Cloud MCP Generally Available on the Cloud AI page. -
Selenium, 28-29 September 2026: the "Using AI coding agents with Selenium" documentation page and an accompanying blog post;
llms.txton selenium.dev now lists it and states that the CDP integration is legacy and being removed. -
Selenium 4.51.0 (9 October 2026): current release at the check date; the BiDi code generator and further BiDi work continue while CDP support follows the Chrome versions (v153 to v155).
-
Moving target: the Cypress AI features are labelled Beta and GA in different pages, limits and plan placement are marked "subject to change", and the Selenium page is weeks old. Re-check release status, limits and URLs before relying on this page.