Turbo Driveのナビゲーション競合によるフォームテストの不安定さを修正
Turbo Driveの非同期ナビゲーションとカスタム要素の初期化タイミングの競合により、CIで断続的にタイムアウトしていたシステムテストを修正しました。アサーション実行前に適切なページ遷移と wait_for_editor の待機を挿入することで、テストの再現性が確保されます。
背景
FormTest の「edit existing records」テストは、Turbo Driveによるページ遷移が完了する前にアサーションが実行される競合状態を抱えていました。click_on "Update Post" を実行すると、Turbo Driveはショウページへの非同期ナビゲーションを開始します。しかしショウページには lexxy-editor 要素が存在しないため、その直後に実行される assert_editor_html はナビゲーション完了前に間に合えば成功し、CIのような低速な環境では lexxy-editor 要素が見つからずタイムアウトするという不安定な挙動になっていました。
CIランナーの速度によって結果が変わるこの種の競合は、ローカル環境では再現しにくく、根本原因の特定が難しいという特徴があります。
技術的な変更
修正は2種類のパターンを組み合わせて FormTest 全体の一貫性を高めています。
1つ目の修正は「edit existing records」テストへの click_on "Edit this post" と wait_for_editor の追加です。click_on "Update Post" の直後にアサーションするのではなく、明示的に編集ページへ戻ってから assert_editor_html を実行するよう変更されました。これは他のフォームテストが採用していたパターンと一致します。
変更前:
click_on "Update Post"
assert_editor_html "<p>Hello</p><p>there</p>"
変更後:
click_on "Update Post"
click_on "Edit this post"
wait_for_editor
assert_editor_html "<p>Hello</p><p>there</p>"
2つ目の修正は、FormTest 内の他のテストに対して wait_for_editor の呼び出しを追加・整理することです。「create a new record」や別のテストケースにおいて、click_on "Edit this post" の直後に wait_for_editor が挿入されています。これにより、flush_lexical_updates がエディタインスタンスにアクセスする前に、カスタム要素が完全にコネクトされていることが保証されます。
変更の差分としては4行追加・1行削除と最小限ですが、テストスイート全体で wait_for_editor の呼び出し位置が統一されました。
設計判断
ナビゲーション先を変更してアサーション条件を安定させるアプローチが採用されました。
ショウページでのアサーションを諦め、エディタ要素が存在する編集ページに戻ってからアサーションすることで、「アサーション対象の要素が必ず存在する」という前提条件が整理されています。タイムアウト値の延長や sleep による待機ではなく、テストの意図(編集後の内容確認)を損なわずに競合の根本原因を取り除いた点が重要です。
また wait_for_editor を「ナビゲーション直後・アサーション直前」に統一配置することで、カスタム要素のライフサイクル(connected callback)が完了していない状態でエディタインスタンスへアクセスするという別の競合も同時に防いでいます。これにより FormTest 全体のテストパターンが一貫したものになりました。
まとめ
Turbo Driveの非同期ナビゲーションとWeb Componentsのライフサイクルが絡み合う競合を、タイムアウト調整ではなくテストフローの修正で解消した変更です。「アサーション前にエディタ要素が存在するページにいること」と「wait_for_editor でカスタム要素の初期化を待つこと」という2つの前提条件を明示化することで、CI環境での再現性が確保されました。