いろいろ課題はあるんですが、とりあえず動きました。
書いたもの
Capybara の稼働状況を animation gif として保存するようなやつ
Ruby 2.0 だったら Module#prepend とか使えばいいのかなって想いながら ↓ 書いてた。
module Capybara class Session SAVE_SCREENSHOT_METHODS = [ :attach_file, :check, :choose, :click_link_or_button, :click_button, :click_link, :fill_in, :select, :uncheck, :unselect, :click_on, :evaluate_script, :visit ] SAVE_SCREENSHOT_METHODS.each do |method| alias_method "after_hook_#{method}".to_sym, method define_method method do |*args, &block| send("after_hook_#{method}", *args, &block) CapybaraAnimation::Recorder.add_frame end end end end
やってることはそこまで複雑ではなくて
SAVE_SCREENSHOT_METHODS
のアクションが起きたらsave_screenshot
を呼び出すsave_screenshot
の結果を Tempfile においとく- 最後に全部の screenshot を RMagick 使って Animation Gif に変換して保存
RMagick 使うまでもないって人は Tempfile の部分を File にして一枚ずつ保存するように変えればいいと想います。
課題
confirm や alert などの Modal Dialog が表示されている状態で save_screenshot
をすると
Selenium::WebDriver::Error::UnhandledAlertError
が raise されます。
そんなわけで、例えば dialog が出ている場合はスクリーンショット撮らないとかすると
--- a/capybara_animation.rb +++ b/capybara_animation.rb @@ -8,11 +8,29 @@ module CapybaraAnimation class Recorder class << self def add_frame + return if alert_present? + tempfile = Tempfile.new(['screenshot', '.gif']) - Capybara.current_session.save_screenshot(tempfile.path) + session.save_screenshot(tempfile.path) frames << tempfile end + def alert_present? + # selenium-webdriver じゃなかったらスルー(これもどうかと思うけど…) + return false if session.driver.browser.respond_to?(:switch_to) + + begin + session.driver.browser.switch_to.alert + true + rescue Selenium::WebDriver::Error::NoAlertPresentError + false + end + end + + def session + Capybara.current_session + end + def frames
ってすると、ひとまず dialog でてる時はスルーしてくれるので動く。
でも、今度は driver.browser.switch_to.alert
が遅い。
おそらく Capybara.default_wait_time
だけアラートが出るのを待ってから raise するっぽいので遅い。
一つ一つのアクションで Capybara.default_wait_time
も待っているとだいぶつらい。
というわけでここらへんどうにかしたい(かといって default_wait_time
短かくすると、本当に Alert を待ちたい処理書いてる時に逃してしまいそうなのでそれもなんだかなー。
(追記 2013/06/27)
define_method method do |*args, &block| - send("after_hook_#{method}", *args, &block) CapybaraAnimation::Recorder.add_frame + send("after_hook_#{method}", *args, &block) end
とすれば dialog は関係ない気がしてきました。
この状態だと、dialog が出るのはスクリーンショットを撮ったあと。
もしこのあと CapybaraAnimation::Recorder.add_frame
で UnhandledAlertError が出ると言うことは、
実際のコードは Alert/Confirm を考慮していないコード、ということになるため、こいつの出る幕じゃない。
みたいな?というわけでこれでいい気がしました。
ちなみにコメントに書いた wait_time
は効きませんでした。どうやっても時間かかったので諦め
おまけ
作ったあとに同じようなことしてる人いるんだろうなって検索したらやっぱり居た
違いとしては save_screenshot
を起動するタイミングを絞ったぐらいかな。