てくすた

ピクスタ株式会社のエンジニア・デザイナーがつづるよもやまテクニカルブログです

テスト環境でPhantomJSを使うのやめました。

こんにちは、開発部のケビンです。開発のテスト環境でPhantomJSを使うのをやめた話をしたいと思います。

背景

 PhantomJSはヘッドレスブラウザであり、コマンドを打つだけでUI無しでブラウザを操作できるものです。適切なコマンドを実行することでページ上の操作を行えるためブラウザーテストに優れているものです。fotowaでは以前Capybaraで実行していたテストでPhantomJSを利用していました。しかし、PhantomJSの開発は終了し、リポジトリはアーカイブされ今後新しい機能が追加される予定はなさそうです。アーカイブされたのが去年(2018年)の6月であり、最新のJavaScriptシンタックスがサポートされてないためPhantomJSで発覚するエラーに出会うことが少しありました。この理由でもう少しモダンなSeleniumに移ることにしました。

 SeleniumはWebDriverを用いてPhantomJSと同じようにヘッドレスブラウザを実行することができます。SeleniumとWebDriverを両方使う必要があるためPhantomJSをCapybaraで使えるために使っていたPoltergeistも入れ替える必要がありました。

移るための手順

  • ChromeDriverのインストール
  • rails_helperのファイルの修正
  • テストの動き確認とCIで実行できるように修正

 はじめに、Seleniumを動かす為に依存しているWebDriverをダウンロードしました。自分がダウンロードした時は間違えて古いバージョンをダウンロードしてしまって、たまたまiframeのバグに引っかかってしまいましたので、最新のバージョンをダウンロードすることに注意してください。

 次はrails_helperの修正です。ここから本格的にPoltergeistを捨てSeleniumを使い始めるようになります。

require 'capybara/poltergeist'
require 'selenium-webdriver'
Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(
    app
  )
end
Capybara.javascript_driver = :poltergeist

Capybara.register_driver :chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new(
    args: %w[headless disable-gpu no-sandbox]
  )
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Capybara.javascript_driver = :chrome

 これで基本的な移行作業は終了です。一度全体のテストを実行するとテストの書き方によって実行できないものがあります。これはSeleniumとPoltergeistの間で、CapybaraのAPIを使った実装に違いがあるからです。。ローカルでテストを実行できるようなりましたら次はCIで動かすステップです。fotowaではCircleCIを利用しています。CircleCIではSeleniumが含まれているテストイメージが提供されているためCircleCIの設定ファイル(config.yml)でそちらを使うように修正を入れます。

それによって発生した課題

発生した課題は以下の2つでした。

  • SeleniumはPoltergeistと違う方法でCapybaraのAPIを実装しているため移行後に同じコードは全部動かない。
  • CircleCIを使っているのでそこでも実行できるように変更を加える必要がある。
テストの書き方修正

 Seleniumを使うようにして一回テストを実行するとおそらく複数のテストが落ちるはずです。これは上に書いてある「SeleniumとPoltergeistの実装方法の違い」が関係していてテストを少し書き直す必要があります。一番多かった修正はPoltergeistの.trigger("click")メソッドとSeleniumのモーダルの扱いです。前者は.trigger("click")と書いていた箇所を.click()に修正することが必要でした。後者はPoltergeistはモーダル(アラートなど)がページに現れた時、自動的にOKなどを押して次に進んでいたようですが、Seleniumではそのようなことがなくモーダルが現れるアクションを

accept_alert do 
   ... 
end

に囲む必要がありました。テストの修正作業を終わらせるとローカル環境でテストを全部一通り実行することができました。

CircleCIでSeleniumの動かし方

 CircleCIではテストが行われているコンテナーとSeleniumがブラウザーを実行しているコンテナーが別れていてテストコンテナーがSeleniumコンテナーにコマンドを送るような仕組みになっています。簡単なテストだと特に問題はありませんが、テスト実行されている環境に置いてあるもの(フィクスチャーのファイルなど)が必要としているようなテストがあると通りません。具体的な例で言うとファイルのアップロードをテストしたい場合そのファイルをテストと一緒の場所におきますが、CircleCIの環境だと、そのファイルをアップロードすると言うコマンドを実行した時にSeleniumのコンテナーにそのファイルが存在しないのでテストが落ちました。この問題には色々調べ最終的にrails_helper内でCircleCIでテストが実行されている時に分岐を入れることになりました。これによって無事テストをCIでも通すことができました。詳細はこちらの記事を参考にして下さい。

https://qiita.com/gongo/items/ab81aaa9329d745fb39f

まとめ

 これでPhantomJSからSeleniumに移行することが完了しました。作業で一番時間を使ったのは情報収集です。いろんな記事を参考にしながら最終的に移行が完了できました。PhantomJSは今後復活する予定はなさそうなので早めに移行できてよかったと思います。