titusfortner / webdrivers

Keep your Selenium WebDrivers updated automatically
MIT License
592 stars 113 forks source link

[3.7.0] Doesn't work with chromium on Linux #38

Closed boris-petrov closed 5 years ago

boris-petrov commented 5 years ago

I guess the issue is here. This checks for google-chrome while I, for example, use chromium. The code should be made to handle that scenario.

Errno::ENOENT:
  No such file or directory - google-chrome
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/chromedriver.rb:82:in `chrome_on_linux'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/chromedriver.rb:64:in `chrome_version'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/chromedriver.rb:55:in `release_version'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/chromedriver.rb:19:in `latest_version'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/common.rb:37:in `desired_version'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/common.rb:16:in `update'
# ./features/build/tmp/jrubyExec/gems/webdrivers-3.7.0/lib/webdrivers/selenium.rb:7:in `driver_path'
# ./features/build/tmp/jrubyExec/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/chrome/driver.rb:39:in `initialize'
# ./features/build/tmp/jrubyExec/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/common/driver.rb:44:in `for'
# ./features/build/tmp/jrubyExec/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver.rb:86:in `for'
# ./features/build/tmp/jrubyExec/gems/capybara-3.15.0/lib/capybara/selenium/driver.rb:32:in `browser'
# ./features/build/tmp/jrubyExec/gems/capybara-3.15.0/lib/capybara/selenium/driver.rb:139:in `current_window_handle'
# ./features/build/tmp/jrubyExec/gems/capybara-3.15.0/lib/capybara/session.rb:438:in `current_window'
# ./features/spec_helper.rb:89:in `block in <main>'
kapoorlakshya commented 5 years ago

Hi @boris-petrov, thanks for reporting this. I'll try to add support for chromium as soon as I can. Hopefully this weekend.

kapoorlakshya commented 5 years ago

I'll need to discuss this with @titusfortner before implementing it, but I think a flag like this would fit your use case:

Webdrivers::Chromedriver.use_chromium = true

The other option is to check for what is installed and use it to retrieve the version. However, that won't work well if you have both google-chrome and chromium-browser installed because whatever is checked for first will always be used.

boris-petrov commented 5 years ago

Well, the best user-experience would be to check for google-chrome and chromium (note there is no -browser on the executable name) and if there is only one of them, use it. If they are both there (very rarely probably), only then use some configuration option which could be Webdrivers::Chromedriver.chrome_executable = 'chromium' or something.

titusfortner commented 5 years ago

Ah, I knew I overlooked something. We should be pulling from Chrome.path https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/chrome.rb

Users can have multiple installations of chrome, and that's the best place to specify.

We should also probably be using the same code as selenium for locating the default path rather than specifying it.

kapoorlakshya commented 5 years ago

@boris-petrov Which distro and version of Chromium are you using? I checked on CentOS 7.6 and Ubuntu 14.04, and the installed executable is named chromium-browser for me. Just curious what's causing the difference here.

@titusfortner That makes sense. So if I understand correctly, this would be the ideal approach then:

  1. Check Selenium::WebDriver::Chrome.path. Use if path is not nil.
  2. If it is nil, check for Google Chrome.
  3. If Google Chrome is not installed, check for Chromium.
  4. Error -> Google Chrome or Chromium not found.

I am okay with skipping check 3 and including a note in the README for Chromium users.

boris-petrov commented 5 years ago

@kapoorlakshya - Arch Linux, latest Chromium - 73.0.3683.86. The executable is /usr/bin/chromium.

kapoorlakshya commented 5 years ago

@boris-petrov Thanks! I'm glad it won't be a problem as Titus's recommendation will allow us to work around this difference :)

kapoorlakshya commented 5 years ago

Released v3.7.1. Please let me know if you run into any other issues.

boris-petrov commented 5 years ago

@kapoorlakshya - well, 3.7.1 still doesn't work for me. :) Selenium.WebDriver::Chrome.path is nil in my case and the fallback for google-chrome obviously doesn't work. Is Selenium.WebDriver::Chrome.path supposed to be set automatically or is it something that I should set?

kapoorlakshya commented 5 years ago

@boris-petrov You should set Selenium.WebDriver::Chrome.path = '/usr/bin/chromium' in your case. This will always override the default Google Chrome path.

EDIT: Wrap path in single quotes.

boris-petrov commented 5 years ago

@kapoorlakshya - I see, but why does Capybara/Selenium work even without this? How does it find the correct Chrome to use and why can't webdrivers do the same?

kapoorlakshya commented 5 years ago

@boris-petrov From what I know, this is where Selenium looks for the Chrome binary:

  1. OS specific default install locations as mentioned here.
  2. Selenium.WebDriver::Chrome.path for non-standard locations.
  3. Selenium::WebDriver::Chrome::Options.binary also for non-standard locations as mentioned here.

webdrivers offers options 1 and 2. I'm not sure if Capybara has their own implementation or if they rely on Selenium to figure it out. You could ask @twalpole.

P.S. If you're curious how Chrome itself does it, you can read through the code here.

boris-petrov commented 5 years ago

@kapoorlakshya Thanks for the answer. I will use Selenium.WebDriver::Chrome.path, that's fine, I'm just wondering how Capybara with Selenium finds my Chromium without this option. Obviously there is some other mechanism somewhere. Anyway, thanks!

twalpole commented 5 years ago

Capybara doesn't do any location of the executable - that is all done by selenium unless you've overridden it in your capybara driver registration.

