</>

Technology

Playwright

Difficulty

Intermediate

Interview Question

What is test.step() in Playwright and why should you use it?

Answer

test.step() in Playwright

test.step() is a way to group related actions under a named step, which improves:

  • āœ“Test report readability
  • āœ“Trace viewer navigation
  • āœ“Error messages that pinpoint where exactly the test failed

Basic Usage

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

test('complete checkout flow', async ({ page }) => {

  await test.step('Navigate to product page', async () => {
    await page.goto('/products/laptop');
    await expect(page.getByRole('heading', { name: 'Laptop Pro' })).toBeVisible();
  });

  await test.step('Add product to cart', async () => {
    await page.getByRole('button', { name: 'Add to Cart' }).click();
    await expect(page.locator('.cart-count')).toHaveText('1');
  });

  await test.step('Proceed to checkout', async () => {
    await page.getByRole('link', { name: 'View Cart' }).click();
    await page.getByRole('button', { name: 'Checkout' }).click();
    await expect(page).toHaveURL('/checkout');
  });

  await test.step('Fill shipping details', async () => {
    await page.getByLabel('Full Name').fill('John Doe');
    await page.getByLabel('Address').fill('123 Main St');
    await page.getByLabel('City').fill('New York');
    await page.getByLabel('Zip Code').fill('10001');
  });

  await test.step('Complete payment', async () => {
    await page.getByRole('button', { name: 'Place Order' }).click();
    await expect(page).toHaveURL('/order-confirmed');
    await expect(page.getByRole('heading')).toContainText('Order Confirmed');
  });
});

Steps in Reports

When this test runs, the HTML report and Trace Viewer show:

CODE
āœ“ complete checkout flow (4.2s)
  āœ“ Navigate to product page (0.8s)
  āœ“ Add product to cart (0.5s)
  āœ“ Proceed to checkout (0.9s)
  āœ“ Fill shipping details (1.2s)
  āœ— Complete payment (0.8s) ← Failure shows exactly here

test.step() Returns a Value

TypeScript
const orderId = await test.step('Place order and get ID', async () => {
  await page.getByRole('button', { name: 'Place Order' }).click();
  const confirmText = await page.locator('.order-id').textContent();
  return confirmText; // Return values work!
});

console.log('Order ID:', orderId);

Steps in Page Objects

TypeScript
// pages/CheckoutPage.ts
import { test } from '@playwright/test';

export class CheckoutPage {
  async fillShippingDetails(name: string, address: string) {
    return test.step('Fill shipping details', async () => {
      await this.nameInput.fill(name);
      await this.addressInput.fill(address);
    });
  }
}

Benefits

  • āœ“Trace Viewer shows step boundaries — click to see the exact DOM state at each step
  • āœ“HTML report shows step-level timing and failure location
  • āœ“Error messages include step names — "Step: Add product to cart" failed
  • āœ“Makes long tests self-documenting

Follow AutomateQA

Related Topics