storybook-stories について
UI コンポーネントを分離して文書化・テストするフロントエンド開発者向けの Storybook ガイドスキルです。CSF3 のストーリー、操作テスト、アクセシビリティ検証、ビジュアル回帰に重点を置きます。
主な機能
- 01CSF3 のストーリーパターン
- 02play 関数による操作テスト
- 03コンポーネントのアクセシビリティ検査
- 04自動ドキュメントとコントロール
- 05Chromatic のビジュアルスナップショット
活用シーン
- 01ライブ例を使ったコンポーネント文書化
- 02コンポーネント操作のテスト
- 03アクセシブルな名前の検証
- 04ビジュアル回帰失敗の調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ oakoss/ agent-skills --skill storybook-storiesインストール後、Claude Code で/storybook-storiesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/component-documentation.mdinteraction-tests.mdstory-writing.mdvisual-testing.md詳細
Storybook ストーリー
概要
Storybook は、UI コンポーネントを分離して構築するためのフロントエンドワークショップです。ストーリーは Component Story Format 3(CSF3)で記述します。CSF3 では args を使ったオブジェクト構文により、型安全なコンポーネントのドキュメント作成とテストができます。
使用する場面: ライブサンプル付きのコンポーネントドキュメント、play 関数を使ったインタラクションテスト、ビジュアルリグレッションテスト、アクセシビリティの検証、デザインシステムの保守、コンポーネントの分離開発。
使用しない場面: エンドツーエンドテスト(Playwright/Cypress を使用)、API 統合テスト(Vitest/Jest を使用)、アプリケーション全体のテスト(ブラウザー自動化を使用)、パフォーマンステスト(Lighthouse/WebPageTest を使用)。
クイックリファレンス
| パターン | API | 主なポイント |
|---|---|---|
| 基本的なストーリー | export const Default: Story = { args } | 単一のシンプルなコンポーネントには args を使用します |
| 複雑なストーリー | export const Example: Story = { render } | 複数コンポーネントのレイアウトには render を使用します |
| Meta の設定 | const meta = { component, args } satisfies Meta | デフォルト値と argTypes を定義します |
| インタラクションテスト | play: async ({ canvas, userEvent, args }) | canvas と userEvent が直接提供されます |
| ユーザーインタラクション | await userEvent.click(element) | userEvent のメソッドは必ず await します |
| 要素のクエリ | canvas.getByRole('button') | ほかのクエリより getByRole を優先します |
| アサーション | await expect(args.onPress).toHaveBeenCalled() | Storybook のテスト用アサーションを使用します |
| beforeEach フック | beforeEach: async ({ args }) => {} | ストーリーのレンダリング前にモックをセットアップします |
| play の合成 | await OtherStory.play?.(context) | ストーリー間でセットアップを再利用します |
| Autodocs | tags: ['autodocs'] | ドキュメントを自動生成します |
| Controls のカスタマイズ | argTypes: { variant: { control: 'select' } } | コントロールパネルを設定します |
| デコレーター | decorators: [withTheme] | ラッパーやコンテキストプロバイダーを追加します |
| パラメーター | parameters: { layout: 'centered' } | ストーリーごとにアドオンの動作を設定します |
| Chromatic スナップショット | parameters: { chromatic: { delay: 300 } } | ビジュアルリグレッションのキャプチャを制御します |
| スナップショットの無効化 | parameters: { chromatic: { disableSnapshot: true } } | ビジュアルテストでストーリーをスキップします |
| A11y テスト | await expect(button).toHaveAccessibleName() | アクセシブルなラベルを検証します |
よくある間違い
| 間違い | 正しいパターン |
|---|---|
| 複数のコンポーネントで構成されるレイアウトで args を使う | 複雑な構成には render を使います |
| userEvent メソッドを await しない | 常に await します:await userEvent.click(button) |
| 手動で within(canvasElement) を使う | play コンテキストから canvas を直接分割代入します |
| 最初に getByTestId を使う | getByRole、getByLabelText、getByText を優先します |
| meta レベルでデフォルトの args がない | プレースホルダーのコントロールを防ぐため、meta に args を追加します |
| シリアライズできない props を公開する | argTypes で className、ref、style を無効にします |
| play 関数を合成しない | await BaseStory.play?.(context) でセットアップを再利用します |
| コールバックをモックし忘れる | イベントハンドラーには fn() を使います:args: { onPress: fn() } |
| アイコンボタンにアクセシブルな名前がない | aria-label を追加するか、aria-labelledby を使います |
| ポータルのコンテンツに対するクエリのスコープを指定しない | within(canvasElement.ownerDocument.body) を使います |
| 条件付きレンダリングに boolean && を使う | スナップショットを一貫させるため、ストーリーでは三項演算子を使います |
| アニメーションの完了を待たない | 非同期状態のアサーションを waitFor で囲みます |
よくある修正方法
| 問題 | 解決策 |
|---|---|
| Controls にプレースホルダーが表示される | デフォルト値を指定して、meta レベルに args を追加します |
| シリアライズエラー | argTypes で className、ref、style を無効にします |
| ポータル要素が見つからない | canvas ではなく body を検索します |
| アニメーションのタイミングに関する問題 | アサーションを waitFor で囲みます |
| 複数のボタンが見つかる | getByRole に { name: '...' } を追加します |
| A11y テストが失敗する | label prop または aria-label を追加します |
委任
- ストーリー構成のレビュー:CSF3 パターンの検証には
code-reviewerスキルを使います - アクセシビリティ監査:ストーリー全体の ARIA パターンを調べるには
Exploreエージェントを使います - ビジュアルリグレッション分析:Chromatic の失敗を調査するには
Taskエージェントを使います
参考資料
コメント
Markdown 対応