Skip to main content

Serenity/JS for Cucumber Users

Already using Cucumber.js? Serenity/JS plugs right into your existing setup — with Playwright or WebdriverIO driving the browser.

You keep Cucumber's Gherkin syntax, step definitions, and hooks. Serenity/JS adds the Screenplay Pattern, structured reporting, and multi-actor support that help your team understand what the system does and ship with confidence.

→ New to Serenity/JS? Start with Why Serenity/JS to see the full picture.


Why add Serenity/JS?​

Serenity/JS works on top of Cucumber.js — your existing feature files, step definitions, and CI/CD pipeline all stay exactly as they are. You don't need to rewrite anything.

Here's how Serenity/JS helps you address common Cucumber challenges:

ChallengeHow Serenity/JS helps
Step definitions coupled to selectorsThe Screenplay Pattern gives you composable Tasks that separate what from how
Reports show only pass/failRich HTML reports with trend tracking, flaky test detection, and living documentation organised by feature and capability
Multi-user workflows are awkwardMulti-actor support is built in — actorCalled('Alice') and actorCalled('Bob') in the same scenario
Step definitions are hard to reuseScreenplay Tasks are composable and portable — reuse them across step definitions, scenarios, and projects
Locked into one browser driverScreenplay Tasks work with both Playwright and WebdriverIO — switch without rewriting logic
Slow UI-only test suitesBlended testing — use APIs for setup, UI only where it matters

Get started in 5 minutes​

The progression most teams go through looks like this:

  1. Add reporting (Steps 1–3) — configure the Serenity/JS adapter and reporters. Existing scenarios get better reports immediately.
  2. Use Screenplay for new step definitions (Step 4) — use the actor model for new scenarios. Old step definitions stay untouched.
  3. Extract shared Tasks — refactor common workflows into reusable building blocks.
  4. Blended testing — mix UI and API interactions in the same scenario for speed and reliability.

Step 0: Create a Cucumber project​

Already have a Cucumber project?

Skip this step and proceed with the remaining steps from your project directory.

Create a new directory and initialise a Cucumber project:

mkdir my-serenity-project
cd my-serenity-project
npm init -y
npm install --save-dev @cucumber/cucumber typescript ts-node @types/node

Create a tsconfig.json:

tsconfig.json
{
"compilerOptions": {
"target": "ES2021",
"module": "commonjs",
"lib": ["ES2021"],
"strict": true,
"esModuleInterop": true,
"outDir": "./lib"
}
}

Step 1: Install​

Prerequisites

You'll need a recent Node.js LTS version (Serenity/JS supports Node 22.22.2 and 24.15.0).

npm install --save-dev @serenity-js/core @serenity-js/cucumber @serenity-js/web @serenity-js/assertions @serenity-js/playwright @serenity-js/console-reporter @serenity-js/html-reporter playwright

→ Learn more: Full Cucumber installation guide | Why Serenity/JS?

Step 2: Configure​

Create a Cucumber profile that attaches the Serenity/JS adapter:

cucumber.yaml
default:
requireModule:
- ts-node/register
format:
- '@serenity-js/cucumber'
require:
- ./features/**/*.steps.ts
- ./features/**/*.config.ts

Create a Serenity/JS configuration file:

