Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use await test.step('Step title', async () => { ... }) inside a Playwright Test test to group actions under a descriptive name in the test report. Steps can be nested, return values, and take options for error locations, report context, and timeouts. They are useful for making a test’s intent easier to follow; they are not required for the test to run.

A minimal working example

Import test and expect from @playwright/test, then await each step. Put the operations and checks that belong together in its asynchronous callback:

import { test, expect } from '@playwright/test';

test('checkout', async ({ page }) => {
  await test.step('Open the product page', async () => {
    await page.goto('/products/123');
  });

  await test.step('Add the product to the cart', async () => {
    await page.getByRole('button', { name: 'Add to cart' }).click();
    await expect(page.getByRole('status')).toContainText('Added');
  });
});

The first argument is the step title; the second is the callback to run. The callback is asynchronous, so use await for Playwright operations and assertions inside it. Await test.step itself as well: this keeps the test’s control flow in order and ensures a failure in the step is reported as a failure of the test.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Step labels should tell a reader what meaningful action or checkpoint is happening. For example, “Add the product to the cart” is more useful in a report than “Click button” or “Assertion 1.” You can leave a small operation unwrapped; adding a step for every locator call or assertion can make the report noisier rather than clearer.

What `test.step` changes—and what it does not

test.step names a portion of a test so it can be inspected as a step in Playwright’s reporting experience. It does not perform an action by itself, replace a locator, or make a test pass. The callback’s code is what performs the work. If a test does not use named steps, it can still execute normally; its operations simply will not have those author-defined group labels.

The method’s documented signature is test.step(title, body, options?). The callback may receive a TestStepInfo argument, and its return value is also the return value of test.step. Steps can be nested when a larger phase contains smaller meaningful phases.

Return a value from a step

Return data from the callback when the next part of the test needs it. The returned value is available from the awaited call:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const username = await test.step('Choose an account', async () => {
  return 'alex';
});

expect(username).toBe('alex');

This is ordinary callback return behavior exposed by test.step; it does not require a special option. Keep the value’s creation inside the step only when doing so makes the test’s action clearer.

Nest steps to show meaningful hierarchy

A step callback can itself call and await test.step. Use nesting to express a real parent-child relationship, such as a checkout flow containing address and payment phases. Avoid nesting merely to create more report entries: each level should help someone understand where a test is in its workflow.

Use `TestStepInfo` to skip or attach files

The callback can accept a step-info object. The documented TestStepInfo API provides step-scoped operations, including conditional skipping and attachments.

Skip a step conditionally

Call step.skip(condition, description) when the step is not applicable under a particular condition. For instance, a control available only in a desktop layout should not be asserted on a mobile layout:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await test.step('Check desktop-only control', async step => {
  step.skip(isMobile, 'Not present in the mobile layout');
  await expect(
    page.getByRole('button', { name: 'Desktop action' })
  ).toBeVisible();
});

Set the condition and description to match the actual reason that action is inapplicable. A skip should not conceal a failure that the test is meant to catch.

Attach an artifact to the step

Use step.attach(name, options) to associate an artifact, such as a screenshot or downloaded file, with a particular step. This helps a report reader find the evidence alongside the operation it relates to. By contrast, testInfo.attach() attaches an artifact at the test level. Choose the narrower scope when the file belongs to one specific step.

Choose step options by the problem they solve

Options are the third argument to test.step. They affect different parts of reporting or execution, so they are not interchangeable preferences. The Playwright Test API reference documents these options and their version introductions.

Option What it does Introduced
box When true, errors inside the step point to the step call site in the report, which can make a reusable helper’s invocation easier to locate than its internal failure line. Playwright v1.39
location Supplies a custom source location displayed in reports and the trace viewer. Playwright v1.48
timeout Sets a maximum duration for the step in milliseconds. The documented default is 0, meaning no step-specific timeout. Playwright v1.50
params Supplies serializable step parameters for reporters and the trace viewer. Playwright v1.63
subtitle Adds a secondary label next to the step title in reports and the trace viewer. Playwright v1.63

These version numbers are the introductions listed in the API reference, not a guarantee that a project has those versions installed. Check the reference for the Playwright version your project uses before relying on an option added in a later release.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use `box` for helper call sites

If a step wraps a reusable helper and a failure currently directs attention to an internal line, box: true makes the step error point to the call site. This changes where the error is presented; it does not change the underlying cause or repair the helper.

await test.step('Create a saved search', async () => {
  await createSavedSearch(page);
}, { box: true });

Use location, subtitle, and params for report context

location controls the source location displayed in the report and trace viewer. subtitle adds a secondary label, while params supplies serializable context for reporters and the trace viewer. Use them when that extra context makes a step easier to identify; do not put sensitive values into report metadata.

Set a step-specific timeout only when needed

The timeout option sets the step’s maximum duration in milliseconds. Use it when a particular step needs an explicit time boundary. Since the documented default is zero (no step-specific timeout), do not assume every step has an independent timeout unless you configure one. Consult your installed version’s API reference for how the option is supported in that version.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Find steps in reports and observe them in a reporter

The Playwright HTML Reporter provides a test detail view where readers can explore steps. The official running and debugging guide covers running tests and report workflows. Open the relevant test in the report and inspect its step hierarchy to see the named sections and their outcomes.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If you build a custom reporter, the reporter API documents onStepBegin and onStepEnd hooks. Playwright calls these hooks as steps begin and end while the test is running, before onTestEnd. Configure a custom reporter with the reporter option in the Playwright test configuration; see the Reporter API and test configuration reference.

Step events are reporter lifecycle events, not a requirement to use a particular reporter. A test can use test.step without a custom reporter, and a custom reporter can observe executed steps through the documented hooks.

Troubleshoot missing steps or confusing errors

  • The report has no named step hierarchy: Confirm the code is executing as a Playwright Test test and that the operations are actually wrapped in awaited test.step calls. Then inspect the test detail in the report or trace rather than expecting step labels in unrelated output.
  • An error points inside a helper: Consider box: true on the step that calls that helper if highlighting the invocation is more useful. It changes the reported location, not the failing operation.
  • An option is rejected or unavailable: Check the installed Playwright version against the version introduction in the API reference. Options have different introduction points, including newer params and subtitle options.
  • A later operation runs before a step finishes: Check that the test awaits test.step and that asynchronous work inside its callback is awaited. An unawaited operation can escape the intended sequence.
  • A skipped step still appears in the test flow: A skip is a reporting outcome for a conditionally inapplicable step, not a way to delete the step’s place from the test’s execution history. Check the condition and description supplied to step.skip.

Or skip the browser setup

test.step organizes Playwright test actions; it does not capture website screenshots as an API. If you need a screenshot file without setting up browser capture yourself, ScreenshotNeo provides a one-request website screenshot API. For example, this cURL request saves a WebP capture of Stripe:

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

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server gives AI agents screenshot tools, and the Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can a `test.step` callback return a value?

Yes. The awaited `test.step` call returns the callback’s return value, so you can use it in the next part of the test.

Does `test.step` have a step-specific timeout by default?

The documented default for its `timeout` option is 0, which means there is no step-specific timeout.

Can I attach a screenshot to one step instead of the whole test?

Yes. Use the callback’s `TestStepInfo` argument and its `attach` method to associate the artifact with that step.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.