ScreenshotNeo

BlogGuides

WebdriverIO Tutorial: Selenium Testing Examples

Set up WebdriverIO, write and run a Selenium WebDriver browser test, and learn how capabilities, drivers, and remote execution fit together.

By the ScreenshotNeo team4 October 20267 min read

WebdriverIO is a JavaScript automation framework with a test runner and WebDriver protocol bindings. Selenium WebDriver is the browser automation API and protocol, with browser-specific drivers and language bindings. They work together: WebdriverIO can run and organize tests that control browsers through WebDriver.

This tutorial takes you from a clean Node.js project to a running browser test. The examples use WebdriverIO’s v9-era setup guidance and Mocha. You need Node.js 18.20.0 or newer; WebdriverIO officially supports Node releases that are or will become LTS. Its browser commands are asynchronous, so use await consistently.

1. Install WebdriverIO

In a new project directory, start the official setup wizard:

npm init wdio@latest .

The wizard asks how to configure the test suite, including its framework, browser, and project structure. Choose options that fit your project. To accept the documented defaults noninteractively, use:

npm init wdio@latest . -- --yes

The documented default uses Mocha, Chrome, and the Page Object pattern. Other package managers have equivalent commands:

yarn create wdio .
pnpm create wdio .
bun create wdio .

Check the generated files before adopting the defaults in an existing project. The setup wizard configures the runner and dependencies; it does not mean every project should use the same browser, framework, or page-object structure.

2. Understand the runner and Selenium WebDriver

The WebdriverIO test runner manages spec files, browser sessions, concurrency, and integration with a test framework such as Mocha. WebdriverIO’s protocol bindings expose lower-level browser automation commands and can also be used from a plain Node.js script. WebdriverIO documents the distinction between its setup types.

Selenium WebDriver is the browser-native automation interface. It can control a browser locally or communicate through a Selenium server; each browser has a driver implementation. Selenium Grid lets tests run across machines and platforms. WebDriver is a W3C Recommendation. Read Selenium’s WebDriver overview and its overview of WebDriver, IDE, and Grid.

So “WebdriverIO versus Selenium” is often the wrong framing. WebdriverIO supplies JavaScript tooling and a runner; Selenium WebDriver describes the automation interface and ecosystem that WebdriverIO can use.

3. Write a browser test

The wizard creates a sample spec and configuration. Here is a compact Mocha-style example using WebdriverIO’s runner globals. Put it in a spec file included by the generated configuration, such as test/specs/example.e2e.js. This checks a page title and a visible heading, then lets the runner manage session teardown:

describe('Example page', () => {
  it('opens the page and finds its heading', async () => {
    await browser.url('https://webdriver.io/');

    await expect(browser).toHaveTitle(/WebdriverIO/);

    const heading = await $('h1');
    await expect(heading).toBeDisplayed();
  });
});

WebdriverIO commands such as browser.url, element queries, and assertions that interact with the page are asynchronous. Await them so each step completes before the next one begins. The exact assertion helpers available depend on the assertion library enabled in your generated setup; the wizard’s default configuration includes the matching WebdriverIO test integrations.

A standalone script with explicit session cleanup

For a script outside the test runner, use WebdriverIO’s remote binding. The session must be deleted even if navigation or an assertion fails; put cleanup in a finally block:

import { remote } from 'webdriverio';

const browser = await remote({
  capabilities: { browserName: 'chrome' },
});

try {
  await browser.url('https://webdriver.io/');
  const title = await browser.getTitle();
  console.log(title);

  const heading = await browser.$('h1');
  console.log(await heading.getText());

  await browser.saveScreenshot('./webdriverio.png');
} finally {
  await browser.deleteSession();
}

This is an ES module example. Use a project configured for ES modules, or adapt the import to the module system configured in your Node.js project. WebdriverIO’s getting-started guide includes a standalone lifecycle example.

4. Run the test

Run the generated suite from the project root:

npx wdio run ./wdio.conf.js

To run one spec file, pass --spec:

npx wdio run ./wdio.conf.js --spec test/specs/example.e2e.js

Use the spec path that matches your generated project. The runner reads the configuration, starts the required browser session, executes the selected test, and reports the result.

5. Configure browser capabilities and drivers

Capabilities describe the browser session requested from a local driver, Selenium server, or remote provider. At minimum, the example requests Chrome with browserName:

capabilities: [{
  browserName: 'chrome'
}]

