ScreenshotNeo

BlogHow-to

How to Run Selenium Automation Tests With Node.js

Install Selenium WebDriver, run a Node.js browser test with Mocha, and troubleshoot local or remote execution, browser drivers, and cleanup.

By the ScreenshotNeo team4 October 20267 min read

To run Selenium automation tests with Node.js, install a supported Node.js release and the selenium-webdriver npm package, then create a WebDriver session, interact with a browser asynchronously, assert the result, and always close the session. For a maintainable test suite, use Mocha hooks for setup and teardown; Selenium Manager handles routine driver management automatically, so downloading ChromeDriver is not the usual first step.

The Selenium JavaScript API currently requires Node.js 22 or newer. Its support table lists Node.js 22 support through 2027-04-30, Node.js 24 through 2028-04-30, and Node.js 26 through 2029-04-30. Check the current Selenium JavaScript API documentation when upgrading Node or Selenium.

1. Install Node.js and Selenium WebDriver

Install a Node.js version supported by the Selenium binding and make sure the browser you intend to automate is installed in the environment where the test will run. Then create a project and add Selenium:

mkdir selenium-node-tests
cd selenium-node-tests
npm init -y
npm install selenium-webdriver

The official package is selenium-webdriver. The examples below use CommonJS, which works with the default npm init project setup. If your project uses ECMAScript modules, adapt require() to import and configure the project accordingly.

2. Run a first browser script

This script starts Chrome, opens Selenium’s website, prints the page title, and closes the browser even if navigation or title retrieval fails:

const { Builder, Browser } = require('selenium-webdriver');

(async function main() {
  let driver;
  try {
    driver = await new Builder().forBrowser(Browser.CHROME).build();
    await driver.get('https://www.selenium.dev');
    console.log(await driver.getTitle());
  } finally {
    if (driver) await driver.quit();
  }
})();

Save it as first-test.js and run node first-test.js. WebDriver calls are asynchronous, so await navigation, element operations, and reads before using their results. The finally block prevents a successful run from leaving a browser session open. The guard also makes cleanup safe if session creation fails before driver is assigned.

3. Organize tests with Mocha

A direct script is useful for a quick check. A test runner becomes useful when you have multiple cases, shared browser setup, assertions, and teardown. Selenium’s JavaScript guide demonstrates Mocha. Install it as a development dependency:

npm install --save-dev mocha

Create runningTests.spec.js:

const { By, Builder, Browser } = require('selenium-webdriver');
const assert = require('node:assert/strict');

describe('Web form', function () {
  let driver;

  before(async function () {
    driver = await new Builder().forBrowser(Browser.CHROME).build();
  });

  it('submits text and shows the response', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/web-form.html');
    await driver.findElement(By.name('my-text')).sendKeys('Selenium');
    await driver.findElement(By.css('button')).click();
    assert.equal(
      await driver.findElement(By.id('message')).getText(),
      'Received!'
    );
  });

  after(async function () {
    if (driver) await driver.quit();
  });
});

Run the test with:

npx mocha runningTests.spec.js

before creates one browser session for this suite, it performs the interaction and checks the response, and after quits the session. For tests that change browser state independently, create a separate session per test or reset state between cases so one test’s cookies, navigation, or local storage do not affect another. Keep teardown guarded: a setup failure can leave driver undefined.

For a project with a test script, add this to package.json:

{
  "scripts": {
    "test": "mocha runningTests.spec.js"
  }
}

Then use npm test. For multiple spec files, Mocha can be invoked with a file glob supported by your shell, such as npx mocha "test/**/*.spec.js".

4. Understand browser drivers and Selenium Manager

WebDriver is the browser-control API and protocol. A browser-specific driver mediates communication between Selenium and the browser. Selenium Manager, included with Selenium releases since 4.6, is called by Selenium bindings to manage routine driver setup automatically. In a standard local setup, start with the binding and an installed browser rather than manually downloading a driver.

Manual driver paths and browser-specific services are advanced configuration options for environments that require a pinned driver, a nonstandard executable location, or custom service arguments. Selenium’s Chrome module documents Chrome options and driver service configuration in its Chrome API reference. Follow that reference for the installed Selenium version and environment. Do not assume Selenium Manager installs the browser itself; ensure the selected browser is available to the test environment.

