npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cerios/playwright-step-decorator

v2.2.1

Published

A Playwright decorator for creating step-based tests

Readme

🎭 Playwright Step Decorator | By Cerios

A TypeScript decorator for Playwright that makes your test steps more readable and traceable by allowing you to add dynamic, parameterized descriptions to your test steps.

Features

  • Decorator syntax for Playwright steps.
  • Dynamic descriptions: Use placeholders to inject parameter values into step descriptions.
  • Supports nested properties: Reference nested object properties in your descriptions.
  • Index-based placeholders: Reference arguments by their position.
  • Better parameter matching: Named placeholders now handle default values and rest parameters more reliably.
  • Readable complex values: Objects and arrays are rendered as JSON in step descriptions when possible.
  • Forwards Playwright step options: Pass box, timeout, or a custom location to test.step().
  • Accurate source locations: Step locations in reports point to the actual method call site, not the decorator implementation.

Installation

npm install @cerios/playwright-step-decorator

For Development

npm install --save-dev @cerios/playwright-step-decorator

Usage

Import the Decorator

import { step, stepResult } from "@cerios/playwright-step-decorator";

Use stepResult() for non-async @step methods that resolve no value, stepResult(value) when they resolve a non-function value, or stepResult(() => { ... }) when you want a small lambda with multiple actions. Function inputs are treated as factories, so if you need to resolve a function itself, return it from a lambda such as stepResult(() => actualFunction).

Basic Example

class MyTest {
	@step("Login as {{user.name}}")
	async login(user: { name: string }) {
		// ...login logic
	}

	@step("Click button [[0]] times")
	async clickButton(times: number) {
		// ...click logic
	}

	@step("Build greeting for {{name}}")
	buildGreeting(name: string): Promise<string> {
		return stepResult(`Hello ${name}`);
	}

	@step("Prepare greeting for {{name}}")
	prepareGreeting(name: string): Promise<string> {
		return stepResult(() => {
			const greeting = `Hello ${name}`;
			return greeting.toUpperCase();
		});
	}

	@step("Reset the form")
	resetForm(): Promise<void> {
		// No `await` inside and no `async` keyword needed (avoids the require-await lint error)
		this.dirty = false;
		return stepResult();
	}
}

Passing test.step() Options

You can pass Playwright step options as the only decorator argument, or as the second argument when you also want a custom description:

class MyTest {
	@step("Wait for checkout", { box: true, timeout: 15_000 })
	async waitForCheckout() {
		// ...wait logic
	}

	@step({ timeout: 5_000 })
	async refreshTotals() {
		// Uses the default step name: "MyTest.refreshTotals"
	}

	@step("Open modal", {
		location: { file: "tests/cart.spec.ts", line: 42, column: 7 },
	})
	async openModal() {
		// Uses the explicit location instead of the generated call site
	}

	@step("Submit order", { timeout: 30_000 })
	async submitOrder() {
		// Still auto-generates the call-site location because no custom location was supplied
	}
}

How It Works

The @step decorator wraps your promise-returning method in a Playwright test.step, using a dynamic description. Placeholders in the description are replaced with actual argument values at runtime.

Note: A decorated method does not need the async keyword. If a method body has no await, you can drop async to avoid the require-await lint error. Because the decorated call is wrapped in test.step (which is asynchronous) and callers should await it, keep the return type a Promise and return stepResult(), stepResult(value) for non-function values, or stepResult(() => { ... }) instead of marking the method async:

@step("Reset the form")
resetForm(): Promise<void> {
	this.dirty = false;
	return stepResult(); // no `async`, no require-await warning
}

@step("Build greeting for {{name}}")
buildGreeting(name: string): Promise<string> {
	return stepResult(`Hello ${name}`);
}

@step("Prepare greeting for {{name}}")
prepareGreeting(name: string): Promise<string> {
	return stepResult(() => {
		const greeting = `Hello ${name}`;
		return greeting;
	});
}

Placeholders

  • Named parameter: {{param}} Replaced with the value of the parameter named param. Named placeholders support identifier parameters, default values, and rest parameters.
  • Nested property: {{param.prop}} Replaced with the value of the property prop of parameter param.
  • Index-based: [[0]], [[1]], ... Replaced with the argument at the given index.

