Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsUse Cucumber.js to describe browser behavior as readable scenarios, and Selenium WebDriver to drive the browser that exercises them. Cucumber maps each scenario step to JavaScript; Selenium performs actions such as opening a page, entering text, clicking, waiting for results, and checking what a user can see. This guide builds a runnable local Chrome example, runs it, and explains how to handle setup, synchronization, and cleanup.
How Cucumber.js and Selenium fit together
Cucumber-JS is the Node.js implementation of Cucumber. A .feature file contains scenarios written in Gherkin, typically using Given, When, and Then. JavaScript step definitions connect those phrases to test code. Selenium’s JavaScript binding, selenium-webdriver, is the browser-control layer: it sends commands through a browser-specific driver to interact with a real browser. Cucumber’s own guidance is explicit: “Cucumber is not a browser automation tool, but it works well with the following browser automation tools.” Cucumber’s browser automation guide shows this integration pattern.
The example below tests a search form and verifies the resulting page title. The test is intentionally about an observable result rather than the application’s internal implementation. Replace the example URL and selectors with those for an application you own or are authorized to test.
Prerequisites and project setup
Check Node.js and browser availability
Use Node.js 22 or later, as required by the current Selenium JavaScript API, plus npm and a Chrome browser available in the environment where the test will run. Selenium’s documented JavaScript quick start uses Chrome and Selenium Manager to manage the browser driver for that path. This can simplify setup, but it does not guarantee success in every network-restricted, customized, or CI environment.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Create and install the project dependencies
-
Create a project directory and initialize npm:
mkdir cucumber-selenium-demo cd cucumber-selenium-demo npm init -y -
Install Cucumber-JS and Selenium WebDriver as development dependencies:
npm install --save-dev @cucumber/cucumber selenium-webdriver
The official Cucumber-JS installation page specifies @cucumber/cucumber and documents npm and Yarn installation: Cucumber-JS installation. Selenium’s current package and runtime requirements are documented in its JavaScript API reference.
Write a feature scenario
Create features/search.feature:
Feature: Search the example site
Scenario: A visitor searches for a term
Given I open the example search page
When I search for "webdriver"
Then the page title should contain "webdriver"
The wording describes the user-facing behavior. The step definitions will implement the browser work separately, so a scenario remains readable even if the page’s implementation changes.
Implement the Selenium browser session and steps
Create features/step_definitions/search.steps.js:
const { Given, When, Then, Before, After } = require('@cucumber/cucumber');
const assert = require('node:assert/strict');
const { Builder, Browser, By, until } = require('selenium-webdriver');
Before(async function () {
this.driver = await new Builder().forBrowser(Browser.CHROME).build();
});
After(async function () {
if (this.driver) {
await this.driver.quit();
}
});
Given('I open the example search page', async function () {
await this.driver.get('https://www.google.com/');
});
When('I search for {string}', async function (term) {
const searchBox = await this.driver.wait(
until.elementLocated(By.name('q')),
10000,
'Search box was not found within 10 seconds'
);
await this.driver.wait(until.elementIsVisible(searchBox), 10000);
await searchBox.sendKeys(term);
await searchBox.submit();
});
Then('the page title should contain {string}', async function (expectedText) {
await this.driver.wait(until.titleContains(expectedText), 10000);
const title = await this.driver.getTitle();
assert.ok(
title.toLowerCase().includes(expectedText.toLowerCase()),
`Expected title to contain "${expectedText}", got "${title}"`
);
});
This example uses a public search page as an illustration; public websites can change their markup or show consent, localization, or bot-check pages. For stable automated tests, prefer a controlled application or test environment with selectors and data you maintain.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Why use asynchronous steps and explicit waits?
WebDriver operations return promises, so each navigation, lookup, interaction, and assertion-related read should be awaited. A page load or click does not necessarily mean that an asynchronously rendered result is ready. The example waits for the search field to exist and become visible, then waits for the title condition before asserting it. Adjust the condition to match the actual user-visible state that matters, such as a result element appearing or a confirmation message changing.
Why the hooks use regular functions
Cucumber’s hooks can create and close one browser session per scenario. In this example, the driver is stored on Cucumber’s World as this.driver. The hook and step callbacks use regular function expressions because arrow functions do not receive Cucumber’s World as this. See the Cucumber-JS hooks documentation.
Run the browser test
From the project root, run:
npx cucumber-js
Cucumber discovers feature files under features and their matching support code under features/step_definitions using the conventional layout. A passing run reports the scenario’s steps as successful; a failed assertion or step is reported as a failure. If your project uses a different directory layout or configuration, provide the appropriate paths for that setup rather than assuming this default.
Adapt the example to your application
Choose the browser
The example selects Chrome with new Builder().forBrowser(Browser.CHROME).build(). Selenium’s Builder supports selecting a browser, and the JavaScript API documents the SELENIUM_BROWSER environment variable as an alternative configuration path. Use a browser available in the execution environment; the browser choice alone does not install that browser.
Recommended Free Tools
Rank #3
Use a remote Selenium server when needed
For execution through Selenium Grid or another standalone remote server, configure the Builder to use the server URL, for example with usingServer(), or use the documented SELENIUM_REMOTE_URL setting. A remote setup adds a separately managed server and browser environment; it is not required for the local Chrome example. Consult the Selenium JavaScript API documentation for the current configuration details.
Make scenarios independent
Creating and quitting the driver in hooks gives each scenario a clear browser lifecycle. If your suite needs shared setup, authenticated state, or multiple browser configurations, keep that setup explicit and ensure scenarios do not depend on execution order. Always close the session after the scenario, including when a step fails; an awaited teardown hook prevents orphaned browser sessions.
Troubleshooting
Package or runtime errors
-
Cannot find module: Confirm that both packages are installed in the project and that you are running
npx cucumber-jsfrom the project directory. Check that step definitions are in a discoverable support-code path. -
Unsupported Node.js version or syntax/runtime failures: Check
node --versionand use Node.js 22 or later for the current Selenium JavaScript API.Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Browser startup or driver errors
-
Chrome cannot start or a driver cannot be obtained: Confirm that Chrome is installed and executable in the target environment, and that the environment permits the documented Selenium Manager flow to obtain what it needs. Restricted network access, browser installation, permissions, or a customized environment may require separate configuration.
-
Local run works but remote or CI run fails: Check which browser is installed on the runner and whether the test is actually configured for local execution or a remote Selenium URL. A remote server must be reachable and configured independently.
Timing and element failures
-
Element not found: Verify the selector against the current page, check whether the page presents a different state such as a consent dialog, and wait for the element’s relevant condition instead of querying immediately.
-
Stale element or result not ready: Dynamic pages may replace elements after navigation or interaction. Locate the element after the update and wait for an observable condition such as visibility, text, or title.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Unexpected page title: Inspect the actual page state. A changed application, localization, redirect, or bot check can mean the test is not seeing the expected page; do not weaken the assertion without understanding the difference.
Or skip the browser setup
If you need a screenshot rather than an interactive browser test, ScreenshotNeo offers a one-request screenshot API and an MCP server. It is not a replacement for Selenium tests: it captures pages, while Selenium drives browser interactions and Cucumber organizes scenarios. ScreenshotNeo accepts cookie and consent banners and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the page verdict and billing status in headers.
One-call cURL example, using a page URL as the target:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Replace the example target URL with the page you want to capture. The API can return PNG, JPEG, WebP, or PDF; see the ScreenshotNeo API documentation for request options. Its 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 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo free.
Frequently asked questions
Can Cucumber.js automate a browser without Selenium?
Cucumber.js defines and runs scenarios; browser control must come from a browser automation tool or another mechanism. Selenium is one option for that control layer.
Should a test assert on page internals or user-visible behavior?
Prefer an observable outcome that represents the behavior the scenario promises, such as a result appearing or a confirmation being shown. Internal implementation details tend to make scenarios more coupled to page changes.
Can I run these tests against a browser other than Chrome?
Yes. Selenium supports browser selection through its Builder, provided the chosen browser and execution environment are available and configured for the run.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