Browser-specific settings can be supplied under namespaced capability keys such as goog:chromeOptions. Remote vendors can define their own options, such as bstack:options. A remote service may also require credentials in its connection configuration. Follow the current configuration instructions for the service you use; capability names and account setup are provider-specific. See WebdriverIO configuration.

Do not assume you must always download and wire up a driver manually. WebdriverIO documents automatic browser-driver setup from version 8.14 onward, including choosing a browser and optionally a browser version. Verify the behavior for your installed WebdriverIO version and chosen browser in the driver binaries documentation.

Need Typical configuration choice
First local test Request one installed browser with browserName; use the generated local setup.
Browser-specific flags Add the browser’s namespaced options, such as goog:chromeOptions.
Hosted remote browser Configure the provider endpoint, credentials, and its vendor capability options.
Several machines or platforms Use Selenium Grid or a hosted remote service and configure the target capabilities.

6. Local versus remote execution

A local browser is enough to learn the workflow and run a first test. Remote execution becomes useful when a suite needs multiple browser versions, operating systems, parallel machines, or a shared CI environment. Selenium Grid is designed to distribute WebDriver sessions across machines; hosted services provide their own browser environments and setup instructions.

Keep remote execution optional until you need the extra coverage or capacity. It adds network and service configuration, credentials, and another source of session failures. WebdriverIO’s configuration supports remote connection details and vendor capabilities, but check the current documentation of the provider you select rather than copying credentials or settings from an unrelated example.

7. Troubleshooting

Symptom Likely cause Fix
Setup or commands fail on an older Node.js release The documented current setup requires Node.js 18.20.0 or newer. Switch to a supported LTS release, then reinstall dependencies if needed.
A later step runs before navigation or a query finishes An asynchronous WebdriverIO command was not awaited. Mark the test or function async and add await to each browser interaction.
Browser session cannot start The requested browser is unavailable, the capability is misspelled, or the driver setup does not match the installed version. Check browserName, browser installation, WebdriverIO version, and the driver binaries guide. Avoid assuming manual driver setup is always required.
Remote session is rejected Endpoint, credentials, or provider-specific capabilities are missing or incorrect. Confirm the remote service’s current endpoint and required options; keep credentials in environment-based configuration rather than committing them.
A test times out waiting for an element The page did not reach the expected state, the selector is wrong, or the element is inside a delayed/embedded context. Check the URL and selector, wait for the specific element condition, and inspect the browser or provider logs.
Browser sessions remain open after a script error A standalone script skipped session deletion on an exceptional path. Wrap work in try/finally and call deleteSession() in the finally block. In runner tests, use runner lifecycle hooks for resources your test creates.
Runner does not find a spec The path passed to --spec differs from the generated test layout. Use a path relative to the project root and check the spec include pattern in wdio.conf.js.

8. Performance, reliability, and cost

For a dependable suite, keep tests focused, wait for observable page conditions instead of arbitrary long sleeps, and always close standalone sessions. Parallel execution can reduce elapsed time, but each worker needs its own usable browser session and remote capacity. A remote provider or Grid can add queueing and network latency, so start with a small worker count and increase it only when the environment supports it.

Browser automation itself does not prescribe a single price: local execution uses your own machine, while Grid infrastructure and hosted services have their own operating costs or plans. Review the current terms of any remote service before budgeting. Avoid hard-coding service credentials in source control.

Or skip the browser setup

If your goal is a screenshot rather than an interactive browser test, ScreenshotNeo provides a website screenshot API and MCP server. Its API takes one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. See the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners are accepted and removed before the capture, along with 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers identify the page verdict and billing status.
  • An MCP server gives AI agents tools for screenshots, page information, and PDF capture.
  • The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan.

Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card.

FAQ

How do I write Selenium tests with WebdriverIO?

Use WebdriverIO’s runner and commands in an async test. The runner manages specs and sessions, while WebDriver is the browser automation interface those commands use.

How do I install WebdriverIO?

From a project directory, run npm init wdio@latest . and answer the configuration wizard prompts. The current getting-started documentation targets WebdriverIO 9 and later.

How do I run a WebdriverIO test?

Run npx wdio run ./wdio.conf.js; add --spec path/to/file to target one spec.

Do I need to install ChromeDriver for WebdriverIO?

Not necessarily. WebdriverIO documents automatic browser-driver setup starting with version 8.14. Check the driver guide for your WebdriverIO version and browser.