前略
Selenium::WebDriver::Error::StaleElementReferenceError になると悲しい
Stale Element Reference Error とは
see http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp
まあ私もよくわかってないんですが、感覚としては
- ノード取得
- ページが切り替わる
- 1 で取得したノードにアクセスする
- raise Selenium::WebDriver::Error::StaleElementReferenceError
かしら。コードにするとこんな感じ
require 'sinatra' require 'erb' get '/' do erb :index end get '/foo' do erb :foo end post '/bar' do sleep 2 'ok' end __END__ @@ layout <!DOCTYPE html> <body> <%= yield %> </body> </html> @@ index <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script> $(function() { $('#foo').click(function() { $.post( '/bar', { 'baz':'hoge' }, function(data) { location.href = '/foo'; } ) }); }); </script> <h1>Hello, World!</h1> <input type="button" id="foo" value="push" /> @@ foo <h1>FooBarBaz</h1>
テストコードはこんな感じ
class HelloWorldTest < Test::Unit::TestCase include Capybara::DSL Capybara.default_driver = :selenium def setup Capybara.app = Sinatra::Application.new end def test_button_and_goto visit '/' page.click_button('push') assert page.find(:css, 'h1').has_content?('FooBarBaz') end end
ボタンクリックして <h1>
取得して has_content?
(内部では have_content が走って synchronize) になる。
その間にページが切り替わって h1 があたらしくなる。って動きです。
実はこれでも再現性は100%ではなく、3回に1回ぐらいです。
やりたいこと
perhaps the page has changed since it was looked up
って言われて悲しい思いするのはもうコリゴリなので
Stale な Exception が来たら node を再取得する
という動きにしました。
module Capybara module Node class Base old_sync = instance_method(:synchronize) define_method :synchronize do |*args, &block| retry_flag = true begin old_sync.bind(self).(*args, &block) rescue ::Selenium::WebDriver::Error::StaleElementReferenceError => e raise e unless retry_flag retry_flag = false retry end end end end end
- リトライは1回だけ
- 連続で Stale になるの今のところ想像つかないですが、なんかもうそこは諦めたいですね
method.bind(self).()
にした理由super()
とかやるとCapybara::Node::Document
でsynchronize()なんてねーよ
っていわれてめんどかったので- あまりよく挙動わかってない
今のところこれで安定しています。
終わり
とりあえず今回のやつはここに https://gist.github.com/gongo/6509722
$ bundle install --path vendor/bundle $ bundle exec ruby test_web.rb
とかやるとテスト走ると思います。多分