5. Choose local or remote execution

Local execution is simplest when the browser runs on the same machine or CI worker as Node. A Selenium Grid or standalone server lets the script request a session from a remote WebDriver endpoint. The JavaScript API supports setting the endpoint in the Builder:

const { Builder, Browser } = require('selenium-webdriver');

(async function main() {
  let driver;
  try {
    driver = await new Builder()
      .forBrowser(Browser.CHROME)
      .usingServer('http://localhost:4444')
      .build();
    await driver.get('https://www.selenium.dev');
    console.log(await driver.getTitle());
  } finally {
    if (driver) await driver.quit();
  }
})();

The URL must be reachable from the Node process, and the remote service must offer the requested browser capabilities. Selenium also documents using SELENIUM_REMOTE_URL to configure a remote server. Consult the Grid or server operator’s documentation for supported browsers, capabilities, authentication, and concurrency limits; those details vary by deployment.

Choice What you manage Useful when
Local browser Browser installation, version, and runtime on the test machine Developing locally or running a small suite on a known worker
Remote WebDriver Endpoint connectivity and the remote service’s browser capabilities Browser execution is provided by a Grid or another managed environment

6. Common failures and fixes

Symptom Likely cause What to check or change
Session creation fails before the test starts Node is below the binding’s supported minimum, the browser is unavailable, or driver setup cannot complete Check node --version, use Node.js 22 or newer for the current API, confirm the chosen browser is installed, and check network or proxy restrictions that may affect Selenium Manager.
Driver or browser version mismatch A pinned or manually configured driver does not match the browser environment Remove stale custom driver configuration if it is not required, or deliberately install a compatible pinned driver and configure its path using the browser module’s documented options.
Remote connection refused or times out The remote URL is wrong, the service is down, or the Node process cannot reach it Check the endpoint, service status, port, and network path from the machine running Node. Confirm the requested browser is available remotely.
Element not found The page has not loaded the element yet, the locator is wrong, or the page structure changed Verify the current page and locator. Wait for the relevant condition instead of assuming navigation means every dynamic element is ready.
Test hangs or a browser remains open A WebDriver promise is unawaited or teardown did not run Await each operation and put driver.quit() in a guarded Mocha after hook or a script’s finally block.
Mocha reports a timeout Browser startup or a page operation exceeds the runner’s current test timeout Identify which awaited operation is slow first. If the environment legitimately needs more time, configure Mocha’s timeout deliberately rather than masking a stuck session.

7. Performance, reliability, and cost

Browser tests are affected by browser startup, page load behavior, the application under test, and whether execution is local or remote. The sources do not provide a general benchmark, so measure the suite in its actual environment. Reuse a session within a suite when isolation permits; use clean sessions where test independence matters more than startup overhead.

For reliability, await every WebDriver command, close sessions in teardown, and keep the test data and target environment predictable. Remote execution adds endpoint availability and network reachability as dependencies. Selenium itself is open-source software; execution costs depend on the machines or remote browser infrastructure you choose. No single runtime or infrastructure price applies to all setups.

Or skip the browser setup

If your goal is to capture a page image or PDF rather than interactively test browser behavior, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. The API accepts common screenshot API parameter names, which can make switching easier. See the ScreenshotNeo API documentation.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://www.selenium.dev"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://www.selenium.dev'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = require('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before the capture; each cleanup step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan.

Get started with 1,000 free screenshots a month, no card required.

FAQ

Do I need to install ChromeDriver manually?

Usually no. Selenium Manager handles routine driver management through the binding. Manual driver setup is for custom or pinned environments.

Can I run Selenium tests without Mocha?

Yes. A Node script can create a session, perform browser actions, make assertions, and quit. A test runner adds a structure for multiple cases and lifecycle hooks.

Does a successful navigation mean the page is ready for every test?

No. Pages can update dynamically after navigation. Check for the specific element or state the test needs before interacting with it.

Can ScreenshotNeo replace Selenium for UI tests?

No. ScreenshotNeo captures pages and provides page information; Selenium drives browser interactions and assertions. Use the tool that matches whether you need a capture or an interactive browser test.

Official references