Open2

Rspec に於ける Capybara の driver 設定に関するメモ

hwatattamahwatattama
  • rails (8.0.2)
  • capybara (3.40.0)
  • rspec-rails (7.1.1)
  • rspec-core (3.13.3)

Rspec の System spec で cuprite を使おうと、 Capybara.javascript_driver = :cuprite としたのだけれども、どうも :selenium が使われている。 Rspec のテストのほうで、 describe ... type: :system, js: true do ... といった具合に js タグを立てれば、javascript_driver に自動で切り替わると思い込んでいた。

いろいろ迷走右往左往した結果、 System spec では javascript_driver には切り替わらない。これは Rspec の仕様のようで、ドキュメントに書いてあった。

https://rspec.info/features/7-1/rspec-rails/system-specs/system-specs/

RSpec does not use your ApplicationSystemTestCase helper. Instead it uses the default driven_by(:selenium) from Rails. If you want to override this behaviour you need to call driven_by in your specs.

デフォルトは :selenium であるから、変えたい場合は driven_by の設定を上書きして切り替えよ、とのこと。


(余談) ChatGPT に訊いてみました。

(問い)

https://github.com/rails/rails/issues/34379 について、どういう考えで Capybara.javascript_driver が使われないことを選択したのでしょう?

(回答)

Rails の system spec で js: true を指定しても、Capybara.javascript_driver が自動的に使用されない理由は、主に以下の技術的な背景と設計上の選択によるものです:

🧠 技術的背景と設計上の選択

  1. SystemTestCase の初期化タイミングと設定の適用タイミングの不一致

SystemTestCase は、driven_by(:selenium) をデフォルトで設定しています。この設定は、SystemTestCase が初期化される際に適用されます。一方で、Capybara.javascript_driver の設定は、RSpec の設定ファイル(例えば rails_helper.rb)で行われるため、SystemTestCase の初期化後に適用されます。このため、Capybara.javascript_driver の設定が SystemTestCase に反映されないという問題が発生します。

この問題を解決するためには、SystemTestCase の初期化タイミングを変更するか、Capybara.javascript_driver の設定を SystemTestCase の初期化前に行う必要があります。

  1. driven_by の明示的な設定の推奨

RSpec の公式ドキュメントでは、system spec でのドライバの設定は明示的に行うことが推奨されています。これは、テストの可読性と明確性を高めるためです。driven_by を明示的に設定することで、どのドライバが使用されているかが明確になり、テストの挙動を予測しやすくなります。

hwatattamahwatattama

現在使っているドライバ設定:

Capybara.register_driver(:cuprite_custom) do |app|
  # see also https://github.com/rubycdp/ferrum?tab=readme-ov-file#customization
  Capybara::Cuprite::Driver.new(app,
    js_errors: true,
    window_size: [1200, 800],
    headless: %w[0 false].exclude?(ENV['HEADLESS']),
    slowmo: ENV['SLOWMO']&.to_f,
    inspector: true,
    browser_options: (ENV['DOCKER'] ? { 'no-sandbox' => nil } : {}).merge('accept-lang' => 'en'),
  )
end

多言語化したページに対する System specs が英語表記をベースに作られていたところ、テストを実行すると軒並み FAIL になっていた。つまり cuprite が動かすブラウザがページを日本語で表示する設定になっていたことが原因である。これを英語で表示させるために browser_options'accept-lang' => 'en' を追加してみたところ、ページが英語表記になり、テストも PASS することができた。(その後、 accept-lang の値は ENV から得るようにした)

また、 ENV を渡すアイデアは、こちらの記事 Rails: SeleniumをCupriteにアップグレードする(翻訳) の記述をそのままいただいた。

デバッグが必要になったら、怪しいコードに binding.pry を埋め込んで、次のように実行するとよい:

$ HEADLESS=0 SLOWMO=0.5 ./bin/rspec spec/system/sample_spec.rb:123