debug
debug copied to clipboard
Chrome hang with Capybara and RSpec
Your environment
ruby -v:ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [arm64-darwin20]rdbg -v:rdbg 1.3.1(f5ff7f7)- OS: macOS 11.6 20G165
Describe the bug
When running Capybara and RSpec with Chrome under a certain condition, Chrome hangs.
This never occurs with the child / parent fork mode. It occurs only with the both fork mode (default).
To Reproduce
I prepare a repository for reproduction. Please follow the instruction on the README: https://github.com/ybiquitous/ruby-debug-with-capybara
https://user-images.githubusercontent.com/473530/138542439-59d77839-886b-4f6b-bf9b-37f05cd538f9.mov
Note: Here is a simplified version on Gist (thanks to @nishio-dens): https://gist.github.com/nishio-dens/c64245eb143e9c3b22b9d7b9f93f25d2
Expected behavior
I think Chrome should not hang.
Additional context
None.
OMG: "Failed to find Chrome binary." my WSL2 environment it's difficult...
without chrome (with REPL), do you have same trouble?
without chrome (with REPL), do you have same trouble?
No, this problem occurs with Capybara and Chrome (also headless mode).
OMG: "Failed to find Chrome binary." my WSL2 environment it's difficult...
Oh, I can reproduce it with macOS. The webdrivers gem's instruction might help you, but it seems limited...
https://github.com/titusfortner/webdrivers#wslv2-support
Thank you for the information. @ono-max san can you try it?
Temporarily, is there a way to stop the debug server only when starting Capybara?
Unfortunately, there is no way to disable debugger now. I'll consider.
This never occurs with the child / parent fork mode. It occurs only with the both fork mode (default).
Instead of disabling the debugger, you can choose child or parent debug mode (maybe parent mode is fine for you).
On the debugger REPL:
> config set fork_mode parent
On the Ruby code:
DEBUGGERR__::CONFIG[:fork_mode] = :parent
@ko1 Thank you for the helpful advice! The workaround works. 👍🏼
FYI. The following code via ENV also works:
ENV["RUBY_DEBUG_FORK_MODE"] ||= "parent"
Spent hours debugging why starting multiple browsers (Chrome or Firefox) with Capybara failed to close them all (it only ever closed the last one created). Turned out it was the #at_exit call here:
https://github.com/ruby/debug/blob/3b3ce8ff51d85b39422d7a0e96c9e2ab3c2973d0/lib/debug/local.rb#L93-L105
Everytime Capybara forked off a new browser it would register a new #at_exit to clean itself up here:
https://github.com/teamcapybara/capybara/blob/a12915a6ae6faf1f79445ccd9e2b29d4c3850d7a/lib/capybara/selenium/driver.rb#L509-L514
So when these were called in reverse order of creation, it would clean up the latest browser then hit the #at_exit created from #after_fork_parent and block forever. It would never make it to the next browser to clean it up.
Finally found this issue and after setting the environment variable RUBY_DEBUG_FORK_MODE=parent it all works.
Adding the debug gem broke my Capybara setup (rspec would never exit), but as some other people mentioned running my specs with RUBY_DEBUG_FORK_MODE=parent bin/rspec solved it.
Not sure whether this is an issue with debug or Capybara, but would be great to get it resolved so everything works out-of-the-box without requiring ENV vars.
Thank you for heading up. Can you confirm that the process is hung around https://github.com/ruby/debug/blob/master/lib/debug/local.rb#L101 ?
Hi @ko1 👋
Long time no see! I found myself looking at a very similar situation when running rspec tests with Capybara today. The rspec process never completes. The main thread is hung up on the local.rb line that you referenced above:
/Users/.../ruby/3.1.1/lib/ruby/gems/3.1.0/gems/debug-1.6.1/lib/debug/local.rb:101:in `waitpid'
/Users/.../ruby/3.1.1/lib/ruby/gems/3.1.0/gems/debug-1.6.1/lib/debug/local.rb:101:in `block in after_fork_parent'
The spec forked twice (Once for a capybara server and once to run an external pdflatex command.):
DEBUGGER: Attaching after process 5803 fork to child process 6425
DEBUGGER[/Users/.../ruby/3.1.1/bin/rspec#6460]: Attaching after process 5803 fork to child process 6460
Things work well if the spec only forks once.
I'm happy to provide additional details if they help to narrow down the problem.
Thank you, could you make a small repro-code?
My first attempts in making a reproduction were not successful. It's very possible that I'm missing a detail that triggers the condition in our main codebase. There are a lot of moving parts and layers involved that could make a difference.
I'll try a bit more but I'm not sure I'll be able to isolate the behavior.
I am seeing the same behavior with Capybara + RSpec + selenium at the moment. In my case I am registering a custom chrome driver:
Capybara.register_driver :selenium_chrome_headless_with_downloads do |app|
browser_options = Selenium::WebDriver::Chrome::Options.new
[
"--no-sandbox",
"--headless",
"--disable-site-isolation-trials",
"--disable-dev-shm-usage"
].each { |arg| browser_options.add_argument(arg) }
browser_options.add_preference(:download, prompt_for_download: false, default_directory: DownloadHelpers::PATH.to_s)
browser_options.add_preference(:browser, set_download_behavior: {behavior: "allow"})
Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: [browser_options])
end
If any tests driven by this driver run then rspec fails to exit. Interestingly tests driven by the standard selenium_chrome_headless driver don't have this problem.
I currently have DEBUGGER__::CONFIG[:fork_mode] = :parent at the top of my config file and that seems to have solved the problem.