setting-feature-flags-in-storybook について
Storybook のストーリーでフィーチャーフラグを設定する方法を説明するスキルです。ブール値とバリアント値の指定方法に加え、命令的な更新がビジュアル回帰スナップショットに誤りを生む理由を解説します。
主な機能
- 01ストーリーパラメーターでブール値を設定
- 02レコード形式でバリアント値を固定
- 03ブール値とバリアント値の混在
- 04パラメーターの浅い置換への注意
- 05必要に応じた他のランタイム状態の準備
活用シーン
- 01ブール値のフラグを有効にしたストーリーの描画
- 02異なる実験バリアントを使うストーリーの比較
- 03ビジュアル回帰でフラグ無効のスナップショットを防止
- 04追加のランタイム状態に依存するストーリーの設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ posthog --skill setting-feature-flags-in-storybookインストール後、Claude Code で/setting-feature-flags-in-storybookを入力して読み込まれたか確認します。
詳細
Storybook での機能フラグの設定
警告
ストーリーから
featureFlagLogic.actions.setFeatureFlags(...)を呼び出さないでください。ビジュアルリグレッションのランタイムでは何もせずに終了し(フラグ OFF の分岐をレンダリングします)、jest では成功するため、ユニットテストは通ってもスナップショットは誤ったものになります。代わりにfeatureFlagsストーリーパラメーターを使用してください。
基本的な考え方: ブール値のフラグは常に機能します(常にマージされるベースラインに含まれるため)。一方、バリアント値にはゲートが必要で、正しくゲートを開けられるのは featureFlags パラメーターだけ です。
使用方法
これは安定した仕様です。以下の「内部の仕組み」にある内容より、こちらを優先してください。
ブール値のフラグ(フラグを単純にオンにする)
const meta: Meta = {
title: 'Scenes/MyScene',
parameters: {
featureFlags: [FEATURE_FLAGS.MY_FLAG, FEATURE_FLAGS.OTHER_FLAG],
},
}
配列の要素は、true と評価されるフラグです。よく使われる形式です。
多変量フラグ(特定のバリアントを指定する)
値がバリアント文字列(実験のグループや多変量ロールアウト)のフラグには、レコード形式を使います。配列形式で表せるのは true だけです。
// meta-level: applies to every story in the file
parameters: { featureFlags: { [FEATURE_FLAGS.THEME_OVERRIDE]: 'intent_plus' } }
// per-story: a different arm per story
export const ControlArm: Story = {
parameters: { featureFlags: { [FEATURE_FLAGS.THEME_OVERRIDE]: 'control' } },
}
export const TreatmentArm: Story = {
parameters: { featureFlags: { [FEATURE_FLAGS.THEME_OVERRIDE]: 'intent_plus' } },
}
1 つのレコードでブール値とバリアントを混在させられます:{ 'some-bool-flag': true, 'my-experiment': 'test_b' }。
重要
ストーリーの
parametersはメタのparametersを(浅くマージして)置き換えるため、ストーリーごとにfeatureFlagsを指定すると、メタレベルで設定したすべてのフラグが失われます。引き続き必要なメタのフラグは再度列挙してください。フラグがひっそり失われると、フラグ OFF の分岐がレンダリングされ、見落としやすいためです。
一見すると正しそうな方法が失敗する理由
命令的にフラグを設定する方法(featureFlagLogic.actions.setFeatureFlags)は jest(NODE_ENV==='test')では機能しますが、ビルド済みのビジュアルリグレッション用 Storybook では機能しません。posthog-js がフラグを読み込み、空のセットで onFeatureFlags を実行します。これにより setFeatureFlags がディスパッチされ、命令的に設定した値が消去されます。そのため、ユニットテストは通る一方で、スナップショットはフラグ OFF の分岐をレンダリングします。featureFlags パラメーターは、代わりにフラグを常にマージされるベースライン(以下を参照)に書き込むことでこの問題を回避するため、空のコールバックに上書きされません。
posthog-js のフラグを無効にする(例:
advanced_disable_feature_flags)ことで、この問題を解決しようとしないでください。 アプリシェル(appLogic.showApp)は通常、receivedFeatureFlagsがtrueになるまで待機します。この値は同じonFeatureFlagsコールバックによって設定されるため、これを抑止すると、すべてのScenes-App/*ストーリーが 3s のタイムアウトで停止し、不安定になります。 ログインページは意図的な例外です。/loginにはユーザーがいないため、showAppはフラグを待たずにレンダリングします。ログインのストーリーでも、フラグの状態を決定的にするにはfeatureFlagsパラメーターが必要です。
内部の仕組み(実装の詳細 — 変更される可能性があります)
この説明は、パラメーターが機能する理由を明らかにし、ハーネスを拡張する人の参考にするためのものです。 仕様として扱うのは上記の「使用方法」であり、こちらではありません。
withFeatureFlags → setFeatureFlags(frontend/src/mocks/browser.tsx)は、フラグ(配列またはレコード)をそのまま window.POSTHOG_APP_CONTEXT.persisted_feature_flags に書き込みます。
getPersistedFeatureFlags(frontend/src/lib/logic/featureFlagLogic.ts)はこれを featureFlagLogic の初期値として読み込み、spyOnFeatureFlags は常にこれをベースラインとしてマージするため、ブール値と指定したバリアントの両方が、空の onFeatureFlags コールバック後も保持されます。このために必要な本番側の対応は、getPersistedFeatureFlags がサーバーの配列形式に加え、レコード形式(バリアント値)も受け付けることだけです。
これらに手を加える必要はありません。ハーネスを拡張する場合は、この接続部分を確認してください。
関連項目
featureFlags パラメーターが制御するのはフラグだけです。コンポーネントのレンダリングがほかのランタイム状態(localStorage、APP_CONTEXT フィールド、エントリーを解決する kea ロジックなど)にも依存する場合は、その状態も準備してください。通常は、状態を設定してからロジックをマウントし、コンポーネントをレンダリングする小さなラッパーをストーリーに用意します。このラッパーはストーリーファイルに置いてください。レンダリング可能にするために、本番コンポーネントへテスト専用の props を追加しないでください。