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

@korvol/stepwright

v0.1.3

Published

Step-based framework for writing resilient Playwright scripts with rich failure context

Downloads

393

Readme

@korvol/stepwright

A step-based framework for writing resilient Playwright scripts with rich failure context, video recording, and trace capture.

Features

  • Fluent API - Chain steps, checkpoints, and configuration
  • Video & Trace Recording - Capture video and Playwright traces with configurable modes
  • Rich Failure Context - Automatic capture of screenshots, DOM, and logs on failure
  • Checkpoints - Group steps and define retry strategies
  • Background Tasks - Handle modals, auth redirects, and dynamic content
  • Reporters - Console and JSON reporters included, extensible architecture
  • Failure Cases - Generate structured failure data for AI-powered fixing with Fixwright

Installation

npm install @korvol/stepwright playwright
# or
pnpm add @korvol/stepwright playwright

Quick Start

import { Stepwright, ConsoleReporter } from '@korvol/stepwright';

interface MyData {
  username: string;
  loggedIn: boolean;
  [key: string]: unknown;
}

const script = Stepwright.create<MyData>('Login Flow')
  .config({
    headless: false,
    defaultTimeout: 30000,
    screenshotOnFailure: true,
  })
  .video({ mode: 'on-failure' })
  .trace({ mode: 'on-failure' })
  .reporter(new ConsoleReporter())
  .data({
    username: '[email protected]',
    loggedIn: false,
  })

  .checkpoint('Authentication', { required: true })

  .step('Navigate to login', async (ctx) => {
    await ctx.page.goto('https://example.com/login');
    ctx.log('Navigated to login page');
  })

  .step('Enter credentials', async (ctx) => {
    await ctx.page.fill('#username', ctx.data.username);
    await ctx.page.fill('#password', 'password');
  })

  .step('Submit form', async (ctx) => {
    await ctx.page.click('button[type="submit"]');
    await ctx.page.waitForURL('**/dashboard');
    ctx.data.loggedIn = true;
  })

  .endCheckpoint();

const result = await script.run();
console.log(result.success ? 'Passed!' : `Failed at: ${result.failedStep?.name}`);

Configuration

Basic Options

Stepwright.create('My Script')
  .config({
    // Browser
    browser: 'chromium',           // 'chromium' | 'firefox' | 'webkit'
    headless: true,
    launchOptions: {},             // Playwright LaunchOptions
    contextOptions: {},            // Playwright BrowserContextOptions

    // Timeouts
    defaultTimeout: 30000,         // ms
    stopOnFailure: true,

    // Failure Artifacts
    screenshotOnFailure: true,
    domOnFailure: true,

    // Output
    runDir: '.stepwright/runs',    // Base directory for run artifacts
    artifactDir: '.stepwright/artifacts',
    verbose: false,
  })

Video Recording

.video({
  mode: 'on-failure',              // 'off' | 'on' | 'on-failure' | 'retain-on-failure'
  size: { width: 1280, height: 720 },
  dir: './custom-videos',          // Optional: override output directory
})

Trace Recording

.trace({
  mode: 'on-failure',              // 'off' | 'on' | 'on-failure' | 'retain-on-failure'
  screenshots: true,
  snapshots: true,
  sources: true,
  dir: './custom-traces',          // Optional: override output directory
})

Reporters

import { ConsoleReporter, JSONReporter } from '@korvol/stepwright';

.reporter(new ConsoleReporter({
  timestamps: true,
  durations: true,
  colors: true,
}))

.reporter(new JSONReporter({
  outputPath: './results/output.json',  // Optional: defaults to run directory
  pretty: true,
}))

API Reference

Stepwright

Stepwright.create<T>(name: string)

Create a new Stepwright instance with typed data.

.config(options: StepwrightConfig)

Configure the instance. Returns this for chaining.

.data(initialData: T)

Set initial shared data. Returns this for chaining.

.video(config: VideoConfig | VideoMode)

Configure video recording. Returns this for chaining.

.trace(config: TraceConfig | TraceMode)

Configure trace recording. Returns this for chaining.

