Lesson 8 of 8 · DevOps for QA
Cloud Testing Platforms
How device and browser clouds work, when they are worth it, and how to connect Selenium RemoteWebDriver and Playwright to remote browsers securely and reliably.
intermediate 8 min read Updated
You will learn to
- Explain what browser and device clouds provide and when a team needs one
- Run Selenium tests on a remote grid or cloud with RemoteWebDriver and capabilities
- Describe how Playwright connects to remote browsers through a WebSocket endpoint
- Plan tunnels, credentials, parallelism and cost control for cloud runs
Prerequisites
- Selenium or Playwright basics
- GitHub Actions for Test Automation
- Docker for Testers
Your users run your product on a spread of browsers, operating systems and devices that no team can keep on desks. Cloud testing platforms rent you that spread: real or virtual browsers and devices, hosted and maintained by someone else, which your tests drive remotely over the network.
Well-known commercial providers include BrowserStack, Sauce Labs and LambdaTest, and there are others. Features, device catalogues and pricing change frequently and differ between plans, so this lesson stays generic: it covers the concepts and the standard protocols that all of them build on. Check each vendor’s current documentation for specifics.
What a cloud platform provides
- Browser coverage: many browser versions on Windows, macOS and Linux, including combinations you cannot run locally, such as Safari on macOS when your CI runs Linux.
- Real mobile devices: physical phones and tablets in a data centre, plus emulators and simulators.
- Parallel capacity: many sessions at once without you operating the machines.
- Debugging artefacts: video recordings, screenshots, console and network logs per session.
- Tunnels: a way for remote browsers to reach your private test environments.
- Live/manual sessions: interactive access to a device for exploratory testing and bug reproduction.
Do you need one?
| You probably need a cloud (or a device lab) when | You probably do not when |
|---|---|
| Your analytics show meaningful traffic on browsers or devices you cannot run in CI | Your users are overwhelmingly on evergreen Chromium, Firefox and WebKit engines |
| You ship native or hybrid mobile apps and need real-device coverage | Playwright’s bundled browsers and device emulation cover your risk |
| You must certify on specific OS and browser versions for customers | You can run a self-hosted grid with acceptable effort |
Base the decision on your own usage data and risk, not on the size of a vendor’s device list. A cloud adds network latency, a dependency on a third party and cost; it should buy coverage you actually need.
A common pattern: run the main suite locally or in CI on bundled browsers on every PR, and run a smaller, risk-focused cross-browser and real-device suite on the cloud nightly or before release. A pairwise generator helps pick a small set of browser, OS and device combinations that still covers every pair of values.
Selenium: RemoteWebDriver
Selenium was built for remote execution. The W3C WebDriver protocol is HTTP-based: your test sends commands to a server, which drives the browser. Locally, the driver talks to chromedriver on your machine; remotely, you point a RemoteWebDriver at a Selenium Grid or a cloud endpoint, which speaks the same protocol.
import java.net.URI;
import java.net.URL;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
public class RemoteDriverFactory {
public static WebDriver create() throws Exception {
ChromeOptions options = new ChromeOptions();
options.setBrowserVersion("latest");
options.setPlatformName("Windows 11");
// Vendor-specific settings live under a namespaced capability.
// The exact key and fields come from your provider's documentation.
Map<String, Object> vendorOptions = new HashMap<>();
vendorOptions.put("build", System.getenv().getOrDefault("BUILD_ID", "local"));
vendorOptions.put("name", "checkout smoke");
options.setCapability("vendor:options", vendorOptions);
URL gridUrl = URI.create(System.getenv("GRID_URL")).toURL();
RemoteWebDriver driver = new RemoteWebDriver(gridUrl, options);
driver.manage().timeouts().implicitlyWait(Duration.ZERO);
return driver;
}
}
Notes on the example:
- Standard capabilities (
browserName,browserVersion,platformName) are defined by the W3C spec and set through the browser’s options class. - Extension capabilities must contain a colon, such as
vendor:options. Each provider documents its own key and fields (for example build names, video settings and tunnel identifiers). Replace the placeholder with the documented one. - The grid URL and credentials come from environment variables. Many providers accept credentials embedded in the URL or as capabilities; either way, keep them in your CI secret store.
URI.create(...).toURL()avoids theURL(String)constructor, which is deprecated in recent Java versions.
The same code works against a self-hosted Selenium Grid (for example one started from the official selenium/standalone-chrome image or deployed to Kubernetes as covered in Kubernetes Fundamentals for QA). Only the URL and the vendor capability change. Keep the driver factory as the single place that knows where browsers come from, so tests stay unchanged when you switch.
Reporting results back
The remote server only sees WebDriver commands; it does not know whether your test assertions passed. Most providers offer a way to mark a session as passed or failed (often a REST call or a special script command) so their dashboard matches your test report. Without it, every session that completes looks “successful” in the vendor UI.
Playwright: connecting to remote browsers
Playwright does not use WebDriver. It talks to browsers over its own protocol, normally to browsers it launched locally. For remote execution it can connect to a browser server through a WebSocket endpoint:
import { chromium } from '@playwright/test';
const browser = await chromium.connect(process.env.PW_WS_ENDPOINT!);
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://staging.example.com');
await browser.close();
In Playwright Test, the same thing is configured once with connectOptions, and your tests keep using the usual page fixture:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
connectOptions: process.env.PW_WS_ENDPOINT
? { wsEndpoint: process.env.PW_WS_ENDPOINT }
: undefined,
},
});
Important constraints:
- Versions must be compatible. The remote browser server is a Playwright server of a particular version; the client in your project should match it. Mismatches produce connection errors. Providers that support Playwright document which versions they run.
connectvsconnectOverCDP.browserType.connectuses Playwright’s protocol and works across browser engines.chromium.connectOverCDPattaches to a Chromium browser over the Chrome DevTools Protocol; it is lower fidelity than the Playwright protocol and only for Chromium-based browsers.- Real devices are different. Playwright’s device emulation sets viewport, user agent and touch for its own browsers; it is not a real phone. Real-device testing generally means a provider’s mobile offering, often through Appium, as covered in Mobile Testing.
You can also self-host remote Playwright browsers by running a Playwright server inside the official Docker image. See the “Docker” and “remote connection” sections of the Playwright docs for the current command.
Reaching private environments: tunnels
Your staging environment is usually not on the public internet, but the cloud’s browsers are. Providers solve this with a tunnel: a small binary you run inside your network (or in the CI job) that opens an outbound, encrypted connection to the provider, so their browsers can reach your internal hosts through it.
Practical points:
- Start the tunnel before tests and wait until it reports ready; stop it in an always-run cleanup step.
- Give each CI run a unique tunnel identifier so parallel pipelines do not share tunnels.
- Treat the tunnel as a security boundary: it gives a third party’s machines a path into your network. Agree on it with your security team, and restrict which hosts it may reach.
Running cloud suites reliably and cheaply
- Respect your concurrency limit. Plans usually cap parallel sessions. Configure test workers to match, or sessions queue and time out.
- Expect more latency. Every command crosses the internet. Avoid chatty patterns (thousands of tiny
findElementcalls) and rely on condition-based waits, never fixed sleeps. - Name builds and sessions from CI variables so you can find the video for a failed test quickly.
- Do not hard-code device lists in many places; keep one configuration that the pipeline reads.
- Run cloud suites selectively. Use them for the coverage only they provide. Running the full suite on every combination for every PR is slow and expensive.
- Plan for provider outages. The suite should fail clearly (“could not create session”) rather than as a wall of confusing test failures.
Practice exercise
Your web app’s analytics show significant traffic from Safari on iOS and from an older Samsung Internet version. CI runs Playwright on Linux with Chromium, Firefox and WebKit. Product asks: “Do we need a device cloud?” Write a recommendation and outline how you would wire it in.
Show a model answer
Recommendation: yes, for a targeted suite. Playwright’s WebKit build on Linux is useful but is not Safari on a real iPhone, and Samsung Internet is not covered at all by bundled browsers. Both have enough traffic to justify real-browser coverage.
Plan:
- Keep the existing Playwright suite as the PR gate.
- Select 15 to 30 critical journeys (sign-in, search, checkout, account) for a cross-device suite.
- Run a time-boxed proof of concept with one or two providers: confirm they support our framework and the specific devices and browser versions, and measure session start time and stability.
- Wire it in as a nightly and pre-release job: start a uniquely named tunnel to staging, read credentials and the endpoint from CI secrets, set workers to the plan’s concurrency limit, name sessions after the CI build, mark sessions passed or failed, and stop the tunnel in cleanup.
- Keep the driver or connection setup in one place so tests do not change, and route failures to the owning team with links to the session video.
- Review after a quarter: how many real issues did it find, and is the device list still aligned with analytics?
Key takeaways
- Cloud platforms rent browser, OS and real-device coverage plus parallel capacity; buy them for coverage your data says you need.
- Selenium uses
RemoteWebDriverand W3C capabilities; vendor settings go in a namespaced extension capability from the provider’s docs. - Playwright connects to remote browser servers through a WebSocket endpoint (
connectOptions.wsEndpoint), and client and server versions must be compatible. - Tunnels let remote browsers reach private environments; treat them as a security boundary.
- Match workers to concurrency limits, name sessions after builds, and run cloud suites selectively.
- Use synthetic data only, since sessions are recorded and stored by the provider.
Key terms
Finished this lesson?
Progress is saved in this browser. No account needed.