[basecamp/lexxy] 非同期テスト処理の安定化による不安定なテストの解消
背景と課題
Lexxyの非同期テスト処理において、タイミング依存による不安定なテスト(flaky tests)が発生していました。これは#552で sleep を削除したことに続く改善で、今回は選択状態の確認やポップオーバーの表示待ちを適切に実装することで、テストの安定性を向上させています。
従来のテストでは、DOM操作後に要素の状態が変わるまでの待機処理が不十分で、次のアサーションが実行される前に非同期処理が完了しない場合がありました。この問題を解決するため、エディタのノード選択状態を確認する新しいヘルパーメソッドと、ポップオーバーの状態を確認する明示的な待機処理が導入されました。
主要な変更内容
ノード選択状態の待機処理
最も重要な変更は、wait_for_node_selection ヘルパーメソッドの追加です。このメソッドにより、エディタ内の要素を選択・削除する際に、選択状態が確定するまで待機できるようになりました。
test/test_helpers/editor_helper.rb
def wait_for_node_selection(expected = true)
wait_until { expected == find_editor.has_node_selection? }
end
このメソッドは EditorHandler に追加された has_node_selection? メソッドを利用しています。
test/test_helpers/editor_handler.rb
def has_node_selection?
evaluate_script "this.selection.hasNodeSelection"
end
JavaScriptの this.selection.hasNodeSelection プロパティを評価することで、エディタが現在ノード選択状態にあるかを判定しています。
画像添付ファイルの削除テスト
画像削除のテストでは、クリック後とDelete後の両方で選択状態の待機処理を追加しています。
test/system/attachments_test.rb
find("figure.attachment img").click
wait_for_node_selection
find_editor.send_key "Delete"
wait_for_node_selection false
assert_no_attachment content_type: "image/png"
assert_editor_html "<p><br></p>"
まず画像をクリックして選択状態になるまで待機し、Deleteキー送信後は選択状態が解除される(false)まで待機します。この二段階の待機により、削除処理が完全に完了してから次のアサーションを実行できます。
水平線の削除と挿入テスト
水平線(horizontal divider)の削除テストでも同様のパターンが適用されました。
test/system/horizontal_divider_test.rb
find("figure.horizontal-divider").click
wait_for_node_selection
find_editor.send_key "Delete"
wait_for_node_selection false
assert_no_selector "figure.horizontal-divider"
assert_editor_html "<p>Text before</p><p>Text after</p>"
さらに、水平線の挿入テストではアサーションの構造も改善されています。
変更前:
assert_selector "figure.horizontal-divider"
assert_selector "figure.horizontal-divider hr"
変更後:
assert_selector "figure.horizontal-divider" do
assert_selector "hr"
end
この変更により、ネストされたアサーションが明確になり、hr 要素が figure.horizontal-divider 内に存在することが保証されます。
プロンプトの表示状態確認
メンション機能などで使用されるプロンプトの表示・非表示確認も、wait_until ブロックを使用した明示的な待機処理に変更されました。
test/system/prompts_test.rb
find_editor.send "1"
wait_until { find_editor.open_prompt? }
find_editor.send "peter "
wait_until { !find_editor.open_prompt? }
従来の assert find_editor.open_prompt? という即座の確認から、wait_until による待機処理に変更することで、プロンプトが完全に開く/閉じるまで待機できるようになりました。
エディタハンドラーの改善
EditorHandler クラスには、エディタ自体をクリックする際の注意点を明記したメソッドも追加されています。
test/test_helpers/editor_handler.rb
def click
# Proper usage is a click on the content element rather than on the editor
content_element.click
end
コメントが示すように、エディタ要素自体ではなくコンテンツ要素をクリックすることが適切な使用方法です。これにより、予期しない動作を防ぎます。
タイムアウト時のエラーハンドリング
assert_editor_plain_text メソッドには、タイムアウト時のフォールバック処理が追加されました。
test/test_helpers/editor_helper.rb
def assert_editor_plain_text(value)
wait_until { find_editor.plain_text_value == value }
rescue Timeout::Error
assert_equal value, find_editor.plain_text_value
end
wait_until がタイムアウトした場合でも、assert_equal によって現在の値との比較を行い、より詳細なエラーメッセージを提供します。
まとめ
今回の変更により、Lexxyの非同期テストは以下の点で改善されました。
-
明示的な状態待機:
wait_for_node_selectionにより、選択状態の確定を確実に待機 -
プロンプト表示の確認:
wait_untilを使用した非同期処理の完了待ち - アサーションの構造化: ネストされたセレクタの関係性を明確化
- エラー情報の改善: タイムアウト時に詳細な比較結果を提供
これらの改善により、テストの実行タイミングに依存しない、安定したテストスイートが実現されています。