If a method uses destructured parameters, prefer index placeholders such as [[0]]. The decorator cannot reliably map destructured bindings like { name } back to a placeholder name such as {{name}}.

When a placeholder resolves to an object or array, the decorator renders it as JSON when possible so reports stay readable.


Examples

1. Named and Nested Placeholders

@step("User: {{user.name}}, Age: {{user.age}}")
async function greet(user: { name: string, age: number }) {
  // ...
}
await greet({ name: 'Alice', age: 30 });
// Step description: "User: Alice, Age: 30"

2. Index Placeholders

@step("First arg is [[0]], second is [[1]]")
async function doSomething(a: string, b: number) {
  // ...
}
await doSomething('foo', 42);
// Step description: "First arg is foo, second is 42"

3. Mixing Named and Index Placeholders

@step("Named: {{name}}, Index: [[1]]")
async function example(name: string, value: number) {
  // ...
}
await example('Bob', 77);
// Step description: "Named: Bob, Index: 77"

Accurate Source Locations in Reports

The decorator automatically captures the call site location of your decorated methods and passes it to Playwright's test.step(). This means that:

  • HTML reports show the correct file and line number where the method was called
  • Trace viewer points to the actual test code, not the decorator implementation
  • CI logs display accurate source locations for easier debugging

This feature uses Playwright's built-in location parameter to ensure step locations in reports are as helpful as possible. If you provide location in the decorator's second argument, that explicit value is used. Otherwise, the decorator falls back to the generated call-site location automatically.

Example

When you call a decorated method in your test:

// my-test.spec.ts
test("example", async ({ page }) => {
	const loginPage = new LoginPage(page);
	await loginPage.login(user); // Line 10
});

The Playwright report will show the step location as my-test.spec.ts:10, not the location of the decorator implementation.


Error Handling

  • Throws if a named parameter in the description does not exist in the function signature.
  • Throws a targeted error when named placeholders are used with destructured or otherwise unsupported parameter syntax, and suggests using index placeholders instead.
  • Throws if a nested property does not exist on the parameter.
  • Throws if an index placeholder is out of bounds.

Accessing Step Context (getStepInfo)

Sometimes you want to attach files, logs, or metadata to the current Playwright step inside your decorated method. Use the getStepInfo function to access the TestStepInfo object for the current step.

Example

import { step, getStepInfo } from "@cerios/playwright-step-decorator";

class NavbarTest {
	@step("Assert the navbar items are as expected")
	async assertNavbarItems(expectedItems: string[]): Promise<void> {
		const stepInfo = getStepInfo();
		await stepInfo.attach("expected-items.json", {
			body: JSON.stringify(expectedItems),
			contentType: "application/json",
		});
		// ...your assertions...
		await stepInfo.attach("actual-items.json", {
			body: JSON.stringify(await this.navbarItem.allInnerTexts()),
			contentType: "application/json",
		});
	}
}

Note:

  • getStepInfo() and getStepInfo(this) must be called inside a method decorated with @step.
  • Step context is tracked per async invocation, so concurrent Promise.all(...) calls on the same instance keep their own TestStepInfo.
  • Throws an error if called outside a step context.

API

step(description: string)

  • description: The step description, supporting placeholders like {{param}}, {{param.prop}}, or [[index]].
  • Returns: A decorator function for promise-returning methods.

getStepInfo()

  • Returns: The current Playwright TestStepInfo for the active decorated method call.

getStepInfo(instance)

  • instance: Retained for backwards compatibility with earlier releases.
  • Returns: The current Playwright TestStepInfo for the active decorated method call.

stepResult()

  • Returns: Promise<void> for non-async @step methods that do not return a value.

stepResult(value)

  • value: A non-function value to resolve.
  • Returns: Promise<Awaited<T>> for non-async @step methods that return a value.

stepResult(() => value)

  • callback: A zero-argument lambda that can perform multiple synchronous actions before returning a value.
  • Returns: Promise<Awaited<T>> with the callback result, rejecting if the callback throws.

If you need to resolve a function value itself, wrap it in the callback form: stepResult(() => actualFunction).


License

MIT


Author

Ronald Veth - Cerios


Contributing

Pull requests are welcome! Please open an issue first to discuss what you would like to change.


Links