writing-tests について
Remotion リポジトリで、テスト境界を選び、ユーザーから確認できる契約を検証するテストを書くためのスキルです。UI、CLI、レンダリングなどのワークフローに適したテストを案内し、実装詳細より一連の成果を重視します。
主な機能
- 01安定したテスト境界の選定
- 02観測可能な結果の優先
- 03統合テストと E2E テストの指針
- 04ユニットテストの適切な用途
- 05回帰テストの検証方法
活用シーン
- 01機能のテスト範囲の計画
- 02CLI ワークフローの一連テスト
- 03レンダリング結果や保存結果の検証
- 04バグ修正の回帰テスト評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ remotion-dev/ remotion --skill writing-testsインストール後、Claude Code で/writing-testsを入力して読み込まれたか確認します。
詳細
テストの作成
ユーザーが新しいテストを明示的に依頼した場合、または機能追加、バグ修正、リファクタリング、PR の準備に伴って既存のテスト、フィクスチャ、スナップショットの更新が必要な場合に、このスキルを適用します。ユーザーが明示的に依頼しない限り、新しいファイルへのテスト追加も、既存ファイルへのテストケース追加も行わないでください。テストのレビュー依頼は、テストの変更を許可するものではありません。
テストの目的は、Studio ユーザー、CLI ユーザー、パッケージ利用者、レンダラー利用者にとって、ワークフローや契約が機能するという確信を得ることです。
有用な確信を得られる、最も広い安定した境界で機能をテストします。完全な統合ワークフローを優先し、真に複雑なロジックには焦点を絞ったユニットテストを、重要なプロセス間ワークフローには E2E テストを使用します。
テスト数、アサーション数、ファイル数、カバレッジ率は品質指標ではありません。多くの限定的なユニットテストよりも、レンダリングされたフレーム、最終成果物、または永続化されたソースを確認するアサーションのほうが、大きな確信を得られることがあります。
機能が切り離されても成功し続けるテストは、主要なカバレッジとして役に立ちません。ユーザー向け機能やレイヤーをまたぐ機能では、プライベートヘルパーのユニットテストだけをカバレッジにしないでください。
テストを書く前に境界を選ぶ
まず、次の質問に答えてください。
- ユーザーやパブリック API の利用者が気づく問題は何ですか?
- その問題を効率よく再現できる、最も広い安定した境界はどこですか?
- 拡張できる既存の統合ワークフローや E2E ワークフローはありますか?
- 提案したテストは、機能のエントリーポイントがテスト対象のヘルパーを呼び出さなくなった場合に失敗しますか?
- 焦点を絞ったユニットテストで検証する価値のあるエッジケースはありますか?
テストの種類はディレクトリやランナーではなく、境界によって決まります。Bun テストでも統合テストになり得ますし、Playwright テストでも実装の詳細に結びついている場合があります。
主な境界には、次を使用してください。
| 変更 | 優先する主なカバレッジ |
|---|---|
| Studio の操作 | Playwright の操作を行い、表示、ソースファイル、永続化、URL、またはレンダリング結果を確認する |
| Studio Server または codemod | 現実的なソースフィクスチャをルートまたはハンドラーに渡し、結果のソースまたはイベントを確認する |
| Core、Player、または Media | 実際の隣接モジュールと代表的なメディアを使って、実際のコンポーネントをマウントまたはレンダリングする |
| Web レンダラーまたは視覚効果 | ブラウザでのレンダリング、画像比較、ピクセルの検査、または生成されたフレーム |
| CLI | コマンドを実行し、終了コード、出力、ファイルシステムへの影響を確認する |
| Renderer、SSR、テンプレート、またはパッケージング | packages/it-tests を介したパブリック API、または現実的な一時プロジェクト |
| Lambda またはクラウドオーケストレーション | リモートプロバイダーのみをモックまたはフェイクにした、完全なオーケストレーション |
| 純粋な数学、パーサー、シリアライザー、プロトコル変換、または状態機械 | 焦点を絞った、できればテーブル駆動のユニットテスト |
すべての変更を無理に Playwright でテストしないでください。多くの場合、ルートレベルやファイルシステムの統合が最適な安定境界です。ブラウザー、サーバー、ファイルシステム、HMR、またはプロセスの境界をまたぐ重要なリスクがある場合に、完全な E2E テストを使用してください。
アサーションで契約と結果を検証する
ユーザーやインテグレーターが観察できる結果を優先します。
- レンダリングされたフレーム、ピクセル、メディアのタイムスタンプ、画像出力、視覚的なリグレッション
- 生成または永続化されたソースコードやファイル
- 公開された戻り値、イベント、エラー、プロトコルメッセージ
- CLI の終了ステータス、出力、プロンプト、ファイルシステムの変更
- Studio のテキスト、アクセシブル名、フォーカス、有効状態、ナビゲーション、永続化
- メソッド、パス、ペイロードが契約に含まれる場合は、それらを含む外部境界へのリクエスト
処理経路が実行されたことを証明する、肯定的な最終結果を優先します。does not throw、not visible、not present、または「エラーがない」ことだけでは、証明として不十分です。まず、期待される並べ替え、ファイルの変更、リクエスト、レンダリング出力、永続化された状態、または成功した結果をアサートしてください。否定的なアサーションは、それによって確信が高まる場合にのみ追加します。
生成されたコードがユーザーに見える成果物である場合、ソースのアサーションは妥当です。意味のある出力をアサートし、フォーマット自体が契約の一部でない限り、無関係な書式への依存は避けてください。
Studio と製品 UI のテスト
ユーザーが操作対象を見つける方法に合わせて、getByRole、getByLabel、getByText、アクセシブル名を使ってコントロールを特定します。属性を調べるより、toBeDisabled() や toBeFocused() などのセマンティックな状態マッチャーを優先してください。
外部の結果を確認できる場合、以下をアサーションの対象にするのは避けてください。
- CSS クラスやライブラリ内部専用の属性
- タグ名、ラッパーの階層、親要素のたどり方、アイコンの有無
- 内部メニュー ID や記述子オブジェクト
- 内部メニュー項目を直接呼び出して得たコールバックのペイロード
- フック、コンテキスト、リデューサー、モーダル状態のオブジェクト
- 単に状態の保存に使われる内部 ARIA 値
セマンティックなロケーターがない場合は、アクセシビリティを改善するか、安定した操作用フックを追加してください。サードパーティ製の内部要素や、その他アクセスできない内部要素に対する操作には CSS セレクターやテスト属性を使用できますが、アサーションの対象は引き続き観察可能な結果にしてください。
Remotion における視覚的な例外
スタイル、ジオメトリ、DOM 出力、ピクセルを一律に禁止しないでください。Remotion では、視覚的な出力自体が製品であることがよくあります。
レンダラー、エフェクト、レイアウト、メディア、生成ソースでは、以下が公開契約となる場合があります。
- ピクセル、スクリーンショット、不透明度、色、合成
- ジオメトリ、位置、寸法、タイミング
- CSS の動作や DOM 出力
- フレーム、タイムスタンプ、デコード済みメディア、レンダリングされた成果物
- 利用者が受け取る、または編集する厳密な生成ソース
可能な場合は、中間のスタイルオブジェクトだけではなく、レンダリングされた結果をテストしてください。エッジケースの多いレイアウトアルゴリズムでは、焦点を絞ったジオメトリのユニットテストも引き続き適切です。特に、結果がレンダリングに反映されることを証明するブラウザーまたはビジュアルテストを併用する場合は有効です。
所有するコラボレーターを実際に使用する
デフォルトでは、Remotion の実際のモジュール、ルート、ファイルシステム操作、サーバー、コンポーネント、ブラウザーのレンダリングを使用してください。AWS、利用できないリモートサービス、時刻、非決定的な外部依存関係など、Remotion が所有しない境界はモックまたはフェイクに置き換えてかまいません。
セットアップを簡単にするためだけに、内部の本番モジュールや近隣の自社パッケージをモックしないでください。内部のフェイクが避けられない場合は、実際の境界を使うのが現実的でない理由を説明し、そのフェイクが代替した配線を別のテストでカバーしてください。
適切な統合テストでは、一時ディレクトリ、実際のフィクスチャプロジェクト、実際のサーバールート、実際のパッケージエントリーポイント、または実際のメディアファイルを使い、置き換えるのは外部プロバイダーだけにできます。
少ないテストでワークフロー全体を検証する
一貫した手動ワークフローをテストとしてモデル化します。セットアップは1回だけ行い、その後はワークフローに必要なアクションとアサーションを追加します。
- 1つのテストに複数のアサーションを含めるのは適切です。
- すべてのテストは、それぞれ単独で実行でき、分離されている状態を保ちます。
- 1つのワークフローを、順序に依存する複数のテスト、共有される可変変数、または
beforeAllの手順に分割しないでください。 - 個々のアサーションのために、同じブラウザー、レンダラー、または Studio プロセスを再起動しないでください。
- セットアップ、実行者、目標が同じ場合は、既存のワークフローを拡張します。
- セットアップ、契約、または失敗経路が実質的に異なる場合は、別のテストを追加します。
- 純粋関数の表形式のエッジケースは、作為的なブラウザーワークフローではなく、テーブル駆動型のユニットテストにまとめます。
- テストファイルの数を減らすためだけに、無関係な動作を組み合わせないでください。
packages/example/e2e では Studio の起動に時間がかかり、テストスイートは直列で実行されます。1つのワークフローを構成するタイトル、表示状態、ナビゲーション、操作、最終結果のアサーションごとに、Studio を再起動してはいけません。beforeAll でプロセス状態を共有するのではなく、単独で実行できる1つのテストにまとめてください。
アサーションを追加する前に、隣接するより強力なアサーションで、すでに証明できないかを確認してください。冗長な中間状態をいくつも観察するより、強力な結果を1つ確認する方が望ましいです。
ユニットテストの役割
ユニットテストが役立つのは、次のような場合です。
- 意味のある入力が多数ある純粋なアルゴリズム
- パーサー、シリアライザー、codemod、プロトコル変換
- 組み合わせによる分岐が多数ある状態機械とエラー処理
- 広範なテストが扱いにくくなるほどのエッジケースがある幾何計算や時間計算
- 戻り値自体が契約となる公開ユーティリティ関数
複数レイヤーにまたがる機能では、まず主要な統合ワークフローを追加するか、既存のものを特定します。ユニットテストは、広範なテストでは効率よくカバーできない重要なエッジケースに限って追加してください。
テスト可能にすることだけを目的に、単純なヘルパーを切り出したりエクスポートしたりしないでください。ヘルパーが正常に動作していても、機能のエントリーポイントからヘルパーが呼び出されなくなったときにテストが失敗しないなら、そのテストでは主要なカバレッジとして不十分です。
テストを求められた場合でも、実装の詳細しか検証しないテストは避けてください。制約と、実施した手動検証があれば報告してください。
次のアンチパターンを避ける
- UI 機能のカバレッジとして、結合、マッピング、配列構築ヘルパーだけをテストする
- 内部のメニュー ID、コールバック記述子、reducer の状態、またはフックの状態をアサートする
- リスクが CLI の配線にあるのに、フォーマッターを直接呼び出す
- カバレッジを増やすためだけに、変更した本番コードの各行を個別にテストする
- 各レイヤーに固有のリスクがないのに、ユニット、ルート、コンポーネント、E2E の各レイヤーで同じ動作を重複してテストする
- より小さな契約や最終成果物で検証できるのに、大きな内部オブジェクトやマークアップツリー全体をスナップショットする
- 最も壊れやすい統合処理を含むモジュールをモックする
- セットアップが同じ要件文ごとに1つずつテストブロックを作る
- 意図した操作が成功したことを確認せず、エラーが発生しなかったことだけを証明する
回帰をレッドとグリーンで検証する
バグ修正では、実行可能な場合、新しいテストが回帰を検出することを確認してください。
- 修正を適用した状態でテストを実行します。
- 関連する本番コードの変更箇所を一時的に元に戻すか、切り離します。
- 想定した理由でテストが失敗することを確認します。
- 修正を戻し、テストが成功することを確認します。
次の変更テストのヒューリスティックを使ってください。
テスト対象のヘルパーが引き続き動作していても、機能のエントリーポイントから呼び出されなくなった場合、このテストは失敗するでしょうか?
失敗しない場合は、主要なテストをより広い境界に移してください。
最終回答には Red/green verified と記載してください。検証が現実的でない場合は、実施したと誤解させず、その理由を述べてください。
例
新しいコンポジションのデフォルト値
弱い主なテスト:
expect(getNewCompositionDefaults(selected)).toEqual(selected);
より強いワークフロー:
- 縦向きのコンポジションを選択します。
- 「新しいコンポジション」を開きます。
- 幅、高さ、FPS、再生時間が入力されていることを確認します。
- コンポジションを作成します。
- 作成されたコンポジションまたはソースにこれらの値が含まれていることを検証します。
意味のある独立したロジックを表す場合は、特異なフォールバック入力を対象にしたユニットテストも有効です。
CLI のヘルプ
弱い主なテスト:
expect(getCreateVideoHelp()).toContain('--help');
より強い統合テスト:
- 実際の CLI エントリーポイントから
create-video --helpを実行します。 - 正常に終了し、想定した出力が表示されることを検証します。
- プロンプトが表示されず、プロジェクトも作成されていないことを検証します。
読み取り専用の Studio
弱い主なテスト:
expect(getItem(items, 'rename').disabled).toBe(true);
より強いワークフロー:
- 読み取り専用モードで Studio を開きます。
- 安全なアクションを実行し、画面上または外部でその効果を検証します。
- 変更を伴うアクションが利用できないこと、またはソースを変更できないことを確認します。
否定的な回帰テスト
弱いテスト:
await expect(page.getByText(error)).toBeHidden();
より強いテストでは、操作を実行し、新しいシーケンスの順序、ソースの変更、リクエスト、永続化された値、レンダリング結果など、肯定的な結果を検証します。その後、エラーがないことを補助的なアサーションとして確認できます。
リポジトリの例
テストの構成と境界の選択の参考にしてください。
- HMR ワークフロー全体:
packages/example/e2e/error-overlay.test.mts - 境界をまたぐウォッチャーのワークフロー:
packages/example/e2e/suppress-rebuild.test.mts - 実際の Player とメディアのビジュアルテスト:
packages/media/src/test/player-preview-frame-accuracy.test.tsx - プロバイダー境界のフェイクを使ったクラウドのオーケストレーション:
packages/lambda/src/test/integration/deploy-site-from-bundle.test.ts - ブラウザーでのビジュアル出力:
packages/web-renderer/src/test/opaque-layer-over-fading-layer.test.tsx
サブシステム固有の仕組みには web-renderer-test などの専用スキルに従いつつ、このスキルの原則を維持してください。
レビューと報告
完了する前に、次の点を確認してください。
- テストが、主要な公開仕様またはユーザーから見える仕様を検証していること。
- 実際の機能の配線が壊れた場合に、テストが失敗すること。
- 冗長なアサーションや重複する低レベルのテストを削除すること。
- 変更したすべてのテストについて、対象を絞ったテストコマンドを実行すること。
- 実施可能な場合は、回帰テストのレッド/グリーン検証を行うこと。
テストの変更を報告する際は、次の内容を含めてください。
- テストした主要な動作または仕様
- 選択した境界:ユニット、統合、ビジュアル/ブラウザー、E2E
- その境界で有用な信頼性を得られる理由
- 内部依存関係をモックした場合は、その対象と理由
- 既存のワークフローを拡張したか、新しいシナリオが必要だった場合はその理由
Red/green verified、または実施が困難だった理由
以下の原則を参考にしています。