注:2020年8月版の手順を最後に追記しています。
はじめに
先ほど、こちらの記事を拝見しました。
【Everyday Rails 6章 JavaScriptテスト】AWS Cloud9でChromeエラーが出たときの対処法 - Qiita
詳しくは上記の記事を読んでいただきたいのですが、簡単にまとめると、
- 「Everyday Rails - RSpecによるRailsテスト入門」(僕が翻訳した電子書籍。以下Everyday Rails)の第6章に書いてある
js: true
付きのテストコードをCloud9で動かそうとしたらエラーが起きた - 参考記事を読んで対応しようとしたが、それでもダメだった
- Chromeを使うのはあきらめてPhantomjs + poltergeistを使うようにしたらテストが動いた
というものです。
たしかに、本の中では第2の選択肢としてPhantomjs + poltergeistを紹介しています。
ですが、こちらはすでに開発が止まっているため、できることならChromeを使って実行したいところです。
そこで、この記事ではCloud9上でサンプルコードを動かしながらEveryday Railsを勉強しようとしている読者さんのために、Cloud9上でjs: true
付きのフィーチャスペックを実行する手順(Phantomjs + poltergeistではなく、Chromeを使う手順)を紹介します。
実行環境
この記事は以下の環境で動作確認しています。
- Amazon Linux AMI release 2018.03
- Ruby 2.6.3
- Chrome 75
- everydayrails-rspec-2017のサンプルコード
また、サンプルコードを動かすために参照しているEveryday Railsの版は、最新の変更履歴が2019/04/08の版(chromedriver-helperではなく、webdriversを使っている版)です。
手順
1. tasks_spec.rb を準備する
今回はspec/features/tasks_spec.rb
をCloud9上で動かせるようにしていきます。
第6章にある以下の説明文まで、本書の説明通りにサンプルコードを準備してください。
さあ、これで準備が整いました。実際にやってみましょう。新しく作ったスペックを実行してみてください。
$ bin/rspec spec/features/tasks_spec.rb
Cloud9上でこのコマンドを実行すると以下のようなエラーが発生するはずです。
Failures:
1) Tasks user toggles a task
Failure/Error: visit root_path
Webdrivers::VersionError:
Failed to find Chrome binary or its version.
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webdrivers-4.0.1/lib/webdrivers/chrome_finder.rb:10:in `version'
# 以下省略...
もしくは次のようなエラーになっているかもしれません。
(webdrivers 4.1.0でのみ発生? - 参考)
Failures:
1) Tasks user toggles a task
Failure/Error: visit root_path
ArgumentError:
wrong first argument
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webdrivers-4.1.0/lib/webdrivers/system.rb:150:in `popen'
# 以下省略...
2. Chromeブラウザをインストールする
js: true
付きのフィーチャスペックを実行するにはChromeブラウザが必要ですが、初期状態のAmazon LinuxにはChromeがインストールされていません。
そこで、ターミナルから以下のコマンドを実行し、Chromeをインストールしてください。
$ curl https://intoli.com/install-google-chrome.sh | bash
この記事の執筆時点ではChrome 75がインストールされました。
Successfully installed google-chrome-stable, Google Chrome 75.0.3770.100 .
3. ヘッドレスモードでChromeを起動できるようにする
Cloud9上ではGUIモードのChromeを起動することはできません。
ですので、代わりにヘッドレスモード(GUIを起動しないモード)でテストを実行するようにします。
spec/support/capybara.rb
にあるselenium_chrome
をselenium_chrome_headless
に変更してください。
-Capybara.javascript_driver = :selenium_chrome
+Capybara.javascript_driver = :selenium_chrome_headless
4. selenium-webdriverとcapybaraを最新版にする
最新のChromeを正常に操作できるよう、selenium-webdriverとcapybaraを最新版にします。
まず、Gemfileを編集してcapybaraのバージョン制限を外します。
group :test do
- gem 'capybara', '~> 2.15.2'
+ gem 'capybara'
gem 'webdrivers'
end
続いて以下のコマンドを実行し、selenium-webdriverとcapybaraをアップデートします。
$ bundle update selenium-webdriver capybara
この記事の執筆時点では以下のバージョンにアップデートされました。
$ bundle list | grep 'selenium\|capybara'
* capybara (3.25.0)
* selenium-webdriver (3.142.3)
5. テストが正常に実行できることを確認する
これで準備完了です。
うまくいけば次のようにtasks_spec.rb
が正常に実行できるはずです。
$ bin/rspec spec/features/tasks_spec.rb
Running via Spring preloader in process 18989
Tasks
Capybara starting Puma...
* Version 3.8.2 , codename: Sassy Salamander
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:35495
user toggles a task
Finished in 2.13 seconds (files took 0.28209 seconds to load)
1 example, 0 failures
ちなみに、上の実行例では.rspec
ファイルから--warnings
を外して、不要な警告が表示されないようにしています。
--require spec_helper
--format documentation
動画を使った、より詳しい説明
この記事の内容をもっと詳しく説明した動画をYouTubeにアップしています。
こちらもぜひご覧ください。
https://www.youtube.com/watch?v=wIKW3mIPrdc
参考文献
- Everyday Rails - RSpecによるRailsテスト入門
- AWS Cloud9でCapybara+Selenium+Chrome設定時のエラーとその対処法について[ Everyday Rails 6章 ] - クラクスの記録帳
追記:2020年8月版の手順
下記の質問に答える形で、2020年8月版の手順も動画にまとめました。
具体的には本記事の手順4と手順5の間に以下の手順が追加で必要になります。
webdrivers gemを使う
selenium-webdriver gemはサポートが止まっています。代わりにwebdrivers gemを使います。
group :test do
gem 'capybara'
gem 'selenium-webdriver'
- gem 'chromedriver-helper'
+ gem 'webdrivers'
$ bundle install
spec/support/vcr.rb に設定を追加
webdrivers gemをインストールした関係で、vcrの設定を追加する必要があります。
VCR.configure do |config|
config.cassette_library_dir = "#{::Rails.root}/spec/cassettes"
config.hook_into :webmock
config.ignore_localhost = true
+ config.ignore_hosts 'chromedriver.storage.googleapis.com'
config.configure_rspec_metadata!
end
詳しくは上記の動画を参考にしてください。
追記2:さらにRuby 2.6系で実行する場合
上の「2020年8月版の手順」ではRuby 2.4系で動かしたのですが、Ruby 2.6系で動かすと以下のようなエラーが出る場合があります。(masterブランチのテストコードをそのまま実行しようとすると発生します)
Failures:
1) Tasks user toggles a task
Got 0 failures and 2 other errors:
1.1) Failure/Error: visit root_path
ArgumentError:
unknown keyword: write_timeout
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:259:in `initialize'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:136:in `start_with_connect_without_finish'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:104:in `request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:56:in `block in responsive?'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:36:in `make_request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:28:in `http_request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:14:in `request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:56:in `responsive?'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:81:in `boot'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/session.rb:93:in `initialize'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:415:in `new'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:415:in `block in session_pool'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:312:in `current_session'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/dsl.rb:46:in `page'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/dsl.rb:58:in `block (2 levels) in <module:DSL>'
# ./spec/system/tasks_spec.rb:24:in `go_to_project'
# ./spec/system/tasks_spec.rb:14:in `block (2 levels) in <top (required)>'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call'
# -e:1:in `<main>'
1.2) Failure/Error:
def initialize(io, read_timeout: 60, continue_timeout: nil, debug_output: nil)
@read_timeout = read_timeout
@rbuf = ''
@debug_output = debug_output
@io = case io
when Socket, OpenSSL::SSL::SSLSocket, IO
io
when StringIO
PatchedStringIO.new(io.string)
ArgumentError:
unknown keyword: write_timeout
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:259:in `initialize'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:136:in `start_with_connect_without_finish'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:104:in `request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:56:in `block in responsive?'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webmock-3.0.1/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:36:in `make_request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:28:in `http_request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server/checker.rb:14:in `request'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:56:in `responsive?'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/server.rb:73:in `boot'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/session.rb:93:in `initialize'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:415:in `new'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:415:in `block in session_pool'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara.rb:312:in `current_session'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/capybara-3.32.2/lib/capybara/dsl.rb:46:in `page'
# /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call'
# -e:1:in `<main>'
このエラーが出た場合はwebmockのバージョンを最新にすると解消します。(参考)
$ bundle update webmock