Selenium + Ruby + Cucumber. Weird port error - ruby

# encoding: UTF-8
# language: ru
require 'webdrivers'
require 'selenium-cucumber'
options = Selenium::WebDriver::Options.chrome
driver = Selenium::WebDriver.for :chrome, options: options
#driver.get "https://www.google.com"
Given 'Переходим на сайт' do
driver.get "https://www.google.com"
end
sleep(2)
driver.quit
File .feature
# encoding: UTF-8
# language: ru
Функция: Тест
Сценарий: Тест тест
Дано Переходим на сайт
The code is as simple as possible. And it works if you remove the Given function and start opening the site not through cucumber. Everything works and opens. But if you open it through Given, an incomprehensible error with ports appears.
Failed to open TCP connection to 127.0.0.1:9515 (Connection refused - connect(2) for "127.0.0.1" port 9515) (Errno::ECONNREFUSED)
./features/step_definitions/test_steps.rb:23:in `nil'
Linux Mint

This is likely due to lazy initialization in Selenium. When you call driver.get "https://www.google.com" directly it's initializing the selenium driver and browser connection, so when driver.quit is called the connection is up and can then be cleanly shut down. However, when you call
Given 'Переходим на сайт' do
driver.get "https://www.google.com"
end
you are defining a block that can be called later, but it doesn't actually execute the driver.get ... yet, so the driver to browser connection isn't fully setup yet which leads to quit being called on a non-initialized connection and therefore raising an error.

Related

Selenium Webdriver connection timing out while running automation tests

While running automation tests I sometimes get a timeout error for Selenium Webdriver (I think this is where the issue is at least). Me and my team have all recently migrated to Macbooks (from a combination of Windows and Ubunutu machines) and are all getting this behaviour.
While running a suite of tests I will (seemingly at random) get the following error output in the console:
Errno::ETIMEDOUT: Failed to open TCP connection to 127.0.0.1:9515 (Operation timed out - connect(2) for "127.0.0.1" port 9515)
This doesn't happen consistently, sometimes I'll run a pack and not have any such errors, sometimes I'll have multiple occurrences.
Here is the code which registers the driver (in case anything here points to what the issue could be):
Capybara.register_driver :selenium do |app|
opts = Selenium::WebDriver::Chrome::Options.new
opts.add_argument '--start-maximized'
opts.add_argument 'disable-infobars'
opts.add_argument '--disable-notifications'
opts.add_preference(:safebrowsing,
enabled: true)
opts.add_preference(:browser, set_download_behavior: { behavior: 'allow' })
Capybara::Selenium::Driver.new(app, browser: :chrome, options: opts)
end
The gems I am using are Capybara (3.11.0), Cucumber (3.1.0) and Selenium-webdriver (3.141.0). I have ChromeDriver(73.0.3683.68) installed via HomeBrew
Has anyone encountered this issue and worked out what the cause is?
Port 9515 is the default port chromedriver runs on. If you happen to be using Chrome/chromedriver v74 try rolling back to 73 or forward to 75 - 74 has been reported to have issues where it will randomly hang.
Another potential solution is to upgrade to Capybara >= 3.16.0 which defaults to using a persistent connection to chromedriver. This would mean less opening/closing of connections and less chance for chromedriver to hang during connection establishment.

Ruby Selenium ignoreProtectedModeSettings not working

I am working in a office environment and security settings in IE are disabled for all the users and also we cant modify windows registry, below code to disable protected mode is not working
I am using Ruby, Cheezy Pageobject & selenium
Before do
cap = Selenium::WebDriver::Remote::Capabilities.ie(:ignoreProtectedModeSettings=>true,:ignoreZoomSetting=>true,:unexpectedAlertBehaviour=>"accept")
#browser = Selenium::WebDriver.for :ie,:desired_capabilities=>cap
#browser.manage.window.maximize
end
I am getting below error message
Selenium::WebDriver::Error::NoSuchDriverError: Unexpected error launching Internet Explorer. Protected Mode settings are not the same for all zones. Enable Protected Mode must be set to the same value (enabled or disabled) for all zones.
./features/support/env.rb:40:in `Before'
Skipped step
Skipped step
Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it. - connect(2) for "10.78.224.114" port 5554
./features/support/hooks.rb:47:in `After'
NoMethodError: undefined method `close' for nil:NilClass
./features/support/env.rb:48:in `After'
1 scenario (1 failed)
8 steps (8 skipped)
0m7.959s

Chromedriver remote-debugging-port with Selenium

I am using Capybara Selenium to run headless Chrome, which works great, except I cannot figure out how to use remote debugging. When I add --remote-debugging-port=4444 or --remote-debugging-port=9222 or --remote-debugging-port=9521, Selenium no longer connects to the browser to run the test.
How do I get remote debugging to work? Here is my code for reference:
Capybara.register_driver :selenium do |app|
# from https://github.com/SeleniumHQ/selenium/issues/3738
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: {browser: 'ALL'})
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument '--disable-infobars' # hide info bar about chrome automating test
# if we don't use this flag, every selenium test will die with the error:
# "unknown error: Chrome failed to start: exited abnormally"
options.add_argument '--no-sandbox'
# BREAKS THINGS if uncommented
# options.add_argument '--remote-debugging-port=4444'
options.add_argument '--headless'
options.add_argument '--window-size=1600,2400'
options.add_preference('profile.default_content_settings.popups', 0)
options.add_preference('download.default_directory', DownloadHelpers::PATH.to_s)
Capybara::Selenium::Driver.new(
app,
clear_local_storage: true,
clear_session_storage: true,
browser: :chrome,
options: options,
desired_capabilities: capabilities,
)
end
Since chrome 67 and chromedriver 2.39, chromedriver now correctly uses the port you specify with --remote-debugging-port. This removes quite a bit of complexity from my answer above. The steps I now take, which work for my use case of needing to configure download settings using chrome_remote, are as follows:
It makes uses of a nodejs library, crmux - which allows multiple clients to connect to the remote debug port of chrome at the same time.
Get nodejs installed first: Nodejs v9.7.0 works fine
Install crmux by running npm install crmux -g
Before you start chromedriver (Capybara::Selenium::Driver.new), you need to spawn a separate thread that will fire up crmux, which will let both you and chromedriver communicate with chrome itself via the port you specified in Capybara (4444):
crmux --port=4444 --listen=4444
You may want to add a sleep 3 after the spawn command in the main script/thread to give time for crmux to start before you continue with your test startup.
You can then use chrome_remote (for example) to access chrome using port 4444, while capybara is doing its thing.
Updating my ChromeDriver fixed it for me. I didn't have to do anything else. Before it would hang when attempting to start the test.
Specifically I was on ChromeDriver 2.36 and I upgraded to ChromeDriver 2.40. I don't think the Chrome version was a problem, since I was on Chrome 67 both before and after.
Here's how I'm registering the driver:
Capybara.register_driver :headless_chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
chromeOptions: { args: %w[headless window-size=1280,960 remote-debugging-port=9222] }
)
Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: capabilities)
end
After that I ran my test with a debugger (binding.pry) placed where I wanted to inspect. Then when I hit the debugger I navigated to http://localhost:9222/ in a normal instance of Chrome and was able to follow a link to view what was happening in the headless Chrome instance, including the browser console output I needed.
Update: if using versions since Chrome 67/chromedriver 2.39, my alternative answer above provides a simpler solution
The core issue here is Chromedriver also uses the remote debugging port connection to communicate with Chrome. This uses the websocket protocol, which only supports a single-client connected at a time. Normally, when chromedriver starts the chromedriver process, it will choose a random free TCP port number and use this to access the remote debug port. If you specify --remote-debuggging-port=9222 however, Chrome will be opened with the debug port you have requested, but chromedriver will silently continue to try and open a connection using this random port number.
The solution I ended up with was heavily inspired by comment 20 in this chromedriver issue. It required quite a bit of code to get it working, but works solidly. It makes uses of a nodejs library, crmux - which allows multiple clients to connect to the remote debug port of chrome at the same time.
Get nodejs installed first: Nodejs v9.7.0 works fine
Install crmux by running npm install crmux -g
Before you start chromedriver (Capybara::Selenium::Driver.new), you need to spawn a separate thread that will do a few things: look for the remote debug port chromedriver is trying to use to connect to chrome, and then use this to fire up crmux. Once this has happened Capybara etc will work as normal.
My separate thread runs a ruby script that first executes a netstat command repeatedly until it finds the relevant entry for chromedriver (TCP status is SYN_SENT). This separate thread must continue to run in the background while chrome is up and running.
The code for this is:
$chrdrv_wait_timeout = 60
$chrdrv_exe = "chromedriver.exe"
def get_netstat_output
stdout = `netstat -a -b -n`
stat_lines = stdout.split("\n")
stat_lines
end
def try_get_requested_port
socket_state = "SYN_SENT" # i.e. sent with no reply
statout = get_netstat_output
n = statout.length
i = 0
loop do
i += 1
# find lines relating to chromedriver
exe_match = /^ +\[#{$chrdrv_exe}\]$/.match statout[i]
if exe_match != nil
# check preceeding lines which should contain port info
port_match = /TCP.*:([0-9]+)\W+#{socket_state}/.match statout[i-1]
if port_match != nil
return port_match[1].to_i
end
end
break unless i < n
end
return nil
end
def get_tcp_port_requested_by_chromedriver
i = 1
loop do
puts "Waiting for #{$chrdrv_exe}: #{i}"
port = try_get_requested_port
if port != nil
return port
end
break unless i < $chrdrv_wait_timeout
sleep 1
i += 1
end
raise Exception, "Failed to get TCP port requested by #{$chrdrv_exe} (gave up after #{$chrdrv_wait_timeout} seconds)"
end
(I'm working in Windows: for Mac/Linux the netstat syntax/output is probably different so the code will need adjustment; the key thing is you need it to output the executable owner of each connection entry - and parse the bit relating to chromedriver to get the port in question).
Once this has found the random port (I'll use 12225 as an example), the background ruby script can then execute a crmux process, which will reunite chromedriver with chrome itself via the port you specified in Capybara (4444):
crmux --port=4444 --listen=12225
Finally, this separate script saves the discovered listen port to a text file. This allows the main script/thread that is running capybara to know the port number it can use to get access to chrome (via crmux's multiplexed connection) by reading in the port from that file. So you can then use chrome_remote to access chrome using port 12225, for example, while capybara is doing its thing.

Open browser with URL in Ruby

I've been using the following to launch the default browser in OS X:
system('open', url)
This has been working fine until upgrading to Yosemite. Now, I frequently get this message when trying to open various URLS:
LSOpenURLsWithRole() failed with error -1712 for the URL http://blah.com
But sometimes that URL will work. I can try it once, and it'll work, another it might not. Very unpredictable.
I've tried all of these:
system("open #{url}")
`open #{url}`
Launchy.open(url, debug: true)
Launchy.open( "#{ url }" ) do |exception|
puts "Attempted to open #{url} and failed because #{exception}"
end
But they all exhibit this same behavior. There are several URLs being opened at once, like this:
urls.each do |url|
system("open #{url}")
end
How can I consistently open a specific URL in my browser on OS X using ruby?
It looks like you are pushing the Browser with too many urls at the same time.
Using sleep seems to work fine.
15.times {|i| `open http://google.com?q=#{i}` }
# LSOpenURLsWithRole() failed with error -1712 for the URL http://google.com?q=5.
# LSOpenURLsWithRole() failed with error -1712 for the URL http://google.com?q=6.
# LSOpenURLsWithRole() failed with error -1712 for the URL http://google.com?q=12.
# LSOpenURLsWithRole() failed with error -1712 for the URL http://google.com?q=14.
# => 15
15.times {|i| sleep(0.2); `open http://google.com?q=#{i}` }
# => 15

