TrixとLexxyのクロスエディタ互換性テストハーネスを追加
Lexxyのテストスイートに、TrixエディタとLexxyエディタ間でAction Textコンテンツが双方向に保持されることを検証するシステムテストが追加されました。これにより、同一コンテンツを両エディタで編集するシナリオを網羅的にカバーできるようになります。
背景
LexxyはBasecampが開発するリッチテキストエディタであり、Railsの標準エディタである Trix と同じAction Text基盤を共有しています。両エディタが同一のAction Textフィールドを編集する場面では、添付ファイルやギャラリーを含むコンテンツが相互変換を経ても失われないことが重要です。
これまでLexxy単体の動作検証はテストが存在していましたが、「Lexxyで作成したコンテンツをTrixで編集する」「Trixで作成したコンテンツをLexxyで読み込む」という双方向のクロスエディタシナリオをカバーするテストハーネスは存在しませんでした。本PRはそのギャップを埋め、エッジケースを積み上げていくための初期基盤として位置づけられています。
技術的な変更
ダミーアプリへのTrixリソース追加
テスト基盤の中核となるのは、ダミーアプリへの TrixPostsController と関連ビューの追加です。既存の PostsController(Lexxyエディタを使用)と対になる形で、同じ Post モデルのレコードをTrixエディタで編集できるエンドポイントを提供します。
config/routes.rb に resources :trix_posts が追加され、posts/edit.html.erb には「Edit in Trix」リンクが、trix_posts/edit.html.erb には「Edit in Lexxy」リンクが追加されています。この双方向のナビゲーションにより、同一レコードを両エディタで往来する操作がシステムテスト上で自然に表現できます。
to_trix_html によるコンテンツの橋渡し
Trixフォームのビューにおける重要な実装ポイントは、hidden inputへの値の渡し方です。
<%= hidden_field_tag "post[body]", post.body.to_trix_html, id: "trix_post_body_input" %>
<trix-editor input="trix_post_body_input"
data-direct-upload-url="<%= main_app.rails_direct_uploads_url %>"
data-blob-url-template="<%= main_app.rails_service_blob_url(":signed_id", ":filename") %>"></trix-editor>
post.body.to_trix_html を使用している点が肝心です。生の body_before_type_cast ではなく to_trix_html を使うことで、<action-text-attachment> タグに content 属性がレンダリングされます。Trixは添付ファイルを表示・保持するためにこの content 属性を必要とするため、raw値を渡すと添付ファイルが失われます。
TrixHelper によるテストユーティリティ
システムテストからTrixエディタを操作するための TrixHelper モジュールが追加され、test_helper.rb のミックスイン対象に組み込まれました。
module TrixHelper
def fill_trix_editor(with:)
find("trix-editor")
page.execute_script <<~JS, with
const editor = document.querySelector("trix-editor").editor
const position = editor.getDocument().toString().trimEnd().length
editor.setSelectedRange([position, position])
editor.insertString(arguments[0])
JS
end
def upload_trix_file(path)
find("trix-editor")
attach_file(path) do
find("button[data-trix-action='attachFiles']").click
end
end
end
fill_trix_editor はJavaScriptを介してTrix内部のエディタオブジェクトを直接操作し、ドキュメント末尾にカーソルを移動してから文字列を挿入します。upload_trix_file はTrixのファイル添付ボタン(data-trix-action='attachFiles')をCapybaraの attach_file と組み合わせて操作します。
テストケースの構成
2つのテストファイルが追加され、合計6つのシナリオをカバーしています。
from_lexxy_to_trix_test.rb(Lexxy → Trix方向):
- リッチテキスト: Lexxyで作成 → Trixで追記 → 結合テキストを検証
- 添付ファイル: Lexxyで画像アップロード → Trixで保存 → action-text-attachment を検証
- ギャラリー: Lexxyで複数画像アップロード → Trixで保存 → ギャラリー保持を検証
from_trix_to_lexxy_test.rb(Trix → Lexxy方向):
- リッチテキスト: Trixで入力 → LexxyのHTML構造を検証 → 追記して保存
- 添付ファイル: Trixでアップロード → Lexxyで action-text-attachment を検証
- ギャラリー: Trixで2画像アップロード → Lexxyで両添付ファイルを検証
設計判断
既存の Post モデルを TrixPostsController で再利用する設計 が採用されました。Trix専用のモデルを作らず、同じレコードを別コントローラが扱うことで、「同一のAction Textフィールドを両エディタが編集する」という実際のユースケースを忠実に再現しています。
TrixのロードはCDN(unpkg.com/trix@2.1.12)からのSRI(Subresource Integrity)付き読み込みで実現されています。これはテスト用ダミーアプリに閉じた構成であり、Lexxy本体への依存追加を避けつつ、ファイルアップロードを含む実際のTrix動作を検証できる実用的な選択です。
また、フォームに data: { turbo: false } が設定されています。Trixとの組み合わせでTurboドライブが干渉することを避けるための措置であり、テストの信頼性を高めています。
まとめ
本PRは、LexxyとTrixが同一のAction Textコンテンツを介してシームレスに連携できることを継続的に保証するためのテスト基盤を確立しました。to_trix_html を使った正確なコンテンツシリアライズと、JavaScriptを介したTrix内部API操作という2つの技術的工夫が、エディタ間の互換性を実際の操作フローで検証することを可能にしています。