JSPM

@storycap-testrun/browser

2.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1357
  • Score
    100M100P100Q113430F
  • License MIT

Screenshot capture for Storybook addon-vitest - Provides stable visual testing functionality and Vitest plugin for Storybook stories running in browser environments

Package Exports

  • @storycap-testrun/browser
  • @storycap-testrun/browser/package.json
  • @storycap-testrun/browser/vitest-plugin

Readme

@storycap-testrun/browser

GitHub Actions Workflow Status NPM Version MIT LICENSE

Screenshot capture for Storybook addon-vitest - Provides stable visual testing functionality and Vitest plugin for Storybook stories running in browser environments.


@storycap-testrun/browser brings reliable visual testing to @storybook/addon-vitest with the same stability approach as storycap, optimized for Vitest browser environments 📷

Why @storycap-testrun/browser?

@storybook/addon-vitest enables running Storybook tests directly in the browser environment. While the underlying @vitest/browser provides basic screenshot functionality, it lacks the specialized features needed for reliable visual regression testing:

Limited visual testing capabilities:

  • Basic screenshot API without stability detection
  • No automatic waiting for rendering completion
  • Fixed file paths with limited configuration options
  • No built-in handling for dynamic content or animations
  • Missing retry mechanisms for flaky captures

@storycap-testrun/browser enhances the basic functionality with production-ready features:

Stability and reliability:

  • Intelligent waiting: Automatically detects when rendering is truly complete using CDP metrics
  • Hash verification: Ensures screenshot consistency through multiple capture comparison
  • Flaky prevention: Built-in masking and removal for dynamic content

Developer experience:

  • Flexible file management: Full control over screenshot paths and naming conventions
  • Story-level configuration: Per-story parameters for skip, delay, mask, and remove
  • Vitest plugin: Seamless integration with Vitest's configuration and lifecycle

Performance optimizations:

  • Metrics monitoring: Uses Chrome DevTools Protocol for efficient stability detection (Chromium)
  • Smart retries: Configurable retry logic that minimizes unnecessary captures
  • Browser-native execution: Screenshots captured directly in the test environment without external automation

This makes it ideal for teams who need more than basic screenshots - providing the reliability and flexibility required for production visual regression testing workflows.

Features

  • High stability checks for rendering content
  • Accurate waiting for Play Function
  • Customization before and after screenshot capture using Hooks
  • Masking of unstable elements
  • Removal of unstable elements
  • Skipping of unstable elements
  • Easy setup with Vitest plugin
  • Integration with Storybook addon-vitest

Requirements

  • Vitest browser mode with Playwright provider
  • @storybook/addon-vitest setup

Limitations

  • Metrics monitoring limited to Chromium browsers
    • Full stability checks work only with Chromium-based browsers (Chrome, Edge, etc.)
    • Fallback: Other browsers use hash verification only (still effective, but slower)
  • Browser environment constraints
    • Limited to capabilities available in browser context.

Installation

Install via npm:

$ npm install --save-dev @storycap-testrun/browser

Getting Started

Please set up @storybook/addon-vitest beforehand.

1. Configure Vitest

Add the storycap plugin to your vitest.config.js:

import path from 'node:path';
import { defineConfig, defineProject } from 'vitest/config';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
import storycap from '@storycap-testrun/browser/vitest-plugin';

export default defineConfig({
  test: {
    projects: [
      defineProject({
        plugins: [
          storybookTest({
            configDir: '.storybook',
            storybookScript: 'storybook --ci',
          }),
          storycap({
            // options...
          }),
        ],
        test: {
          name: 'storybook',
          browser: {
            enabled: true,
            provider: 'playwright',
            headless: true,
            instances: [{ browser: 'chromium' }],
          },
          setupFiles: ['./.storybook/vitest.setup.ts'],
        },
      }),
    ],
  },
});

2. Setup Screenshot Capture

Create .storybook/vitest.setup.ts:

import { afterEach } from 'vitest';
import { page } from '@vitest/browser/context';
import { screenshot } from '@storycap-testrun/browser';
import { setProjectAnnotations } from '@storybook/react-vite'; // Adjust for your framework
import * as projectAnnotations from './preview';

setProjectAnnotations([projectAnnotations]);

afterEach(async (context) => {
  await screenshot(page, context);
});

Why afterEach?

  • Post-story state: Captures the final state after all story rendering and play functions complete
  • Test isolation: Each story gets its own screenshot without interference from previous tests
  • Automatic execution: No need to manually call screenshot in every story file
  • Consistent timing: Ensures screenshots are taken at the same lifecycle point for all stories

3. Run Tests

$ vitest run --project=storybook

By default, the screenshot images are saved in the __screenshots__ directory.

TypeScript Setup

By importing types and merging them for the framework you use, you can enable type checking for parameters specified in each Story.

import type { ScreenshotParameters } from '@storycap-testrun/browser';