boris-petrov commented 5 years ago

@kapoorlakshya, @twalpole - the funny thing is that we have nothing in our configuration and our setup works fine on my machine (Arch Linux, chromium binary) and on our CI (Ubuntu, chromium-browser binary). This is with webdrivers 3.6.0. 3.7.0+ doesn't work by default, I have to configure it specifically for each machine (which is mildly annoying). My guess would be, given that Capybara doesn't do anything special, that chromedriver knows how to find the correct browser. So my idea was that webdrivers could delegate to it the job, or if there is no command-line/API for that, copy-paste the logic? As otherwise many people like me will have to provide options in their own code for specifying the executable on different platforms...

titusfortner commented 5 years ago

I think Issue #45 is what we probably need to implement for it to do what you want.

RyanTG commented 5 years ago

Could anyone hold my hand and tell me where exactly Selenium.WebDriver::Chrome.path = /usr/bin/chromium should be added? I keep getting syntax errors - this isn't my bread and butter. (we're currently using chromedriver-helper still, but I wanted to see if switching to webdrivers will magically fix a capybara/headless issue I'm experiencing on my linux box).

https://github.com/RyanTG/pbm/blob/master/spec/spec_helper.rb

and when using webdrivers, should I remove require 'selenium/webdriver' from spec_helper?

kapoorlakshya commented 5 years ago

@RyanTG Please share the exact error.

Selenium::WebDriver::Chrome.path = /usr/bin/chromium should be set before you initialize the browser. And you do not need to require selenium-webdriver in your project. Requiring this gem already does it for you.

Please note that it's selenium-webdriver with a hyphen and not selenium/webdriver.

boris-petrov commented 5 years ago

@RyanTG - it should be Selenium::WebDriver::Chrome.path, not Selenium.WebDriver::Chrome.path. That's the syntax error you're getting.

kapoorlakshya commented 5 years ago

@boris-petrov Good catch!

RyanTG commented 5 years ago

Thanks!

The error is

An error occurred while loading ./spec/controllers/application_controller_spec.rb.
Failure/Error: require 'spec_helper'

SyntaxError:
  /home/rgratzer/Documents/pinball/pbm/spec/spec_helper.rb:32: unknown regexp option - b
# ./spec/controllers/application_controller_spec.rb:1:in `require'
# ./spec/controllers/application_controller_spec.rb:1:in `<top (required)>'

Line 32 is where the I'm trying to set the path. I've tried putting it in lots of places in spec_helper.

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'factory_bot_rails'
require 'rspec/rails'
require 'capybara/rspec'
require 'simplecov'
require 'coveralls'
require 'rack_session_access/capybara'
require 'rspec/retry'
require 'webdrivers'
# require 'selenium/webdriver'

include Sprockets::Rails::Helper

SimpleCov.start
Coveralls.wear!

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

RSpec.configure do |config|
  config.verbose_retry = true
  config.display_try_failure_messages = true

  config.around :each, :js do |ex|
    ex.run_with_retry retry: 3
  end

   Selenium::WebDriver::Chrome.path = /usr/bin/chromium      

  Capybara.register_driver :chrome do |app|
    Capybara::Selenium::Driver.new(app, browser: :chrome)
  end

  Capybara.register_driver :headless_chrome do |app|
    capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
      chromeOptions: { args: %w[headless disable-gpu window-size=2000,1000] }
    )

    Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: capabilities)
  end

  Capybara.javascript_driver = :selenium_chrome_headless
...
kapoorlakshya commented 5 years ago

/usr/bin/chromium should be wrapped in single quotes, like this:

Selenium::WebDriver::Chrome.path = '/usr/bin/chromium'

RyanTG commented 5 years ago

Oh jeez. I really should have been pasting from the readme, and not https://github.com/titusfortner/webdrivers/issues/38#issuecomment-477007343

Works now - thanks for your help! And this confirmed that the tests that are failing on headless in linux, but not chrome in linux and not headless or chrome on mac are still failing even after switching to webdrivers (which was a long shot, but I'm grasping at straws here).

kapoorlakshya commented 5 years ago

Oops... updated my comment. Good luck with your test!

twalpole commented 5 years ago

@RyanTG It was unlikely switching from chromedriver-helper to webdrivers would fix any issue -- it all ends up running the same things. For issues with headless in linux have you tried adding the --disable-dev-shm-usage flag to Chrome?

RyanTG commented 5 years ago

I hadn't. But I tried it just now, and it didn't improve my situation. Thanks for that tip, though.

My test involves clicking a button that expands a div to load a select. Then choosing an item from the select. With save_and_open_page it appears that some of the js isn't present, and thus the select isn't loading. Increasing sleep didn't fix it. I struggle to troubleshoot this, because I'm not sure which things could be contributing (postgresql, ruby, chromium, etc). Like, could downgrading chromium help?

twalpole commented 5 years ago

@RyanTG It's highly unlikely to have anything to do with Postgresql or ruby itself. Assuming you're running current versions of chromium It's going to be something to do with a setting for the browser - for instance you're only setting a window size in headless mode -- try setting headless and headful to the same window size and see if the problem goes away/exists on both, or why are you disabling the GPU (that's only needed on windows). Also use save_and_open_screenshot to see what's actually being rendered. Anyway this is getting off-topic for the webdrivers gem - if you can provide access to a simple example that shows the issue file an issue over on the Capybara project and I'll take a look.

titusfortner commented 5 years ago

Another option if you're on Linux is to use the headless gem instead of the browser's headless mode