Cloud Grid Execution
Introduction
Section titled “Introduction”What is Cloud Grid Execution?
Section titled “What is Cloud Grid Execution?”Cloud Grid Execution lets you take the test suite you already run locally and execute it on a hosted browser fleet — BrowserStack, LambdaTest, or Sauce Labs — by clicking one button in the Runner. Testver handles everything the vendor normally makes you wire by hand: credentials, hub/CDP endpoints, config files, build naming, SDK agents, artifact collection, and — critically — proof that the run actually executed on the cloud.
Who this guide is for
Section titled “Who this guide is for”- QA engineers who need cross-browser coverage without maintaining grid config in every project.
- Teams migrating an existing local suite (Selenium, Playwright, Cypress — any language) to cloud execution.
- Anyone burned before by a “cloud” run that silently executed on a local browser — Testver’s verdict system makes that impossible to miss.
Key terms (glossary)
Section titled “Key terms (glossary)”| Term | What it means here |
|---|---|
| Cloud provider / grid | The hosted browser fleet: BrowserStack, LambdaTest, or Sauce Labs. Enabled in Connectors. |
| Zero-touch | A cloud run that needs no changes to your project at all — Testver attaches a vendor SDK or injects environment variables at run time. |
| Cloud-aware / cloud-ready | A project whose driver setup honors Testver’s cloud environment variables, so selecting a provider is enough. |
| AI Assistant fix | For stacks with no zero-touch path: a one-click handoff that has the AI Assistant make the smallest code change, run one verification test on the cloud, and confirm success from the ground-truth verdict. |
SELENIUM_REMOTE_URL | The WebDriver hub URL Testver injects at run time (credentials embedded). Selenium-family projects read this to create a RemoteWebDriver. |
CLOUD_CDP_URL | A complete, ready-to-connect websocket URL (capabilities and credentials embedded) Testver injects for Playwright/Puppeteer projects — connect to it verbatim. |
| Cloud execution verdict | Ground truth stamped on every cloud-selected run: whether a real cloud session was observed. A run that silently lands local gets a loud amber banner in Results. |
| Build name | The label grouping the run’s sessions in the vendor dashboard. Auto-generated per run unless you set one. |
| SDK agent | A vendor-provided runtime component (e.g. BrowserStack’s Java agent) that redirects browser creation to the cloud without touching your source. Testver fetches and attaches it automatically. |
| Session capture | Testver reading the page through the test’s own cloud browser session — the evidence that powers Auto-Heal on cloud failures. |
Setup: connect a provider
Section titled “Setup: connect a provider”- Open Connectors and enable your provider (BrowserStack / LambdaTest / Sauce Labs) with its username and access key.
- That’s it for setup. The provider now appears in the Runner’s Run on: row, in suites, schedules, and CI pipeline mappings.
Credentials never enter your project files as permanent secrets — Testver injects them per run (environment variables or a generated config file that is rewritten on every run).
How a cloud run works, end to end
Section titled “How a cloud run works, end to end”When you press Run with a cloud provider selected, Testver:
- Analyzes the project (a fast code scan, re-checked on every run — no stale cached verdicts) to decide the connection path: zero-touch, already cloud-aware, or needs the AI Assistant fix.
- Prepares the run: injects provider env vars (
SELENIUM_REMOTE_URL,CLOUD_CDP_URL, credentials, build name), generates the vendor config file where needed (e.g.browserstack.yml), attaches SDK agents for zero-touch stacks, and wraps the command where the vendor uses a CLI (browserstack-sdk,saucectl,lambdatest-cypress). - Executes your unchanged command and streams output live, exactly like a local run.
- Watches for cloud sessions as they are created — through its capability proxy, hub relay, or the SDK’s own session journal — feeding both the verdict and Auto-Heal’s session capture.
- After the run: marks the vendor build complete, fetches artifacts (sessions, video, logs, dashboard links) into the Results page, and finalizes the cloud execution verdict.
Connection paths by stack
Section titled “Connection paths by stack”The path Testver chooses depends on your framework, language, and provider. You never pick it yourself — the analyzer does — but knowing the map helps you predict what happens.
Zero-touch (nothing in your project changes)
Section titled “Zero-touch (nothing in your project changes)”| Stack | BrowserStack | LambdaTest | Sauce Labs | How |
|---|---|---|---|---|
| Selenium Java (TestNG / JUnit / Cucumber-JVM) | ✅ | — | — | BrowserStack’s JVM agent, fetched once via your own Maven and attached with JAVA_TOOL_OPTIONS. new ChromeDriver() becomes a cloud session. |
| Selenium Python (pytest / behave) and Robot Framework | ✅ | — | — | BrowserStack’s Python SDK, installed once via your own pip; Testver prepends browserstack-sdk to your command. |
| Selenium C# (NUnit / xUnit / SpecFlow) | ✅ | — | — | BrowserStack.TestAdapter NuGet package (one PackageReference added via your own dotnet CLI — the only zero-touch path that touches a project file, never source code). Plain dotnet test then runs on the cloud. |
| Playwright JS/TS | ✅ | — | ✅ | Command wrap: browserstack-node-sdk / saucectl. |
| Cypress | ✅ | ✅ | ✅ | Vendor CLIs (browserstack-cypress-cli, lambdatest-cypress, saucectl). |
Selenium selenium-webdriver (JS) | ✅ | ✅ | ✅ | The JS Builder honors SELENIUM_REMOTE_URL natively — env injection is enough. |
| WebdriverIO | ✅ | ✅ | ✅ | Config reads user/key/hostname from env vars Testver injects. (Only a hardcoded-localhost config needs the AI fix.) |
| Mobile (Appium, any language) | ✅ | ✅ | ✅ | The mobile cloud-bridge — app upload + capability injection, no code changes. See the mobile guides. |
One-time costs on a fresh machine (SDK download via your own Maven/pip/NuGet) happen automatically on the first cloud run and are cached after that. If a fetch fails (offline, proxy), Testver logs it plainly and falls back to the standard flow — never a silent wrong state.
AI Assistant fix (one-time, per project)
Section titled “AI Assistant fix (one-time, per project)”Stacks with no vendor zero-touch mechanism need the project’s driver setup to honor Testver’s cloud environment variables — a small, one-time code change. Testver does not edit your code silently; it hands the job to the AI Assistant, in front of you:
| Stack | BrowserStack | LambdaTest | Sauce Labs |
|---|---|---|---|
| Selenium Java | zero-touch | 🔧 AI fix | 🔧 AI fix |
| Selenium Python / Robot / behave | zero-touch | 🔧 AI fix | 🔧 AI fix |
| Selenium C# | zero-touch | 🔧 AI fix | 🔧 AI fix |
| Selenium Ruby | 🔧 AI fix | 🔧 AI fix | 🔧 AI fix |
| Playwright Java / Python / .NET | 🔧 AI fix | 🔧 AI fix | ❌ (Sauce has no Playwright CDP endpoint) |
| Playwright JS | zero-touch | 🔧 AI fix | zero-touch |
| Puppeteer | 🔧 AI fix | 🔧 AI fix | ❌ (not supported by Sauce) |
The contract the fix implements is deliberately tiny:
- Selenium-family: when
SELENIUM_REMOTE_URLis set, create aRemoteWebDriverpointed at it; when unset, behave exactly as today (local browser). - Playwright/Puppeteer-family: when
CLOUD_CDP_URLis set,connect()to it instead of launching. The URL is complete — capabilities and credentials already embedded — so the code uses it verbatim.
After the fix, the project is cloud-aware for every provider that speaks the same protocol, and the dialog never appears again (readiness is re-derived from the code on each run, so a revert is caught immediately).
The “Not connected yet” dialog
Section titled “The “Not connected yet” dialog”When a cloud run is requested on a project that isn’t cloud-aware and has no zero-touch path, a dialog appears instead of the run:
- Detection Summary — the detected framework, language, and the driver file a heuristic scan points at. The file is labeled a guess: the AI Assistant verifies it (and looks for other driver-creation sites) before touching anything.
- Fix with AI Assistant — the primary action. It makes no changes and no AI calls from the dialog; it navigates to the AI Assistance screen with a complete work order pre-filled: what was detected, the exact env contract, your own run command (so verification reuses your scope), and the verification rules.
- Run Anyway — runs as-is with the cloud env vars injected. If your code already reads them, this just works; if not, the run lands locally and its result carries the “executed locally” warning.
- Cancel — nothing happens.
What the AI Assistant does with the work order
Section titled “What the AI Assistant does with the work order”- Reads the project, confirms where drivers are really created (the hint may be wrong — it checks), and makes the smallest change that satisfies the env contract.
- Compiles/sanity-checks where the language has a compile step.
- Runs one verification test on the chosen provider — through Testver’s runner, using a dedicated tool (it cannot and does not improvise with shell commands or APIs).
- Reads the run’s cloud execution verdict — ground truth, not test output — and self-corrects on failure, up to 3 attempts.
- Ends in one of exactly two states: verified on the cloud (with the build link), or every change reverted with a plain explanation of what blocked it.
You watch every edit and the verification run live in the AI Assistance screen. Requirements: an AI provider configured (Settings → AI Providers); each verification attempt uses a small amount of cloud minutes.
Copy-paste AI fix prompts
Section titled “Copy-paste AI fix prompts”The Fix with AI Assistant button assembles the prompt automatically from your project’s detections — normally you never write it. These copies exist as a fallback: if the pre-filled prompt was lost, edited by mistake, or produced a wrong result, paste the matching prompt into the AI Assistance screen yourself. Replace <provider> with browserstack, lambdatest, or saucelabs, and <your run command> with the command you normally run.
Selenium family — any language (Java, Python, C#, Ruby), Robot Framework, behave
Section titled “Selenium family — any language (Java, Python, C#, Ruby), Robot Framework, behave”Make this test project run on <provider> through Testver, WITHOUT changing how it behaves locally.
- Find where the WebDriver/browser is actually created (driver factories, base classes, fixtures, hooks) — verify it in the code, and fix every site that creates a local driver.- When the SELENIUM_REMOTE_URL environment variable is set, create a RemoteWebDriver (or this language's equivalent) pointed at that URL — Testver injects it at run time with credentials embedded.- When it is NOT set, behavior must stay exactly as today (local browser). Never hardcode credentials or vendor URLs.- Make the smallest possible edit. No restructuring.- My usual run command: <your run command>
Then verify your change yourself (required):1. Compile/sanity-check first if the language has a compile step.2. Run ONE quick test using the run_tests tool with cloud_provider: "<provider>" — reproduce my run command's scope through the tool's framework/files/args parameters. Do NOT use shell commands, the testver CLI, or Testver's HTTP API to start or inspect runs.3. The tool's result includes the run's CLOUD EXECUTION VERDICT — trust it over any test output. observed=true means the run REALLY executed on the cloud; observed=false with final=true means it silently ran locally and the change did not take effect.4. On failure, use that evidence, adjust, and retry — 3 attempts maximum.5. If it still fails after 3 attempts, restore every file you modified to its original state and explain exactly what blocked you.
Report at the end: the files you changed, the verify run's cloudExecution verdict,and the cloud build link if available.Playwright family — Java, Python, .NET, or JS on a provider without a zero-touch wrap
Section titled “Playwright family — Java, Python, .NET, or JS on a provider without a zero-touch wrap”Make this test project run on <provider> through Testver, WITHOUT changing how it behaves locally.
- Find where the Playwright browser is actually launched (base classes, fixtures, hooks) — verify it in the code, and fix every site that launches a local browser.- When the CLOUD_CDP_URL environment variable is set, CONNECT the browser to it (browserType.connect / playwright.chromium().connect) instead of launching locally. It is a COMPLETE websocket URL with capabilities and credentials already embedded — use it verbatim; never build capabilities, query strings, or vendor URLs yourself.- Ignore SELENIUM_REMOTE_URL entirely: it is a WebDriver endpoint and Playwright cannot speak to it.- Under the same cloud condition, disable Playwright's own video recording (video: 'off') — the vendor records video platform-side, and Playwright's recorder needs ffmpeg on the REMOTE browser host, where it fails.- When CLOUD_CDP_URL is NOT set, behavior must stay exactly as today (local launch).- Make the smallest possible edit. No restructuring.- My usual run command: <your run command>
Then verify your change yourself (required):1. Compile/sanity-check first if the language has a compile step.2. Run ONE quick test using the run_tests tool with cloud_provider: "<provider>" — reproduce my run command's scope through the tool's framework/files/args parameters. Do NOT use shell commands, the testver CLI, or Testver's HTTP API to start or inspect runs.3. The tool's result includes the run's CLOUD EXECUTION VERDICT — trust it over any test output. observed=true means the run REALLY executed on the cloud; observed=false with final=true means it silently ran locally and the change did not take effect.4. On failure, use that evidence, adjust, and retry — 3 attempts maximum.5. If it still fails after 3 attempts, restore every file you modified to its original state and explain exactly what blocked you.
Report at the end: the files you changed, the verify run's cloudExecution verdict,and the cloud build link if available.Puppeteer — BrowserStack or LambdaTest
Section titled “Puppeteer — BrowserStack or LambdaTest”Use the Playwright prompt above with one change: replace the connect instruction’s first bullet pair with:
- When the CLOUD_CDP_URL environment variable is set, connect via puppeteer.connect with a browserWSEndpoint derived from it. CLOUD_CDP_URL targets the vendor's PLAYWRIGHT endpoint — adapt the endpoint path to the vendor's Puppeteer endpoint (BrowserStack: wss://cdp.browserstack.com/puppeteer, LambdaTest: wss://cdp.lambdatest.com/puppeteer) while KEEPING the capabilities/credentials query string from CLOUD_CDP_URL unchanged.The cloud execution verdict
Section titled “The cloud execution verdict”Every run that selected a cloud provider gets a verdict answering one question: did it actually execute there?
- Observed — Testver saw real cloud sessions being created (or the vendor’s build records confirm them). The Results page shows the sessions, video, and build link as usual.
- Executed locally — no cloud session was observed and the provider has no build for the run. The run detail shows a loud amber banner: the project’s driver setup is not cloud-connected. No green result can mask this — test output cannot fake the verdict.
While the post-run check against the vendor’s records is still in flight, the banner area shows a quiet “verifying cloud execution…” state.
Results, artifacts, and Auto-Heal on cloud runs
Section titled “Results, artifacts, and Auto-Heal on cloud runs”- Cloud Session card — each session with browser/OS, status, duration, video, logs, and a deep link into the vendor dashboard; plus a View Build link.
- Build status — Testver marks the vendor build passed/failed via the vendor API after every run, so dashboards stay truthful without any status-reporting code in your project.
- Auto-Heal works on cloud failures — Testver captures the page through the test’s own cloud session (via its proxies, or the SDK’s session journal for agent runs), so a broken locator that fails on BrowserStack can be healed with the same evidence quality as a local run. See Auto-Heal.
Cloud runs beyond the Runner
Section titled “Cloud runs beyond the Runner”- Suites and Test Plan cycles can target a cloud provider the same way.
- Schedules run on the provider configured for the schedule.
- CI pipelines (delegated execution) dispatch through the same runner — the verdict and artifacts appear in CI Runs like any other run.
- A cloud run triggered on a project that isn’t cloud-aware doesn’t have a dialog in headless contexts — it runs env-only and, if it lands local, the verdict marks it. Fix it once from the Runner and every trigger path benefits.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Meaning | Fix |
|---|---|---|
| Amber “Cloud run executed locally” banner | The driver setup isn’t cloud-connected — the run never reached the grid. | Run again from the Runner and use Fix with AI Assistant. |
| Dialog appears again after a successful fix | The cloud-aware code was reverted or removed — readiness is re-checked from the code every run. | Re-apply (the AI fix or your own edit). |
| ”Could not fetch/install the … SDK” in the server log | The one-time SDK download failed (offline, proxy, missing toolchain). | Check network/proxy; the run fell back to the standard flow, nothing is wedged. |
| Cloud run works but no artifacts/build link | The vendor build lookup can lag a few seconds; it retries. If the build name was reused across runs, links may point at the merged build. | Leave Build: blank for auto-generated unique names. |
Playwright project told to use SELENIUM_REMOTE_URL by an old guide | Outdated — Playwright/Puppeteer projects use CLOUD_CDP_URL (a complete websocket URL). | Connect to CLOUD_CDP_URL verbatim. |
| Playwright cloud run fails with “Executable doesn’t exist … ffmpeg” | Your config records video (video: 'retain-on-failure' etc.) — with connectOptions the recorder runs on the vendor’s machine, which lacks Playwright’s ffmpeg. The vendor records video on its side anyway. | Set video: 'off' under the same CLOUD_CDP_URL condition as connectOptions. |
Does Testver modify my project for cloud runs?
Zero-touch paths: no source changes ever (the .NET path adds one NuGet PackageReference; config files like browserstack.yml are Testver-generated and rewritten per run). AI Assistant fix: yes, one small reviewed change — made in front of you, verified on the cloud, and fully reverted if verification fails.
Which stacks need nothing at all? See the zero-touch table above — most notably all of BrowserStack’s Java/Python/.NET Selenium paths, Playwright JS, Cypress everywhere, and all mobile Appium runs.
Do cloud runs consume my vendor minutes? Yes — including the AI fix’s verification runs (bounded to one small test per attempt, 3 attempts max) and Auto-Heal’s verification re-runs if enabled.
Can I keep running locally after connecting? Always. The env contract is explicit: cloud only when Testver injects the variables; your local behavior is untouched.