[basecamp/lexxy] 非同期テスト処理の安定化による不安定なテストの解消

basecamp/lexxy

背景と課題

Lexxyの非同期テスト処理において、タイミング依存による不安定なテスト(flaky tests)が発生していました。これは#552sleep を削除したことに続く改善で、今回は選択状態の確認やポップオーバーの表示待ちを適切に実装することで、テストの安定性を向上させています。

従来のテストでは、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の非同期テストは以下の点で改善されました。

  1. 明示的な状態待機: wait_for_node_selection により、選択状態の確定を確実に待機
  2. プロンプト表示の確認: wait_until を使用した非同期処理の完了待ち
  3. アサーションの構造化: ネストされたセレクタの関係性を明確化
  4. エラー情報の改善: タイムアウト時に詳細な比較結果を提供

これらの改善により、テストの実行タイミングに依存しない、安定したテストスイートが実現されています。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

ガイドライン準拠 ✓ PASS

記事構成とDiffDaily Styleへの準拠状況

記事構成の3要素(Title, Context, Technical Detail)が明確に記載されています。また、コードブロック前後の空行やファイル名付きハイライトなど、カスタムMarkdown構文も正しく使用されており、ガイドラインを完全に遵守しています。

  • 記事構成(Title、Context、Technical Detail)
  • DiffDaily Styleガイド準拠
  • カスタムMarkdown活用
  • 対象読者への適合性
技術的整合性 ✓ PASS

技術的な正確性と表現の適切性

引用されているコードはPRの目的である「非同期テストの安定化」に合致しており、技術的な説明も正確です。特に、wait_untilの導入理由やアサーションの構造化のメリットなど、変更の意図が技術的に正しく解説されています。

  • 技術用語の正確性
  • コード例の正確性
  • 説明の技術的正確性
PR内容との整合性 ✓ PASS

元のPR情報との一致度

記事のすべての主張はPRのタイトル「Async test stability」と整合性が取れており、ハルシネーションは見られません。PR番号や関連PRへの言及も正確で、PRの内容を忠実に反映した記事になっています。

  • タイトル・説明の一致
  • Diff内容の正確な反映
  • 推測の排除