CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-storybook--react

React renderer for Storybook framework providing TypeScript support, portable stories, and React-specific functionality

Pending
Overview
Eval results
Files

testing-integration.mddocs/

Testing Integration

Testing utilities and experimental Playwright integration for enhanced testing workflows. Provides tools for integrating Storybook stories with various testing frameworks and environments.

Type Dependencies

The testing integration features depend on Storybook preview API:

// Experimental Playwright integration
import { createTest } from "@storybook/react/experimental-playwright";

// Portable stories for testing (see Portable Stories documentation)
import { composeStory, composeStories, setProjectAnnotations } from "@storybook/react";

// Re-exported from storybook/preview-api
import { createPlaywrightTest } from "storybook/preview-api";

Capabilities

Create Test (Playwright Integration)

Experimental Playwright testing utility for creating test functions that work with Storybook stories.

/**
 * Creates Playwright test function for Storybook integration.
 * Re-exported from storybook/preview-api for convenience.
 * 
 * @returns Playwright test creation function
 */
function createTest(): any;

This function is part of the experimental Playwright integration and provides utilities for running Storybook stories in Playwright test environments.

Usage Example:

import { createTest } from "@storybook/react/experimental-playwright";

const test = createTest();

test("Button stories", async ({ page }) => {
  // Use with Playwright for visual testing
  await page.goto("/storybook-iframe.html?id=example-button--primary");
  await expect(page).toHaveScreenshot("primary-button.png");
});

Testing Patterns with React Testing Library

While not directly exported from @storybook/react, the package is designed to work seamlessly with React Testing Library through portable stories:

import { render, screen, fireEvent } from "@testing-library/react";
import { composeStory, composeStories } from "@storybook/react";
import Meta, { Primary, Secondary } from "./Button.stories";

// Single story testing
const PrimaryButton = composeStory(Primary, Meta);

test("renders primary button", () => {
  render(<PrimaryButton />);
  expect(screen.getByRole("button")).toHaveClass("primary");
});

// Testing with custom props
test("button accepts custom props", () => {
  render(<PrimaryButton size="large" onClick={vi.fn()} />);
  expect(screen.getByRole("button")).toHaveClass("large");
});

// Multiple story testing
const { Primary: PrimaryStory, Secondary: SecondaryStory } = composeStories(Meta);

describe("Button component", () => {
  test("all stories render correctly", () => {
    Object.entries(composeStories(Meta)).forEach(([name, Story]) => {
      render(<Story />);
      expect(screen.getByRole("button")).toBeInTheDocument();
    });
  });
});

Jest/Vitest Integration

import { beforeAll } from "vitest";
import { setProjectAnnotations } from "@storybook/react";
import * as projectAnnotations from "../.storybook/preview";

// Setup global configuration
beforeAll(() => {
  setProjectAnnotations(projectAnnotations);
});

// Test individual stories
import { composeStory } from "@storybook/react";
import Meta, { Default } from "./Component.stories";

const DefaultStory = composeStory(Default, Meta);

test("story renders with default args", () => {
  render(<DefaultStory />);
  // Test the rendered component
});

Testing with Context Providers

import { render } from "@testing-library/react";
import { composeStory } from "@storybook/react";
import { ThemeProvider } from "./theme";
import Meta, { Themed } from "./Button.stories";

const ThemedButton = composeStory(Themed, Meta);

test("button works with theme context", () => {
  render(
    <ThemeProvider theme="dark">
      <ThemedButton />
    </ThemeProvider>
  );
  
  // Test themed behavior
});

Visual Regression Testing

// Using @storybook/test-runner or Playwright
import type { TestRunnerConfig } from "@storybook/test-runner";

const config: TestRunnerConfig = {
  async postRender(page, context) {
    // Take screenshot of each story
    const elementHandler = await page.$("#storybook-root");
    const innerHTML = await elementHandler.innerHTML();
    expect(innerHTML).toMatchSnapshot(`${context.id}.html`);
  },
};

export default config;

Accessibility Testing

import { render } from "@testing-library/react";
import { axe, toHaveNoViolations } from "jest-axe";
import { composeStories } from "@storybook/react";
import * as stories from "./Button.stories";

expect.extend(toHaveNoViolations);

const { Primary, Secondary } = composeStories(stories);

test("Primary button should be accessible", async () => {
  const { container } = render(<Primary />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

Mock Function Testing

import { render, fireEvent } from "@testing-library/react";
import { composeStory } from "@storybook/react";
import { fn } from "@storybook/test";
import Meta, { Interactive } from "./Button.stories";

const InteractiveButton = composeStory(Interactive, Meta);

test("button calls onClick handler", () => {
  const mockFn = fn();
  render(<InteractiveButton onClick={mockFn} />);
  
  fireEvent.click(screen.getByRole("button"));
  expect(mockFn).toHaveBeenCalledTimes(1);
});

Integration with Testing Libraries

Setup for React Testing Library

// test-setup.ts
import "@testing-library/jest-dom";
import { setProjectAnnotations } from "@storybook/react";
import * as projectAnnotations from "../.storybook/preview";

setProjectAnnotations(projectAnnotations);

Setup for Vitest

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "jsdom",
    setupFiles: ["./test-setup.ts"],
  },
});

Setup for Jest

// jest.config.js
module.exports = {
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/test-setup.ts"],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
};

Advanced Testing Patterns

Testing Story Parameters

import { composeStory } from "@storybook/react";
import Meta, { WithBackground } from "./Button.stories";

const ButtonWithBackground = composeStory(WithBackground, Meta);

test("story uses correct background parameter", () => {
  expect(ButtonWithBackground.parameters.backgrounds.default).toBe("dark");
});

Testing Story Args

const PrimaryButton = composeStory(Primary, Meta);

test("story has correct default args", () => {
  expect(PrimaryButton.args).toEqual({
    primary: true,
    label: "Button",
    size: "medium",
  });
});

Testing with Loaders

import { composeStory } from "@storybook/react";
import Meta, { WithData } from "./DataComponent.stories";

const DataComponent = composeStory(WithData, Meta);

test("story with loader works correctly", async () => {
  // The story's loader will run automatically when composed
  render(<DataComponent />);
  
  // Test the component with loaded data
  await waitFor(() => {
    expect(screen.getByText("Loaded Data")).toBeInTheDocument();
  });
});

Experimental Features

The testing integration includes experimental features that may change in future versions:

  • Playwright Integration: Enhanced Playwright support for visual testing
  • Component Testing: Direct component testing within Storybook environment
  • Test Runner Integration: Built-in test runner for Storybook stories

These features are available through the experimental-playwright export and should be used with caution in production environments.

Install with Tessl CLI

npx tessl i tessl/npm-storybook--react

docs

index.md

portable-stories.md

preview-configuration.md

react-renderer.md

story-types.md

testing-integration.md

tile.json