// Replace it with the framework you are using.
declare module '@storybook/react' {
  interface Parameters {
    screenshot?: ScreenshotParameters;
  }
}

// For other frameworks, replace with your framework's module name

API

screenshot(page, context, options)

  • page: BrowserPage
    • The page instance from @vitest/browser/context.
  • context: TestContext
    • The test context from Vitest passed in setup hooks.
  • options: BrowserScreenshotOptions
  • Returns: Promise<void>

Vitest Plugin

storycap(options)

The Vitest plugin that integrates screenshot functionality with Vitest's browser mode.

What the plugin does:

  • File output management: Handles screenshot file naming and directory structure
  • Test context integration: Provides story metadata to the screenshot function
  • Build-time configuration: Sets up screenshot options during Vitest configuration
  • Vitest compatibility: Ensures proper integration with Vitest's browser test lifecycle

Why you need it: The plugin bridges Vitest's test execution with screenshot capture, providing the necessary context and configuration that the standalone screenshot() function needs to work properly in a Vitest environment.

Plugin Options

type VitestStorycapPluginOptions = {
  output?: ScreenshotOutputOptions<BrowserScreenshotContext>;
};
output.dir

Type: string
Default: path.join(process.cwd(), '__screenshots__')

Specifies the root directory for saving screenshot images.

output.file

Type: string | ((context: BrowserScreenshotContext) => string)
Default: path.join('[file]', '[name].png')

Specifies the file name for the screenshot image of each Story.

When specifying a string, the following templates can be used:

  • [id]: Story ID
  • [name]: Story's name
  • [file]: Test file path

When specifying a function, you can access the context object:

storycap({
  output: {
    file: (context) =>
      path.join(context.file.replace('.stories.js', ''), `${context.name}.png`),
  },
});

Options

Options that can be specified as the third argument in the screenshot function.

flakiness.metrics.enabled

Type: boolean
Default: true

When set to true, it monitors several metrics related to the rendering of the Story and performs stability checks.

[!WARNING] As this process depends on CDP, it works only in Chromium browsers. If enabled in browsers other than Chromium, a warning will be displayed.

flakiness.metrics.retries

Type: number
Default: 1000

The number of retries during metrics monitoring. It continues monitoring for the specified number of frames (1 frame = 16ms) and ensures that the metrics stabilize.

flakiness.retake.enabled

Type: boolean
Default: true

This option calculates the hash value of the screenshot image and checks the stability of the rendering content by ensuring that there are no changes in the image.

[!TIP] In the case of Chromium, flakiness.metrics.enabled alone is often sufficient. Enabling this option means capturing screenshots at least twice, so it's recommended to disable it if it leads to performance degradation.

flakiness.retake.interval

Type: number
Default: 100

The interval in milliseconds before attempting to capture the screenshot again. The second capture is performed immediately for hash checking.

flakiness.retake.retries

Type: number
Default: 10

The number of times to repeat capturing the screenshot until the hash values of the images are identical. A value of 3 or more is recommended to achieve the effect of retries.

hooks

Type: BrowserScreenshotHook[]
Default: []

Hooks for interrupting processes before and after screenshot capture. Please specify an object that implements the following interface.

export type BrowserScreenshotHook = {
  setup?: (
    page: BrowserPage,
    context: BrowserScreenshotContext,
  ) => Promise<void>;
  preCapture?: (
    page: BrowserPage,
    context: BrowserScreenshotContext,
  ) => Promise<void>;
  postCapture?: (
    page: BrowserPage,
    context: BrowserScreenshotContext,
    filepath: string,
  ) => Promise<void>;
};

Each is executed in the following lifecycle:

Method Description
setup Immediately after the screenshot function is executed
preCapture After stability checks are completed
postCapture After the screenshot is captured, before the image is saved

The built-in functions like Masking and Removal are implemented using Hooks.

fullPage

Type: boolean
Default: true

See Page | Playwright.

omitBackground

Type: boolean
Default: false

See Page | Playwright.

scale

Type: 'css' | 'device'
Default: 'device'

See Page | Playwright.

Parameters

These are parameters that can be specified for each Story.

// Button.stories.tsx
const meta: Meta<typeof Button> = {
  component: Button,
  parameters: {
    screenshot: {
      /* parameters... */
    },
  },
};

export default meta;

skip

Type: boolean
Default: false

Skips the screenshot capture. Useful in cases where you want to conduct tests with addon-vitest but disable screenshot capture.

delay

Type: number
Default: None

The delay in milliseconds before capturing the screenshot. Waits after completing the basic stability checks.

mask

Type: string | { selector: string; color: string }
Default: None

Masks elements corresponding to the CSS selector with a rectangle. Useful for hiding elements that inevitably differ in content with each render.

remove

Type: string
Default: None

Removes elements corresponding to the CSS selector.

License

MIT © reg-viz

reg-viz