{"_id":"@compare-ui/storybook","name":"@compare-ui/storybook","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@compare-ui/storybook","version":"0.1.0","description":"Storybook helpers for design-comparison workflows.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/artandrey/desing-comparison.git","directory":"packages/storybook"},"bugs":{"url":"https://github.com/artandrey/desing-comparison/issues"},"homepage":"https://github.com/artandrey/desing-comparison#readme","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./playwright":{"types":"./dist/playwright.d.ts","import":"./dist/playwright.mjs","require":"./dist/playwright.cjs"}},"main":"dist/index.cjs","module":"dist/index.mjs","types":"dist/index.d.ts","publishConfig":{"access":"public"},"dependencies":{"@compare-ui/runner":"0.1.0"},"peerDependencies":{"@playwright/test":">=1.40.0 <2"},"devDependencies":{"@playwright/test":"^1.58.2","rollup":"^4.50.0","rollup-plugin-delete":"^3.0.1","rollup-plugin-dts":"^6.2.3","rollup-plugin-esbuild":"^6.2.1","tslib":"^2.8.1","@compare-ui/core":"0.1.0","@compare-ui/runner":"0.1.0"},"scripts":{"build":"rollup -c rollup.config.mjs","test":"vitest run --config vitest.config.mts"},"_id":"@compare-ui/storybook@0.1.0","_integrity":"sha512-7IZbumfNtSTltIWl7ASPdfnvOkhfiVOjPukWTeGKdNbFHHro/Y1HFLdEUWlPa9Uub4yJzp5RnFxOL8SGBIvxEw==","_resolved":"/tmp/ac4649f23035d12820c7ffab34c69809/compare-ui-storybook-0.1.0.tgz","_from":"file:compare-ui-storybook-0.1.0.tgz","_nodeVersion":"21.7.3","_npmVersion":"10.5.0","dist":{"integrity":"sha512-7IZbumfNtSTltIWl7ASPdfnvOkhfiVOjPukWTeGKdNbFHHro/Y1HFLdEUWlPa9Uub4yJzp5RnFxOL8SGBIvxEw==","shasum":"ff80a3f7d5c9063c08cb5cd929fb719f03b193de","tarball":"https://registry.npmjs.org/@compare-ui/storybook/-/storybook-0.1.0.tgz","fileCount":10,"unpackedSize":62406,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCID+j7tSrqbCWJBceIAZ5xH67rX2mhWtjCT5dBOE9rLImAiEA19IIbKkkGVW6u2AR3JU+8ezzI07/OAvRo3ADC9sQpA4="}]},"_npmUser":{"name":"artandrii","email":"artandrey7777@gmail.com"},"directories":{},"maintainers":[{"name":"artandrii","email":"artandrey7777@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/storybook_0.1.0_1780327632005_0.7864455787681028"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T15:27:11.805Z","0.1.0":"2026-06-01T15:27:12.161Z","modified":"2026-06-01T15:27:12.466Z"},"maintainers":[{"name":"artandrii","email":"artandrey7777@gmail.com"}],"description":"Storybook helpers for design-comparison workflows.","homepage":"https://github.com/artandrey/desing-comparison#readme","repository":{"type":"git","url":"git+https://github.com/artandrey/desing-comparison.git","directory":"packages/storybook"},"bugs":{"url":"https://github.com/artandrey/desing-comparison/issues"},"license":"MIT","readme":"# `@compare-ui/storybook`\n\nStorybook helpers for design-comparison workflows.\n\nThis package lets you:\n\n- define design-comparison metadata directly on Storybook stories\n- register Playwright tests from Storybook stories\n- turn one story into multiple design-comparison cases\n\n## Installation\n\n```bash\npnpm add @compare-ui/storybook @compare-ui/runner @compare-ui/core\npnpm add @playwright/test\n```\n\nThis package assumes your app already has its normal Storybook packages installed.\n\n## What it exports\n\nMain public APIs:\n\n- `defineStorybookDesignComparison<TArgs>(...)`\n- `registerStorybookDesignComparisonTests(...)` from `@compare-ui/storybook/playwright`\n\nMain public types:\n\n- `StorybookDesignComparisonConfig<TArgs>`\n- `StorybookDesignComparisonCase<TArgs>`\n\nThe published public entrypoints are:\n\n- `@compare-ui/storybook`\n- `@compare-ui/storybook/playwright`\n\n## Story metadata\n\nUse `defineStorybookDesignComparison<TArgs>(...)` inside `parameters.designComparison`.\n\nExample:\n\n```tsx\nimport { artifactRefs, gridRowArtifact, overlayArtifact } from '@compare-ui/core/config';\nimport { defineStorybookDesignComparison } from '@compare-ui/storybook';\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { InteractiveExampleScreen } from './interactive-example-screen';\n\ntype ExampleStoryArgs = {\n  title: string;\n  mode: 'default' | 'fullScreen';\n};\n\nconst meta = {\n  title: 'Screens/ExampleScreen',\n  render: (args: ExampleStoryArgs) => <InteractiveExampleScreen {...args} />,\n} satisfies Meta<ExampleStoryArgs>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const My: Story = {\n  args: {\n    title: 'Interactive Screen 123',\n    mode: 'default',\n  },\n  parameters: {\n    designComparison: defineStorybookDesignComparison<ExampleStoryArgs>({\n      compare: {\n        threshold: 0.1,\n        acceptance: {\n          maxDiffPercent: 0.5,\n        },\n      },\n      artifacts: [\n        overlayArtifact(),\n        gridRowArtifact({\n          items: [artifactRefs.overlay, artifactRefs.actual, artifactRefs.reference],\n          size: 16,\n          lineWidth: 2,\n        }),\n      ],\n      cases: [\n        {\n          name: 'default',\n          args: {\n            mode: 'default',\n          },\n          reference: {\n            type: 'fs',\n            path: './tests/fixtures/example-screen-default.png',\n          },\n        },\n        {\n          name: 'full-screen',\n          args: {\n            mode: 'fullScreen',\n          },\n          reference: {\n            type: 'fs',\n            path: './tests/fixtures/example-screen-full-screen.png',\n            crop: {\n              bottom: 20,\n            },\n          },\n        },\n      ],\n    }),\n  },\n};\n```\n\n## Cases\n\nEach story may define one or more comparison cases.\n\nThe shared story-level config may also define capture defaults for all cases:\n\n- `targetSelector`\n- `settleDelayMs`\n- `strictRenderHealth`\n- `surfaceBackground`\n\nEach case can provide:\n\n- `name`\n- `args`\n- `reference`\n- `viewport`\n- `targetSelector`\n- `settleDelayMs`\n- `strictRenderHealth`\n- `surfaceBackground`\n- optional compare overrides\n- optional artifact overrides\n- optional reporting overrides\n\n`args` are typed as `Partial<TArgs>`, where `TArgs` is the same args type used by the story.\n\nThat means one story can describe multiple comparison states without creating multiple story exports.\n\nWhen both shared config and case config provide the same capture option, the case value wins.\n\n## Playwright package setup\n\nThis package uses the consuming app's Playwright installation.\n\nSupported peer range:\n\n- `@playwright/test >=1.40.0 <2`\n\nIf your workspace also uses Playwright component testing, keep these packages on the exact same version:\n\n- `@playwright/test`\n- `@playwright/experimental-ct-react`\n\nThis is a workspace package setup requirement. The package docs and workspace validation should keep these versions aligned; the Storybook helper does not need extra runtime enforcement for this.\n\nThe workspace also runs tarball compatibility smoke tests in CI so we keep validating the published package against more than one consumer dependency shape.\n\n## TypeScript resolver compatibility\n\nThese package exports rely on modern `exports` resolution.\n\nRecommended `tsconfig.json` resolver modes:\n\n- `moduleResolution: \"bundler\"`\n- `moduleResolution: \"node16\"`\n- `moduleResolution: \"nodenext\"`\n\nOlder `moduleResolution: \"node\"` setups may still work at runtime but often produce TypeScript friction for subpath imports such as:\n\n- `@compare-ui/storybook/playwright`\n- `@compare-ui/core/config`\n\nIf TypeScript reports import-resolution errors for those subpaths, switch to one of the recommended resolver modes above.\n\n## Args support\n\nStorybook comparison cases should support normal JSON-serializable Storybook args.\n\nThat includes:\n\n- strings\n- numbers\n- booleans\n- `null`\n- arrays\n- nested objects\n\nExample:\n\n```ts\nargs: {\n  title: 'Interactive Screen 123',\n  media: {\n    src: '/hero.png',\n    alt: 'Hero image',\n  },\n  products: [\n    { id: '1', name: 'One' },\n    { id: '2', name: 'Two' },\n  ],\n  selectedProductId: null,\n}\n```\n\nThe Playwright helper applies supported args through Storybook's preview channel before capture so the story is rendered in the intended state without relying on a primitive-only args contract.\n\nFor values that are not safely serializable into Storybook args, such as:\n\n- `undefined`\n- functions\n- JSX elements\n- symbols\n- bigint\n- dates\n- maps\n- sets\n- class instances\n- cyclic objects\n\nthe recommended Storybook approach is to use `argTypes.mapping` or another story-level indirection instead of passing those values directly through `cases[].args`.\n\n## Registering tests\n\nUse `registerStorybookDesignComparisonTests(...)` inside a Playwright test file.\n\nRecommended location:\n\n- `tests/storybook-design-comparison.spec.ts`\n\nExample:\n\n```ts\nimport { registerStorybookDesignComparisonTests } from '@compare-ui/storybook/playwright';\n\nimport * as exampleScreenStories from '../src/example-screen.stories';\n\nregisterStorybookDesignComparisonTests({\n  storybookUrl: 'http://127.0.0.1:6007',\n  storyModules: [exampleScreenStories],\n});\n```\n\nThe helper should:\n\n- inspect the provided story modules\n- find stories that define `parameters.designComparison`\n- create one Playwright test per comparison case\n\nComparison execution follows the shared `@compare-ui/runner` and `@compare-ui/core` pipeline.\n\nThat means image-processing behavior such as:\n\n- crop handling\n- explicit size normalization\n- explicit transparent-background flattening\n\ncomes from the shared comparison flow rather than from Storybook-specific image rules in this package.\n\n## Capture target\n\nBy default, Storybook comparisons capture `#storybook-root`.\n\nUse `targetSelector` when the comparison should capture a narrower element inside the story canvas.\n\nExample:\n\n```ts\n{\n  name: 'card',\n  targetSelector: '[data-testid=\"card-root\"]',\n  reference: {\n    type: 'fs',\n    path: './tests/fixtures/card.png',\n  },\n}\n```\n\nIf `targetSelector` is omitted, the default capture target remains `#storybook-root`.\n\nShared config may also define a default `targetSelector` for all cases in the story. A case-level `targetSelector` overrides that shared value.\n\nSelector capture uses an integer-snapped clip rectangle internally so fractional layout positions do not drift by a pixel between runs.\n\n## Surface background\n\nUse `surfaceBackground` when one logical surface color should drive:\n\n- the Storybook capture surface\n- transparent-PNG flattening before compare, when `flattenBackground` is not already configured explicitly\n- generated `grid-row` or `join` artifact backgrounds, when those artifact instructions do not already define one\n\nExample:\n\n```ts\ndefineStorybookDesignComparison({\n  surfaceBackground: [17, 17, 17, 255],\n  cases: [\n    {\n      name: 'card',\n      targetSelector: '[data-testid=\"card-root\"]',\n      reference: {\n        type: 'fs',\n        path: './tests/fixtures/card.png',\n      },\n    },\n  ],\n})\n```\n\nCase-level `surfaceBackground` overrides the shared story-level value.\n\n## Viewport handling\n\nWhen a case defines `viewport`, the helper should apply that size to the browser page before taking the screenshot.\n\nThat means `viewport` is capture behavior, not reporting metadata only.\n\nWhen the capture target is the default `#storybook-root`, the helper also constrains the Storybook root to that viewport size before capture.\n\nSo with the default root capture:\n\n- the page viewport is set to `viewport`\n- `#storybook-root` is sized to match it\n- the resulting screenshot is intended to represent a fixed viewport-sized surface instead of a content-height root\n\nWhen a case uses a custom `targetSelector`, the page viewport is still applied, but the final screenshot dimensions follow the selected element.\n\nExample:\n\n```ts\n{\n  name: 'mobile',\n  viewport: { x: 361, y: 423 },\n  reference: {\n    type: 'fs',\n    path: './tests/fixtures/mobile.png',\n  },\n}\n```\n\n## Storybook URL\n\n`registerStorybookDesignComparisonTests(...)` should support this resolution order:\n\n1. explicit `storybookUrl`\n2. `process.env.STORYBOOK_URL`\n3. default `http://127.0.0.1:6006`\n\nThat means `storybookUrl` may be omitted when the default local Storybook port is being used.\n\nExample with the default:\n\n```ts\nregisterStorybookDesignComparisonTests({\n  storyModules: [exampleScreenStories],\n});\n```\n\nExample with an override:\n\n```ts\nregisterStorybookDesignComparisonTests({\n  storybookUrl: 'http://127.0.0.1:6007',\n  storyModules: [exampleScreenStories],\n});\n```\n\n## Starting Storybook\n\nStorybook should already be running before the tests execute.\n\nTypical local workflow:\n\n1. start Storybook\n2. run the Playwright Storybook comparison tests\n\nTypical CI workflow:\n\n1. build or serve Storybook\n2. run the Playwright Storybook comparison tests\n\nThis package should not start Storybook for you. It expects a reachable Storybook URL.\n\n## Readiness model\n\nThe helper should capture only after the story is actually ready for comparison.\n\nExpected flow:\n\n1. navigate to the story iframe with normal document readiness\n2. apply `viewport` when provided\n3. wait for Storybook render and `play` completion through Storybook lifecycle events\n4. apply supported `args` when the case defines them\n5. resolve the capture target\n6. wait for the target to exist and be visible\n7. apply `settleDelayMs` when provided\n8. capture the screenshot\n\nThe readiness model should follow Storybook lifecycle/events plus explicit settling. It should not rely on `networkidle`.\n\n## Render health\n\nUse `strictRenderHealth` when a case should fail before compare if the preview is obviously unhealthy.\n\nWhen enabled, the helper fails early on signals such as:\n\n- page runtime errors\n- failed network requests for important preview assets\n- HTTP error responses for scripts, stylesheets, images, and fetch/XHR requests\n- broken images inside the capture target\n- zero-size capture targets\n\nExample:\n\n```ts\n{\n  name: 'strict-preview',\n  strictRenderHealth: true,\n  reference: {\n    type: 'fs',\n    path: './tests/fixtures/strict-preview.png',\n  },\n}\n```\n\nThis stays opt-in so existing comparison flows are not forced into a stricter failure policy unless you want that behavior.\n\n## Story ids\n\nThe package resolves Storybook story ids from Storybook metadata.\n\nYou do not need to hardcode ids like:\n\n- `screens-examplescreen--with-play-function`\n\nThis keeps tests aligned with Storybook's generated story ids.\n\n## `play` functions\n\nStories can use normal Storybook `play` functions.\n\nThe generated tests should take the screenshot after the story has rendered and its `play` function has completed.\n\nWhen a case needs extra visual settling after `play`, provide `settleDelayMs`.\n\nExample:\n\n```ts\n{\n  name: 'animated-state',\n  settleDelayMs: 150,\n  reference: {\n    type: 'fs',\n    path: './tests/fixtures/animated-state.png',\n  },\n}\n```\n\nThat means the same story can define:\n\n- render state\n- interactive state\n- design-comparison metadata\n\nin one place.\n\nShared config may also define a default `settleDelayMs` for all cases in the story. A case-level `settleDelayMs` overrides that shared value.\n\n## Focusing on one story\n\nGenerated test names include:\n\n- the Storybook title\n- the Storybook story name\n- the design-comparison case name\n\nExample generated test name:\n\n```text\n[design-comparison] Screens/ExampleScreen :: My :: full-screen\n```\n\nThe recommended workflow is to use Playwright's normal `--grep` support.\n\nExample:\n\n```bash\npnpm test:storybook-design-comparison -- --grep \"ExampleScreen\"\n```\n\nor:\n\n```bash\npnpm test:storybook-design-comparison -- --grep \"full-screen\"\n```\n\nThe most reliable `--grep` values are:\n\n- part of the Storybook title, such as `ExampleScreen`\n- the Storybook story name, such as `My`\n- the case name, such as `full-screen`\n\n## Typical workflow\n\n1. Create or update a Storybook story.\n2. Add `parameters.designComparison`.\n3. Define one or more cases.\n4. Register the story module in a Storybook design-comparison test file.\n5. Run the Playwright tests.\n\n## Recipe: Storybook Story With A Local Reference PNG\n\nStory file:\n\n```tsx\nimport { defineStorybookDesignComparison } from '@compare-ui/storybook';\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ExampleScreen } from './example-screen';\n\ntype ExampleStoryArgs = {\n  title: string;\n};\n\nconst meta = {\n  title: 'Screens/ExampleScreen',\n  render: (args: ExampleStoryArgs) => <ExampleScreen {...args} />,\n} satisfies Meta<ExampleStoryArgs>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {\n    title: 'Interactive Screen 123',\n  },\n  parameters: {\n    designComparison: defineStorybookDesignComparison<ExampleStoryArgs>({\n      cases: [\n        {\n          name: 'default',\n          reference: {\n            type: 'fs',\n            path: './tests/fixtures/example-screen-reference.png',\n          },\n        },\n      ],\n    }),\n  },\n};\n```\n\nPlaywright spec:\n\n```ts\nimport { registerStorybookDesignComparisonTests } from '@compare-ui/storybook/playwright';\n\nimport * as exampleScreenStories from '../src/example-screen.stories';\n\nregisterStorybookDesignComparisonTests({\n  storyModules: [exampleScreenStories],\n});\n```\n\nWorkflow:\n\n1. start Storybook\n2. run the Playwright Storybook comparison spec\n\n## Recipe: Storybook Story With A Figma Reference\n\nBootstrap the Figma resolver once before registering the Storybook comparison tests.\n\nPlaywright spec:\n\n```ts\nimport '@compare-ui/figma';\nimport { registerFigmaFromEnv } from '@compare-ui/figma';\nimport { registerStorybookDesignComparisonTests } from '@compare-ui/storybook/playwright';\n\nimport * as exampleScreenStories from '../src/example-screen.stories';\n\nregisterFigmaFromEnv();\n\nregisterStorybookDesignComparisonTests({\n  storyModules: [exampleScreenStories],\n});\n```\n\nIf TypeScript does not recognize `type: 'figma'`, keep the `import '@compare-ui/figma';` line in a setup module or in this spec so the augmentation is included in the program.\n\nStory file:\n\n```tsx\nimport { defineStorybookDesignComparison } from '@compare-ui/storybook';\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ExampleScreen } from './example-screen';\n\ntype ExampleStoryArgs = {\n  title: string;\n};\n\nconst meta = {\n  title: 'Screens/ExampleScreen',\n  render: (args: ExampleStoryArgs) => <ExampleScreen {...args} />,\n} satisfies Meta<ExampleStoryArgs>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {\n    title: 'Interactive Screen 123',\n  },\n  parameters: {\n    designComparison: defineStorybookDesignComparison<ExampleStoryArgs>({\n      cases: [\n        {\n          name: 'figma-reference',\n          reference: {\n            type: 'figma',\n            url: 'https://figma.com/design/abc123/Example?node-id=2020-1617',\n            crop: {\n              bottom: 20,\n            },\n          },\n        },\n      ],\n    }),\n  },\n};\n```\n\nWorkflow:\n\n1. start Storybook\n2. register the Figma resolver once in the test bootstrap or spec file\n3. run the Playwright Storybook comparison spec\n\n## Notes\n\n- This package is Storybook-specific.\n- Import `defineStorybookDesignComparison(...)` from `@compare-ui/storybook`.\n- Import `registerStorybookDesignComparisonTests(...)` from `@compare-ui/storybook/playwright`.\n- It is intended to work with Storybook stories plus Playwright-based execution.\n- Comparison execution itself is handled by lower-level packages.\n- `cases[].args` should follow Storybook's JSON-serializable args model.\n- supported case args are applied through Storybook's preview-channel update flow before capture.\n- image-processing policy stays in the shared core/runner flow.\n- `strictRenderHealth` is opt-in and is intended for teams that want preview-health failures before compare.\n- `surfaceBackground` is the high-level Storybook knob for keeping capture background, flattening, and composite artifact background aligned.\n","readmeFilename":"README.md","_rev":"1-3f0f0af7acb277efd9749c214c7180da"}