valid,invalid

関心を持てる事柄について

PhantomJS + Poltergeist を Selenium + Headless Chrome で置き換える (2) Teaspoon による JavaScript test 編

PhantomJS + Poltergeist を Selenium + Headless Chrome で置き換える (1) Rails + Capybara による feature spec 編 - valid,invalid の続き。

teaspoon.env の変更内容について

Capybara + Selenium + headless Chrome の設定例はググると結構出てくるものの、Teaspoon + Selenium + headless Chrome の例はぜんぜん出てこなかった…。

それもそのはず、詳細は後述するが Teaspoon 自体のメンテナンスがあまりアクティブでないために組み合わせるためにモンキーパッチを当てなければいけない始末だった。

変更部分

以下はコードの追加分。

# spec/teaspoon_env.rb

# Teaspoon doesn't allow you to pass client driver options to the Selenium WebDriver. This monkey patch
# is a temporary fix until this PR is merged: https://github.com/jejacks0n/teaspoon/pull/519.
require 'teaspoon/driver/selenium'

Teaspoon::Driver::Selenium.class_eval do
  def run_specs(runner, url)
    # この1行のためのモンキーパッチ
    driver = ::Selenium::WebDriver.for(driver_options[:client_driver], @options.except(:client_driver))
    driver.navigate.to(url)

    ::Selenium::WebDriver::Wait.new(driver_options).until do
      done = driver.execute_script("return window.Teaspoon && window.Teaspoon.finished")
      driver.execute_script("return window.Teaspoon && window.Teaspoon.getMessages() || []").each do |line|
        runner.process("#{line}\n")
      end
      done
    end
  ensure
    driver.quit if driver
  end
end

Teaspoon.configure do |config|
  config.driver = :selenium

  options = if ENV['SELENIUM_URL'].present?
              http_client = Selenium::WebDriver::Remote::Http::Default.new(read_timeout: 120)
              {
                client_driver: :remote,
                url: ENV['SELENIUM_URL'],
                http_client: http_client,
              }
            else
              { client_driver: :chrome }
            end

  options.merge!(
    desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
      chrome_options: {
        args: %w(headless window-size=1680,1050)
      }
    )
  )

  config.driver_options = options

  # test suite の記述が続く
end

driver options あたりは Capybara のときとほぼ同じ。

実際にはこのリプレイスのほか、remote の Selenium Chrome でも動くようにする変更を足したりして大変だったのだが本題ではないので省略する。

driver options 渡せない問題

まずいちばんの問題が Teaspoon v1.1.5 では Selenium::Webdriver に driver options を渡せないこと。これを改善する PR が提案されているのだが10ヶ月ほど放置されている…。

teaspoon.env は同様に困っている人々が書いた monkey patch を拝借しつつ書いた。

Net::ReadTimeout 問題

Capybara の設定との大きな違いは HTTP client を渡しているところ。これは remote Chrome -> Teaspoon server へのリクエストがデフォルトの HTTP client だと頻繁に Net::ReadTimeout してしまうため。

最初は Chrome の起動が遅いのかと疑ったが driver の初期化付近にブレイクポイントを張ってデバッグしたところ、driver.navigate.to(url) が高確率でタイムアウトしていることがわかった。

    driver = ::Selenium::WebDriver.for(driver_options[:client_driver], @options.except(:client_driver))
+   binding.pry
    driver.navigate.to(url)

Teaspoon の立ち上がりがそれだけ遅いのは実行されるテスト側に問題があるのかもしれないが、ほぼ初めて触るこのレポジトリのテストコードがどんな感じか見定めるのは厳しかったので read_timeout を伸ばした HTTP client を渡すことで回避した。

設定は 30 -> 60 -> 90 -> 120と試したが安定したのは 120 だけだった。

感想

PhantomJS + Poltergeist を Selenium + Headless Chrome で置き換えて多幸感を得たはずが Teaspoon との戦いで疲弊してしまった。次は Teaspoon を消そう。