.reporter(reporter: Reporter)

Add a reporter. Returns this for chaining.

.checkpoint(name: string, options?: CheckpointOptions)

Start a checkpoint group. Returns this for chaining.

.endCheckpoint()

End the current checkpoint. Returns this for chaining.

.step(name: string, fn: StepFunction, options?: StepOptions)

Add a step. Returns this for chaining.

.step('My Step', async (ctx) => {
  // ctx.page - Playwright Page
  // ctx.browser - Playwright Browser
  // ctx.browserContext - Playwright BrowserContext
  // ctx.data - Typed shared data
  // ctx.log(message) - Log a message
  // ctx.screenshot(name) - Take a screenshot
}, {
  timeout: 60000,
  critical: true,
  retry: { times: 3, delay: 1000, backoff: 'exponential' },
})

.background(name: string, task: BackgroundTaskDefinition)

Add a background task for handling dynamic content.

.run(options?: RunOptions)

Execute the script. Returns Promise<StepwrightResult<T>>.

StepwrightResult

interface StepwrightResult<T> {
  success: boolean;
  duration: number;
  stepsCompleted: number;
  totalSteps: number;
  steps: StepResult[];
  checkpoints?: CheckpointResult[];
  data: T;

  // On failure
  failedStep?: {
    name: string;
    index: number;
    checkpoint?: string;
    error: Error;
    artifacts: StepArtifacts;
  };

  // Artifact paths
  runDirectory?: string;
  trace?: string;
  video?: string;
  log?: string;
}

Context (ctx)

Available in step functions:

| Property | Type | Description | |----------|------|-------------| | page | Page | Playwright Page | | browser | Browser | Playwright Browser | | browserContext | BrowserContext | Playwright BrowserContext | | data | T | Typed shared data between steps | | config | StepwrightConfig | Current configuration | | step | CurrentStepInfo | Current step info | | results | StepResult[] | Results of completed steps | | log(msg) | Function | Log a message | | screenshot(name?) | Function | Take a screenshot | | getDOM(selector?) | Function | Get DOM content |

Generating Failure Cases

When a script fails, you can generate a structured failure case for AI-powered fixing with Fixwright:

import { Stepwright, generateFailureCase } from '@korvol/stepwright';

const result = await script.run();

if (!result.success && result.failedStep) {
  const failureCase = generateFailureCase(result, {
    scriptInfo: {
      name: 'My Script',
      path: 'scripts/my-script.ts',
      repository: 'my-org/my-repo',
      baseBranch: 'main',
      commit: 'abc123',
    },
    artifactPaths: {
      screenshot: result.failedStep.artifacts.screenshot,
      dom: result.failedStep.artifacts.dom,
    },
  });

  // Save or send to Fixwright
  await fs.writeFile(`failures/${failureCase.id}.json`, JSON.stringify(failureCase));
}

Run Directory Structure

When video/trace recording is enabled, artifacts are saved to:

.stepwright/
└── runs/
    └── script-name-20240102-123456/
        ├── trace/           # Playwright trace (unzipped)
        ├── screenshots/     # Manual screenshots
        ├── video.webm       # Video recording
        ├── stepwright.log   # ctx.log messages
        └── result.json      # JSON reporter output

Background Tasks

Handle dynamic content like modals and auth redirects:

.background('cookie-consent', {
  trigger: (event) => event.type === 'dom' && event.mutation === 'added',
  handler: async (event, ctx, queue) => {
    const button = ctx.page.locator('[data-testid="accept-cookies"]');
    if (await button.isVisible({ timeout: 500 })) {
      await button.click();
      ctx.log('Dismissed cookie consent');
    }
  },
  debounce: 1000,
})

Integration with Fixwright

Stepwright produces failure cases that Fixwright can automatically fix:

Stepwright (runner)          Fixwright (fixer)
       │                            │
       │  ──── FailureCase ────▶    │
       │                            │
   [runs scripts]              [analyzes failures]
   [captures errors]           [generates fixes]

See @korvol/fixwright for AI-powered automatic fixing.

License

MIT