SlideShare a Scribd company logo
1 of 10
Download to read offline
Rails,RSpec & Capybara
で困った話
Akio Tajima (arton)
前提
• ソースレベルで調べたのもあるし、帰納的にこうだろうと推測
して対応したものもあるので、「いや、それは違う」があれば
教えてください!
• Ruby 2.6
• Rails 5.2
• CapybaraはChromeDriver+Selenium::WebDriver
コントローラ修正でハングアップ(dev)
• ソース追っかけたけどわかってない
• renderで他のコントローラを呼び出す場合に発生しているよう
に見える ex) render_to_string ‘他のコントローラ/アクション’
• リクエストによってコントローラが再ロードされた場合に、ク
ラスロードのロックがかかって他のコントローラをロードでき
なくなるのではと疑っている。
• ワークアラウンド: 内部で他のコントローラを呼ばないリクエ
ストを最初に呼び出す
JavaScriptの例外の検出
• spec/system/system_helperに以下のメソッドを登録して利用(stackoverflow)
• 元のGemfileがgem ‘capybara’, ‘~> 2.13’だったので、その時点の最新の3.32に修正が必要だった。合わせてChromeDriverの
更新も必要だった。
def no_js_error
logs = page.driver.browser.manage.logs.get(:browser)
logs.each do |log|
if log.level == 'SEVERE' && ['Uncaught', 'exception'].any? {|key| log.message.include?(key) }
logs.each do |log|
Rails.logger.debug "!!!! JavaScript error: #{log.level}: #{Time.at(log.timestamp / 1000)}: #{log.message}"
end
return log.message
end
end
nil
end
$が見つからないエラーでsystemスペック全滅
• 前回のrspec実行時のchromeが居残っている
• 親プロセスが1のchromeを殺す
Capybaraのfill_inやsetの取りこぼし
• 検索するとイッシューも見つかるし困っている人もいるが未解決
• タイミング(ChromeDriverとのインターフェイス時)依存のような
ので、あきらめる。
def exactly_set(selector, val)
until page.find(selector).value == val
page.find(selector, wait: 1).set(val)
sleep 0.1
end
end
clickのクリックミスは困る(ダブルクリックになると別の問題)
まともなCapybara用ドライバーが欲しい
ね
リクエスト―レスポンスベース時代であればよいが、
DOMのレベルでダイアログを表示したり非表示したりするスタ
イルと、非同期でChromeDriverなどにリクエストを出して結果
を見ずに返って来るCapybara(のドライバー)の仕組みが合っ
ていない。
https://medium.com/@yuliaoletskaya/capybara-inconsistent-
click-behavior-and-flickering-tests-f50b5fae8ab2
(直接JSでonclickを呼び出すソリューション 2018年)
DOMを操作する場合はとにかくexpect
page.find(selector1).click # selector2の要素が表示されるはず
page.find(selector2)…
でたまにselector2が見つからないエラーになる。
findは見つからなければエラーだがexpectは見つかるまである程度待
機するのでまずexpectを入れる
Capybara.default_max_wait_time = 5 # デフォルトは2
…
page.find(selector1).click
expect(page).to have_css(selector2)
page.find(selector2)…
expectにメッセージを追加
個別にexpectすれば行番号から問題個所はわかるがそうは言って
も群で処理したい場合はある。
Rails.root.join(‘config/routes.rb’).each_line do |route|
if /¥A¥s*(¥w+)¥s+’([^’]+)’/ =~ route
method, path = $1, $2
if method == ‘get’
resp = http.get(“/#{path}”) unless path.start_with?(‘login’)
expect(resp.code).to eq(403), “#{path}がやばたにえん”
receive
呼出し回数目毎のスペック
expect_any_instance_of(obj).to receive(:method).twice do |obj, args…|
~
end.and_return(…)
ブロックを取るメソッドへの介入
receive(:method).with(/check/, /check/) do |arg1, arg2, &arg3|
arg3.call(…)
end

More Related Content

More from Akio Tajima

DSLの過去と未来
DSLの過去と未来DSLの過去と未来
DSLの過去と未来Akio Tajima
 
Decades around here
Decades around hereDecades around here
Decades around hereAkio Tajima
 
RJB - another choice for Ruby and Java interoperability
RJB - another choice for Ruby and Java interoperabilityRJB - another choice for Ruby and Java interoperability
RJB - another choice for Ruby and Java interoperabilityAkio Tajima
 
Ruby on windows 2010
Ruby on windows 2010Ruby on windows 2010
Ruby on windows 2010Akio Tajima
 
Ruby – The Scripting Language
Ruby – The Scripting LanguageRuby – The Scripting Language
Ruby – The Scripting LanguageAkio Tajima
 
Ruby Extended Library
Ruby Extended LibraryRuby Extended Library
Ruby Extended LibraryAkio Tajima
 

More from Akio Tajima (11)

DSLの過去と未来
DSLの過去と未来DSLの過去と未来
DSLの過去と未来
 
Nougakudo
NougakudoNougakudo
Nougakudo
 
Decades around here
Decades around hereDecades around here
Decades around here
 
RJB - another choice for Ruby and Java interoperability
RJB - another choice for Ruby and Java interoperabilityRJB - another choice for Ruby and Java interoperability
RJB - another choice for Ruby and Java interoperability
 
Ruby on windows 2010
Ruby on windows 2010Ruby on windows 2010
Ruby on windows 2010
 
Ruby – The Scripting Language
Ruby – The Scripting LanguageRuby – The Scripting Language
Ruby – The Scripting Language
 
Asr
AsrAsr
Asr
 
N Lize
N LizeN Lize
N Lize
 
Ruby Extended Library
Ruby Extended LibraryRuby Extended Library
Ruby Extended Library
 
Yarvmi
YarvmiYarvmi
Yarvmi
 
Rubyize
RubyizeRubyize
Rubyize
 

Rails,RSpec & Capybara で困った話