Getting pop-up error "Netscape.cfg/AutoConfig failed" when trying to drive firefox via selenium Grid using Watir-Webdriver

Get Error:
Netscape.cfg/AutoConfig failed. Please contact your system administrator.
Error: defaultPref failed: [Exception... "Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.setBoolPref]" nsresult: "0x8000ffff (NS_ERROR_UNEXPECTED)" location: "JS frame :: prefcalls.js :: defaultPref :: line 58" data: no]
Netscape.cfg/AutoConfig failed. Error: defaultPref failed: [Exception... "Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED)
I have the following setup:
Selenium Grid on CentOs 6.4
Slave Node = CentOs 6.4
Trying to run Firefox remotely via Watir-WebDriver
require "rubygems"
require "test/unit"
#require "selenium"
require "watir-webdriver"
caps = Selenium::WebDriver::Remote::Capabilities.firefox
#caps.version = "24"
caps[:name] = "Firefox 24 , port 5555"
default_profile = Selenium::WebDriver::Firefox::Profile.from_name "default"
default_profile.native_events = true
driver = Selenium::WebDriver.for(:firefox, :profile => default_profile)
#browser = Watir::Browser.new(
:remote,
:url => "http://vm-auto.his.vm:4444/wd/hub",
:desired_capabilities => caps)
#browser.goto "google.com"
#browser.text_field(:name => "q").set "3M"
#browser.button.click
#browser.div(:id => "resultStats").wait_until_present
#browser.screenshot.save ("GoogleSearch_FF24.png")
#browser.close
Firefox version is Mozilla Firefox 24.7.0
there is a reference to this error in https://bugzilla.mozilla.org/show_bug.cgi?id=717438
the resolution being suggested as:
In my case commenting out this pref in mozilla.cfg stops generating this message.
But I do not know origin of this pref.
//stops the request to send performance data from displaying
//pref("toolkit.telemetry.prompted", true);
But, i could not find mozilla.cfg on the filesystem where firefox is installed
That error definitely seems to be related to a problem in the mozilla config file BUT in my case the file was not mozilla.cfg but mozilla-lock.cfg (located at C:\Program Files (x86)\Mozilla Firefox\).
The filename is dictated by the lockset.js file at C:\Program Files (x86)\Mozilla Firefox\defaults\pref\. The line is pref("general.config.filename", "mozilla-lock.cfg")
My issue with the config file was the following lines:
lockpref("security.tls.version.min", "1");
lockpref("security.tls.version.max", "3");
The values should be without quotes:
lockpref("security.tls.version.min", 1);
lockpref("security.tls.version.max", 3);
As addendum, it's entirely possible you don't have a config file at all and the problem exists with a manual configuration in the about:config. Open up the about:config page, and sort by 'status' to look for 'locked', 'user set' or any other non 'default' items.
I had the same issue with Firefox 24 ESR. Mozilla.cfg was in the same directory as the Firefox executable.
In my case this was under "%localappdata%\Microsoft\AppV\Client\Integration[Unique-Code]\Root".
I commented out 'pref("toolkit.telemetry.prompted", true);' and the error message didn't appear anymore.

Resources