features/support/serenity.config.ts
import { BeforeAll, AfterAll } from '@cucumber/cucumber'
import { configure, Cast } from '@serenity-js/core'
import { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'

import * as playwright from 'playwright'

let browser: playwright.Browser;

BeforeAll(async () => {
browser = await playwright.chromium.launch({ headless: true });

configure({
actors: Cast.where(actor =>
actor.whoCan(BrowseTheWebWithPlaywright.using(browser)),
),
crew: [
'@serenity-js/console-reporter',
[ '@serenity-js/html-reporter', {
specDirectory: './features',
} ],
],
});
});

AfterAll(async () => {
await browser?.close();
});

Add the following script to your package.json:

package.json
 {
"scripts": {
+ "test": "cucumber-js"
}
}

→ Learn more: Cucumber configuration | HTML Reporter setup

Step 3: Run​

npm test

That's it. Your existing scenarios run as before, but now produce a rich HTML report in reports/serenity-js/. Open reports/serenity-js/index.html in your browser to view it.

Running a single scenario

Pass any arguments directly to Cucumber via npm test. For example, to run scenarios by name:

npm test -- --name="descriptive title"

Or to run scenarios by tag:

npm test -- --tags="@smoke"

→ Learn more: Reporting overview | HTML Reporter

Example HTML report generated by Serenity/JS (source)

Step 4 (optional): Write your first Screenplay scenario​

Steps 1–3 give you better reporting with zero changes to your step definitions. When you're ready to see what the Screenplay Pattern looks like with Cucumber, add a new feature file and step definitions:

features/website.feature
Feature: Website

Scenario: The serenity-js.org website should have a descriptive title
When Serena navigates to "https://serenity-js.org/"
Then she should see that the page title includes "Serenity/JS"
features/step-definitions/parameter.steps.ts
import { defineParameterType } from '@cucumber/cucumber'
import { actorCalled, actorInTheSpotlight } from '@serenity-js/core'

defineParameterType({
regexp: /[A-Z][a-z]+/,
transformer(name: string) {
return actorCalled(name);
},
name: 'actor',
});

defineParameterType({
regexp: /he|she|they|his|her|their/,
transformer() {
return actorInTheSpotlight();
},
name: 'pronoun',
});
features/step-definitions/website.steps.ts
import { When, Then } from '@cucumber/cucumber'
import { Actor } from '@serenity-js/core'
import { Ensure, includes } from '@serenity-js/assertions'
import { Navigate, Page } from '@serenity-js/web'

When('{actor} navigates to {string}', async (actor: Actor, url: string) => {
await actor.attemptsTo(
Navigate.to(url),
);
});

Then('{pronoun} should see that the page title includes {string}', async (actor: Actor, expectedTitle: string) => {
await actor.attemptsTo(
Ensure.that(
Page.current().title().describedAs('current page title'),
includes(expectedTitle),
),
);
});

Run npm test again. In the HTML report you'll now see each interaction (Navigate.to, Ensure.that) listed as a separate step with timing.

The key differences from plain Cucumber step definitions:

  • parameter.steps.ts registers the {actor} and {pronoun} Cucumber expression parameter types that Serenity/JS uses to resolve actors by name.
  • actorCalled('Serena') creates a named actor — the actor has a browser, but can also interact with REST APIs, multiple browser contexts, etc.
  • Navigate.to() and Ensure.that() are composable interactions that show up as named steps in your reports.
  • {actor} and {pronoun} automatically resolve to the correct actor instance based on the name or pronoun used in the Gherkin step.

For a more advanced example showing composable Tasks, the Lean Page Objects pattern, and masked credentials, see the Complete example below.

→ Learn more: Screenplay Pattern | Your first web scenario

Same Tasks, different runner

Screenplay Tasks are identical whether you use Cucumber, Playwright Test, or WebdriverIO as your test runner — only the configuration differs. See Serenity/JS with Playwright.


Go further​

Now that you've seen the basics, here are complete projects you can use as reference or as a starting point for your own.

Complete example​

A self-contained project you can copy in full. It includes:

  • features/website.feature — a simple Screenplay scenario using Navigate and Ensure (same pattern as Step 4)
  • features/swag-labs.feature — a more advanced scenario interacting with the Swag Labs demo website, using composable Task definitions and the Lean Page Objects pattern

Run npm install then npm test — the HTML report lands in reports/serenity-js/index.html.

Credentials in examples

The password secret_sauce is hard-coded in these examples to keep them simple and self-contained. In real-world tests, load credentials from environment variables or a password vault to avoid committing secrets to your repository.

features/swag-labs.feature
Feature: Swag Labs

Scenario: Standard user completes checkout
Given Alice has logged in with credentials "standard_user" and "secret_sauce"
When she adds "Sauce Labs Backpack" to the cart
And she completes checkout with:
| firstName | Alice |
| lastName | Smith |
| postalCode | 90210 |
Then she should see the confirmation "Thank you for your order!"

Project templates​

If you'd rather start from a fully configured project than add Serenity/JS to an existing one, use one of these GitHub template repositories. Each comes with CI configuration, example tests, and live reports you can preview.

StackLive Report
Cucumber + PlaywrightSerenity BDD
Cucumber + WebdriverIOSerenity BDD

→ All project templates


FAQ​

Does it slow down my tests?​

No. Serenity/JS adds negligible overhead.

Do I have to rewrite all my step definitions?​

No. Mix Screenplay and non-Screenplay step definitions in the same project. Start with reporting and introduce Screenplay gradually for new scenarios.

Can I use it with WebdriverIO instead of Playwright?​

Yes. Replace @serenity-js/playwright with @serenity-js/webdriverio and configure the cast of actors accordingly. Your Tasks stay identical — only the Ability configuration changes. See the Cucumber + WebdriverIO template.

Do I need Java?​

Not if you use the Serenity/JS HTML Reporter — it produces rich reports with trend tracking and flaky test detection using pure Node.js. Java is only needed for the Serenity BDD Reporter.

What Cucumber versions are supported?​

Serenity/JS supports all modern versions of @cucumber/cucumber. The adapter detects your version automatically.

Something not working?

Check the Troubleshooting guide for solutions to common issues with reports, screenshots, and configuration.


Next steps​

Community tutorials​

Using Playwright Test instead of Cucumber?

If you don't need Gherkin syntax, Serenity/JS works directly with Playwright Test or WebdriverIO for a simpler setup. See Serenity/JS with Playwright or Serenity/JS with WebdriverIO.