LoginSignup
16
12

More than 5 years have passed since last update.

PhantomJSからHeadless Chromeに移行したときにハマったポイント

Posted at

祝!Chrome Headless移行完了

私が担当しているプロジェクトのFeatureSpecで、Headless Chromeに移行が完了しました。なかなか大変だったので、ハマったポイントを覚えている限り書いておこうと思います。

  1. Capybara.register_driver周辺
    1. 画像をダウンロードしない設定など
  2. テーブルに行がなくなるとテーブルごとvisibleがfalse扱いになる
  3. DatePickerを使用している箇所にfill_inでデータを入れると、DatePickerが表示されっぱなしになり、被っているボタンが押せなくなる
  4. driver依存の操作ができなくなる
    1. trigger('click')など
    2. driver.network_trafficなど
  5. alert, confirm, promptなどのダイアログ系が自動でOKを押されなくなる

register_driverでHeadless Chromeを登録する

Seleniumのドライバーとして、chromeを登録し、オプションでHeadlessにしていきます。

chrome_optionsで色々と指定します。

  • headless・・・Headlessにする
  • disable-gpu・・・GPUを使わない(現状必須)
  • window-size=1680,1050・・・ウィンドウサイズ指定
  • blink-settings=imagesEnabled=false・・・画像をダウンロードしない
  • lang=ja・・・日本語指定

また、bridgeを使ってファイルのダウンロードを許可し、ダウンロードパスを指定しています。
WaitForDownload::PATHについては、別記事のRSpecでファイルがダウンロードされるまで待つを参照してください。

Capybara.register_driver :selenium do |app|
  driver = Capybara::Selenium::Driver.new(app, browser: :chrome,
                                          desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
                                              login_prefs: { browser: 'ALL' },
                                              chrome_options: {
                                                  args: %w(headless disable-gpu window-size=1680,1050 blink-settings=imagesEnabled=false lang=ja),
                                              },
                                          )
  )
  bridge = driver.browser.send(:bridge)
  path = "session/#{bridge.session_id}/chromium/send_command"
  bridge.http.call(:post, path, cmd: 'Page.setDownloadBehavior',
                   params: {
                       behavior: 'allow',
                       downloadPath: WaitForDownload::PATH
                   })
  driver
end

Capybara.javascript_driver = :selenium

visible: falseになるものの検証をどうにかする

# テーブルのデータを削除する
within "table tbody" do
  expect(page).to have_content "1行目"
  click_button "削除"
end

# ここで、テーブルが非表示ですと怒られて落ちる
within("table tbody") do
  expect(page).to have_no_content "1行目"
end

こういうのは、以下のようにしました。

expect(find('table', visible: false)).not_to be_visible

visible: falseのものは見えないことというテスト内容になるので当たり前すぎておかしい気もしますが、行がないことを検証できるからとりあえずこうしてます。

いい書き方があったらアドバイスください。

DatePicker対策

DatePickerが表示されっぱなし問題に関しては、新たにfill_in_dateメソッドを定義して対応しました。

def fill_in_date(target, options={})
  fill_in target, options
  hide_datepicker
end

def hide_datepicker
  page.execute_script("$('.datepicker').hide()")
end

Driver依存のものの対応

find('.foo').trigger('click')は使えないので、find('.foo').clickに全て変更しました。

# before
find('.foo').trigger('click')

# after
find('.foo').click

network_trafficは、PDFファイルなどへリダイレクトしたときに、URLが取れないため、network_trafficからURLを取得してちゃんとアクセスしたことを検証していたのですが、それができなくなったので、ファイルがダウンロードされているかどうかという観点に変更して対応しました(ダウンロードされている=そのURLにアクセスした)

ダイアログ系の対応

これは、RSpec + Capybaraでアラート/確認ダイアログを操作する場合は page.driver.browser.switch_to.alert.accept じゃなくて page.accept_confirm を使おうを参考に対応しました。

# before
click_link '削除'

# after
accept_confirm { click_link '削除' }

ざっくり置換していきましたが、大概大丈夫でした。

16
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12