CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-msw-storybook-addon

Mock API requests in Storybook with Mock Service Worker.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

storybook-integration.mddocs/

Storybook Integration

Storybook loaders and decorators for applying MSW handlers on a per-story basis, with automatic cleanup and error handling. This enables mocking different API responses for different story variants.

Capabilities

MSW Loader

Modern Storybook loader that applies MSW handlers for each story and waits for MSW readiness.

/**
 * Storybook loader that applies MSW handlers and waits for MSW to be ready
 * @param context - Storybook context containing story parameters
 * @returns Promise that resolves to empty object when ready
 */
function mswLoader(context: Context): Promise<{}>;

interface Context {
  parameters: MswParameters;
}

Usage Example:

// In .storybook/preview.ts
import { initialize, mswLoader } from "msw-storybook-addon";

// Initialize MSW
initialize();

// Configure the loader globally
export const loaders = [mswLoader];

// In story files
import type { Meta, StoryObj } from "@storybook/react";
import { http, HttpResponse } from "msw";

export const Success: StoryObj = {
  parameters: {
    msw: {
      handlers: [
        http.get("/api/user", () => {
          return HttpResponse.json({ name: "John Doe" });
        }),
      ],
    },
  },
};

MSW Decorator (Deprecated)

Legacy Storybook decorator for applying MSW handlers. This is deprecated in favor of mswLoader.

/**
 * Legacy Storybook decorator for MSW handlers (deprecated)
 * @param storyFn - Story function to wrap
 * @param context - Storybook context with parameters
 * @returns Story function result
 * @deprecated Use mswLoader instead
 */
function mswDecorator<Story extends (...args: any[]) => any>(
  storyFn: Story,
  context: Context
): any;

Migration Example:

// OLD (deprecated)
import { mswDecorator } from "msw-storybook-addon";

export const decorators = [mswDecorator];

// NEW (recommended)
import { mswLoader } from "msw-storybook-addon";

export const loaders = [mswLoader];

MSW Parameters Interface

Type definition for MSW parameters in Storybook stories, supporting both array and object formats.

// MSW types imported from 'msw'
import type { RequestHandler } from 'msw';

interface MswParameters {
  [key: string]: any;
  msw?: RequestHandler[] | {
    handlers: RequestHandler[] | Record<string, RequestHandler | RequestHandler[]>;
  };
}

Usage Examples:

import { http, HttpResponse } from "msw";

// Array format (deprecated but supported)
export const StoryWithArray: StoryObj = {
  parameters: {
    msw: [
      http.get("/api/data", () => HttpResponse.json({ id: 1 })),
    ],
  },
};

// Object format (recommended)
export const StoryWithObject: StoryObj = {
  parameters: {
    msw: {
      handlers: [
        http.get("/api/data", () => HttpResponse.json({ id: 1 })),
      ],
    },
  },
};

// Named handlers (advanced)
export const StoryWithNamedHandlers: StoryObj = {
  parameters: {
    msw: {
      handlers: {
        users: [
          http.get("/api/users", () => HttpResponse.json([])),
        ],
        posts: [
          http.get("/api/posts", () => HttpResponse.json([])),
        ],
      },
    },
  },
};

Apply Request Handlers Function

Internal function for applying request handlers to the MSW instance. This is exported for backward compatibility but should generally not be used directly.

/**
 * Apply MSW request handlers to the current worker/server
 * @param handlersListOrObject - Handlers in array or object format
 */
function applyRequestHandlers(
  handlersListOrObject: Context['parameters']['msw']
): void;

Usage Example (not recommended for direct use):

import { applyRequestHandlers } from "msw-storybook-addon";
import { http, HttpResponse } from "msw";

// Apply handlers manually (use mswLoader instead)
applyRequestHandlers({
  handlers: [
    http.get("/api/test", () => HttpResponse.json({ test: true })),
  ],
});

Parameter Formats

Recommended Object Format

The recommended format uses an object with a handlers property:

parameters: {
  msw: {
    handlers: [
      // Array of RequestHandler objects
    ]
  }
}

Named Handlers Format

For complex stories, you can organize handlers by name:

parameters: {
  msw: {
    handlers: {
      api: [
        http.get("/api/data", () => HttpResponse.json({})),
      ],
      auth: [
        http.post("/auth/login", () => HttpResponse.json({ token: "abc" })),
      ],
    }
  }
}

Legacy Array Format (Deprecated)

The array format is deprecated but still supported:

parameters: {
  msw: [
    // Array of RequestHandler objects (deprecated)
  ]
}

Handler Lifecycle

  1. Story Load: When a story loads, mswLoader is called
  2. Wait for MSW: Loader waits for MSW to be ready via waitForMswReady()
  3. Reset Handlers: Any existing handlers are cleared with api.resetHandlers()
  4. Apply New Handlers: Story-specific handlers are applied with api.use(...handlers)
  5. Story Render: Story renders with new handlers active

Error Handling

The addon includes built-in error handling:

  • Missing MSW: If MSW is not initialized, handlers will not be applied
  • Invalid Handlers: Malformed handler configurations are filtered out
  • Deprecation Warnings: Using deprecated formats shows console warnings

Integration with MSW

The addon works seamlessly with MSW's request handlers:

import { http, HttpResponse, graphql } from "msw";

// REST API mocking
http.get("/api/users", () => {
  return HttpResponse.json([{ id: 1, name: "Alice" }]);
});

// GraphQL mocking
graphql.query("GetUser", () => {
  return HttpResponse.json({
    data: { user: { id: 1, name: "Alice" } },
  });
});

// Error responses
http.get("/api/error", () => {
  return new HttpResponse(null, { status: 500 });
});

Storybook Configuration

Complete setup example for .storybook/preview.ts:

import { initialize, mswLoader } from "msw-storybook-addon";

// Initialize MSW
initialize();

// Configure preview
const preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
  loaders: [mswLoader],
};

export default preview;

docs

index.md

initialization.md

storybook-integration.md

worker-management.md

tile.json