{"id":14985489,"url":"https://github.com/mswjs/msw-storybook-addon","last_synced_at":"2025-05-14T06:12:50.641Z","repository":{"id":37939873,"uuid":"324230741","full_name":"mswjs/msw-storybook-addon","owner":"mswjs","description":"Mock API requests in Storybook with Mock Service Worker.","archived":false,"fork":false,"pushed_at":"2024-11-05T12:45:02.000Z","size":5981,"stargazers_count":447,"open_issues_count":19,"forks_count":40,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-11T19:55:30.513Z","etag":null,"topics":["addon","api","mock","msw","story","storybook","worker"],"latest_commit_sha":null,"homepage":"https://msw-sb.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mswjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-12-24T20:22:12.000Z","updated_at":"2025-04-10T22:47:59.000Z","dependencies_parsed_at":"2024-04-15T15:56:42.853Z","dependency_job_id":"85391792-7f96-47fe-aca7-6c975919c6e1","html_url":"https://github.com/mswjs/msw-storybook-addon","commit_stats":{"total_commits":93,"total_committers":21,"mean_commits":4.428571428571429,"dds":0.6451612903225806,"last_synced_commit":"88676082fa8209e0d77e8f62c03557c740ada2d2"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mswjs%2Fmsw-storybook-addon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mswjs%2Fmsw-storybook-addon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mswjs%2Fmsw-storybook-addon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mswjs%2Fmsw-storybook-addon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mswjs","download_url":"https://codeload.github.com/mswjs/msw-storybook-addon/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254080740,"owners_count":22011487,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["addon","api","mock","msw","story","storybook","worker"],"created_at":"2024-09-24T14:11:04.612Z","updated_at":"2025-05-14T06:12:50.623Z","avatar_url":"https://github.com/mswjs.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/1671563/144888802-84346d8f-77c9-4377-98c7-4b0364797978.png\" width=\"200\"\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003eMSW Storybook Addon\u003c/h1\u003e\n\n## Features\n\n- Mock Rest and GraphQL requests right inside your story.\n- Document how a component behaves in various scenarios.\n- Get a11y, snapshot and visual tests using other addons for free.\n\n[Full documentation and live demos](https://msw-sb.vercel.app/)\n\n## Installing and Setup\n\n### Install MSW and the addon\n\nWith npm:\n\n```sh\nnpm i msw msw-storybook-addon -D\n```\n\nOr with yarn:\n\n```sh\nyarn add msw msw-storybook-addon -D\n```\n\n### Generate service worker for MSW in your public folder.\n\n_If you already use MSW in your project, you have likely done this before so you can skip this step._\n\n```sh\nnpx msw init public/\n```\n\nRefer to the [MSW official guide](https://mswjs.io/docs/integrations/browser) for framework specific paths if you don't use `public`.\n\n### Configure the addon\n\nEnable MSW in Storybook by initializing MSW and providing the MSW loader in `./storybook/preview.js`:\n\n```ts\nimport { initialize, mswLoader } from 'msw-storybook-addon'\n\n// Initialize MSW\ninitialize()\n\nconst preview = {\n  parameters: {\n    // your other code...\n  },\n  // Provide the MSW addon loader globally\n  loaders: [mswLoader],\n}\n\nexport default preview\n```\n\n### Start Storybook\n\nWhen running Storybook, you have to serve the `public` folder as an asset to Storybook, so that MSW is included, otherwise it will not be available in the browser.\n\nThis means you should set the `staticDirs` field in the Storybook main config file. Refer to [the docs](https://storybook.js.org/docs/configure/images-and-assets#serving-static-files-via-storybook-configuration) if needed.\n\n```sh\nnpm run storybook\n```\n\n## Usage\n\nYou can pass request handlers (https://mswjs.io/docs/concepts/request-handler) into the `handlers` property of the `msw` parameter. This is commonly an array of handlers.\n\n```ts\nimport { http, HttpResponse } from 'msw'\n\nexport const SuccessBehavior = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('/user', () =\u003e {\n          return HttpResponse.json({\n            firstName: 'Neil',\n            lastName: 'Maverick',\n          })\n        }),\n      ],\n    },\n  },\n}\n```\n\n### Advanced Usage\n\n#### Composing request handlers\n\nThe `handlers` property can also be an object where the keys are either arrays of handlers or a handler itself. This enables you to inherit (and optionally overwrite/disable) handlers from preview.js using [parameter inheritance](https://storybook.js.org/docs/writing-stories/parameters#rules-of-parameter-inheritance):\n\n```ts\ntype MswParameter = {\n  handlers: RequestHandler[] | Record\u003cstring, RequestHandler | RequestHandler[]\u003e\n}\n```\n\nSuppose you have an application where almost every component needs to mock requests to `/login` and `/logout` the same way.\nYou can set global MSW handlers in preview.js for those requests and bundle them into a property called `auth`, for example:\n\n```ts\n//preview.ts\nimport { http, HttpResponse } from 'msw'\n\n// These handlers will be applied in every story\nexport const parameters = {\n  msw: {\n    handlers: {\n      auth: [\n        http.get('/login', () =\u003e {\n          return HttpResponse.json({\n            success: true,\n          })\n        }),\n        http.get('/logout', () =\u003e {\n          return HttpResponse.json({\n            success: true,\n          })\n        }),\n      ],\n    },\n  },\n}\n```\n\nThen, you can use other handlers in your individual story. Storybook will merge both global handlers and story handlers:\n\n```ts\nimport { http, HttpResponse } from 'msw'\n\n// This story will include the auth handlers from .storybook/preview.ts and profile handlers\nexport const SuccessBehavior = {\n  parameters: {\n    msw: {\n      handlers: {\n        profile: http.get('/profile', () =\u003e {\n          return HttpResponse.json({\n            firstName: 'Neil',\n            lastName: 'Maverick',\n          })\n        }),\n      },\n    },\n  },\n}\n```\n\nNow suppose you want to ovewrite the global handlers for auth. All you have to do is set them again in your story and these values will take precedence:\n\n```ts\nimport { http, HttpResponse } from 'msw'\n\n// This story will overwrite the auth handlers from preview.ts\nexport const FailureBehavior = {\n  parameters: {\n    msw: {\n      handlers: {\n        auth: http.get('/login', () =\u003e {\n          return HttpResponse.json(null, { status: 403 })\n        }),\n      },\n    },\n  },\n}\n```\n\nWhat if you want to disable global handlers? All you have to do is set them as null and they will be ignored for your story:\n\n```ts\nimport { http, HttpResponse } from 'msw'\n\n// This story will disable the auth handlers from preview.ts\nexport const NoAuthBehavior = {\n  parameters: {\n    msw: {\n      handlers: {\n        auth: null,\n        others: [\n          http.get('/numbers', () =\u003e {\n            return HttpResponse.json([1, 2, 3])\n          }),\n          http.get('/strings', () =\u003e {\n            return HttpResponse.json(['a', 'b', 'c'])\n          }),\n        ],\n      },\n    },\n  },\n}\n```\n\n#### Configuring MSW\n\n`msw-storybook-addon` starts MSW with default configuration. `initialize` takes two arguments:\n\n- `options`: this gets passed down to [`worker.start()`](https://mswjs.io/docs/api/setup-worker/start) when in the browser or [`server.listen()`](https://mswjs.io/docs/api/setup-server/listen) when in Node, so the same types are expected.\n- `initialHandlers`: a `RequestHandler[]` type, this array is spread to either [`setupWorker()`](https://mswjs.io/docs/api/setup-worker) when in the browser or [`setupServer()`](https://mswjs.io/docs/api/setup-server) when in Node.\n\nA common example is to configure the [onUnhandledRequest](https://mswjs.io/docs/api/setup-worker/start#onunhandledrequest) behavior, as MSW logs a warning in case there are requests which were not handled.\n\nIf you want MSW to bypass unhandled requests and not do anything:\n\n```ts\n// .storybook/preview.ts\nimport { initialize } from 'msw-storybook-addon'\n\ninitialize({\n  onUnhandledRequest: 'bypass',\n})\n```\n\nIf you want to warn a helpful message in case stories make requests that should be handled but are not:\n\n```ts\n// .storybook/preview.ts\nimport { initialize } from 'msw-storybook-addon'\n\ninitialize({\n  onUnhandledRequest: ({ url, method }) =\u003e {\n    const pathname = new URL(url).pathname\n    if (pathname.startsWith('/my-specific-api-path')) {\n      console.error(`Unhandled ${method} request to ${url}.\n\n        This exception has been only logged in the console, however, it's strongly recommended to resolve this error as you don't want unmocked data in Storybook stories.\n\n        If you wish to mock an error response, please refer to this guide: https://mswjs.io/docs/recipes/mocking-error-responses\n      `)\n    }\n  },\n})\n```\n\nAlthough [composing handlers](#composing-request-handlers) is possible, that relies on Storybook's merging logic, which **only works when the handlers in your story's parameters are objects and not arrays**. To get around this limitation, you can pass initial request handlers directly the `initialize` function as a second argument.\n\n```ts\n// .storybook/preview.ts\nimport { http, HttpResponse } from 'msw'\nimport { initialize } from 'msw-storybook-addon'\n\ninitialize({}, [\n  http.get('/numbers', () =\u003e {\n    return HttpResponse.json([1, 2, 3])\n  }),\n  http.get('/strings', () =\u003e {\n    return HttpResponse.json(['a', 'b', 'c'])\n  }),\n])\n```\n\n#### Using the addon in Node.js with Portable Stories\n\nIf you're using [portable stories](https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest), you need to make sure the MSW loaders are applied correctly.\n\n### Storybook 8.2 or higher\n\nIf you [set up the project annotations](https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations) correctly, by calling the `play` function of your story, the MSW loaders will be applied automatically:\n\n```ts\nimport { composeStories } from '@storybook/react'\nimport * as stories from './MyComponent.stories'\n\nconst { Success } = composeStories(stories)\n\ntest('\u003cSuccess /\u003e', async() =\u003e {\n  // The MSW loaders are applied automatically via the play function\n  await Success.play()\n})\n```\n\n### Storybook \u003c 8.2\n\nYou do so by calling the `applyRequestHandlers`  helper before rendering your story:\n\n```ts\nimport { applyRequestHandlers } from 'msw-storybook-addon'\nimport { composeStories } from '@storybook/react'\nimport * as stories from './MyComponent.stories'\n\nconst { Success } = composeStories(stories)\n\ntest('\u003cSuccess /\u003e', async() =\u003e {\n  // 👇 Crucial step, so that the MSW loaders are applied\n  await applyRequestHandlers(Success.parameters.msw)\n  render(\u003cSuccess /\u003e)\n})\n```\n\n\u003e Note:\n\u003e The `applyRequestHandlers` utility should be an internal detail that is called automatically by the portable stories, however as it's not possible in Storybook 7, it's exported by the addon. It will be removed in upcoming releases, so it is recommended that you upgrade to Storybook 8 when possible.\n\n### Troubleshooting\n\n#### MSW is interfering with HMR (Hot Module Replacement)\n\nIf you're experiencing issues like `[MSW] Failed to mock a \"GET\" request to \"http://localhost:6006/4cb31fa2eee22cf5b32f.hot-update.json\"` in the console, it's likely that MSW is interfering with HMR. This is not common and it seems to only happen in Webpack projects, but if it happens to you, you can follow the steps in this issue to fix it:\n\nhttps://github.com/mswjs/msw-storybook-addon/issues/36#issuecomment-1496150729\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmswjs%2Fmsw-storybook-addon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmswjs%2Fmsw-storybook-addon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmswjs%2Fmsw-storybook-addon/lists"}