mcpField
C
condition-based-waiting

condition-based-waiting

github.com/bobmatnycテスト・品質78332 回インストール15 週間前に更新
リポジトリ

condition-based-waiting について

推測による遅延の代わりに、観測可能な条件を待つテストスキルです。非同期処理、負荷、並列実行に起因する不安定なテストの削減に役立ちます。

主な機能

  1. 01固定遅延ではなく条件を待機
  2. 02イベント、状態、件数、ファイルの待機
  3. 03複合条件を使った待機処理
  4. 04用途別イベントヘルパーの利用

活用シーン

  1. 01テスト内の任意の sleep 呼び出しの置き換え
  2. 02高負荷時に失敗するテストの安定化
  3. 03非同期処理の完了待ち
  4. 04並列テスト実行時のタイムアウト回避

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill condition-based-waiting

インストール後、Claude Code で/condition-based-waitingを入力して読み込まれたか確認します。

同梱ファイルmetadata.jsonreferences/patterns-and-implementation.md

詳細

条件に基づく待機

概要

不安定なテストでは、根拠のない遅延時間を設定してタイミングを推測しがちです。その結果、処理の速いマシンではテストが成功しても、負荷がかかっているときや CI では失敗する競合状態が発生します。

基本原則: 処理にかかる時間を推測するのではなく、実際に必要な条件を待ちます。

使用する場面

digraph when_to_use {
    "Test uses setTimeout/sleep?" [shape=diamond];
    "Testing timing behavior?" [shape=diamond];
    "Document WHY timeout needed" [shape=box];
    "Use condition-based waiting" [shape=box];

    "Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"];
    "Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"];
    "Testing timing behavior?" -> "Use condition-based waiting" [label="no"];
}

次の場合に使用します:

  • テストに根拠のない遅延(setTimeout、sleep、time.sleep())がある
  • テストが不安定である(成功するときもあれば、負荷がかかると失敗するときもある)
  • 並列実行時にテストがタイムアウトする
  • 非同期処理の完了を待つ

次の場合は使用しないでください:

  • 実際のタイミング動作(デバウンス、スロットル間隔)をテストする
  • 根拠のないタイムアウトを使用する場合は、必ず理由を記載する

基本パターン

// ❌ BEFORE: Guessing at timing
await new Promise(r => setTimeout(r, 50));
const result = getResult();
expect(result).toBeDefined();

// ✅ AFTER: Waiting for condition
await waitFor(() => getResult() !== undefined);
const result = getResult();
expect(result).toBeDefined();

クイックパターン

シナリオパターン
イベントを待つwaitFor(() => events.find(e => e.type === 'DONE'))
状態を待つwaitFor(() => machine.state === 'ready')
件数を待つwaitFor(() => items.length >= 5)
ファイルを待つwaitFor(() => fs.existsSync(path))
複雑な条件waitFor(() => obj.ready && obj.value > 10)

実装

汎用的なポーリング関数:

async function waitFor<T>(
  condition: () => T | undefined | null | false,
  description: string,
  timeoutMs = 5000
): Promise<T> {
  const startTime = Date.now();

  while (true) {
    const result = condition();
    if (result) return result;

    if (Date.now() - startTime > timeoutMs) {
      throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
    }

    await new Promise(r => setTimeout(r, 10)); // Poll every 10ms
  }
}

ドメイン固有のヘルパー(waitForEvent、waitForEventCount、waitForEventMatch)を含む完全な実装については、@example.ts を参照してください。

詳細なパターン、実装ガイド、よくある間違いについては、@references/patterns-and-implementation.md を参照してください。

実際の効果

デバッグセッションより(2025-10-03):

  • 3 ファイルにわたる不安定なテスト 15 件を修正
  • 成功率:60% → 100%
  • 実行時間:40% 短縮
  • 競合状態が発生しなくなった

コメント