In Selenium webdriver, for remote Firefox how to use OSS bridge instead of w3c bridge for handshaking

787 Views Asked by At

I am using selenoid for remote browser testing in ruby. In that I am using 'selenium-webdriver', 'capybara', 'rspec' for automation. And I am using attach_file method for uploading file to browser I want to upload file on Firefox and Chrome browser but it raises error on both;

In chrome

Selenium::WebDriver::Error::UnknownCommandError: unknown command: unknown command: session/***8d32e045e3***/se/file

In firefox

unexpected token at 'HTTP method not allowed'

So After searching I found the solution for chrome which is to set w3c option false in caps['goog:chromeOptions'] > caps['goog:chromeOptions'] = {w3c: false} So now chrome is using OSS bridge for handshaking but I don't know how to do it in Firefox. Similar solution is not available for Firefox. My browser capabilities are following:

if ENV['BROWSER'] == 'firefox'
    caps = Selenium::WebDriver::Remote::Capabilities.new
    caps['browserName'] = 'firefox'
    # caps['moz:firefoxOptions'] = {w3c: false} ## It is not working
  else
    caps = Selenium::WebDriver::Remote::Capabilities.new
    caps["browserName"] = "chrome"
    caps["version"] = "81.0"
    caps['goog:chromeOptions'] = {w3c: false}
  end
    caps["enableVNC"] = true
    caps["screenResolution"] = "1280x800"
    caps['sessionTimeout'] = '15m'

  Capybara.register_driver :selenium do |app|  
    Capybara::Selenium::Driver.new(app, browser: :remote,
    :desired_capabilities => caps,
    :url => ENV["REMOTE_URL"] || "http://*.*.*.*:4444/wd/hub"
    )
  end

  Capybara.configure do |config|  
   config.default_driver = :selenium
  end
3

There are 3 best solutions below

0
On BEST ANSWER

I have found the problem. There is bug in selenium server which run on java so I have to change my selenium-webdriver gem version 3.142.7 and monkey-patch. You can find more information here about the bug and resolution.

For now I have to change my gem and monkey patch the selenium-webdriver-3.142.7\lib\selenium\webdriver\remote\w3c\commands.rb file. check for below line which is on line no 150.

upload_file: [:post, 'session/:session_id/se/file']

and update it to

upload_file: [:post, 'session/:session_id/file']
1
On

i had a similar issue with rails 7. the issue is connected with the w3c standard. the core problem is that the webdriver for chrome uses a non-w3c standard url for handling file uploads. when uploading a file, the webdriver uses the /se/file url path to upload. this path is only supported by the selenium server. subsequently, the docker image provided by selenium works fine. yet, if we use chromedriver, the upload fails. more info.

we can solve this, by forcing the webdriver to use the standard-compliant url by overriding the :upload_file key in Selenium::WebDriver::Remote::Bridge::COMMANDS. since, the initialization of this the COMMANDS constant does not happen when the module is loaded, we can override the attach_file method to make sure the constant is set correctly. here the hacky code:

module Capybara::Node::Actions
  alias_method :original_attach_file, :attach_file

  def attach_file(*args, **kwargs)
    implement_hacky_fix_for_file_uploads_with_chromedriver
    original_attach_file(*args, **kwargs)
  end

  def implement_hacky_fix_for_file_uploads_with_chromedriver
    return if @hacky_fix_implemented
    original_verbose, $VERBOSE = $VERBOSE, nil # ignore warnings

    cmds = Selenium::WebDriver::Remote::Bridge::COMMANDS.dup
    cmds[:upload_file] = [:post, "session/:session_id/file"]
    Selenium::WebDriver::Remote::Bridge.const_set(:COMMANDS, cmds)
    $VERBOSE = original_verbose
    @hacky_fix_implemented = true
  end
end
2
On

In Firefox images we support /session/<id>/file API by adding Selenoid binary which emulates this API instead of Geckodriver (which does not implement it).