Ok --
The issue seems to be resolved -- see below for a working solution.
THE PROBLEM =>
Careful with Selenium's Explicit timeout vs Implicit timeout.
I'm using Browserstack to test IE remotely, via Selenium's Ruby Bindings, running tests via RSpec.
The elements I'm querying are google ad divs, I want to be sure we're serving ads across all our platforms. Loading is asynchronous, so I'm ensuring I wait for page load.
When I manually drive selenium from the ruby shell (irb), I am always able to find the elements in IE, versions 9, 10, 11.
Same when I manually navigate to the site in Browserstack's 'Live' in-browser IE emulation.
BUT -- when I run the same commands as I do in the shell programmatically, via RSpec -- my tests fail about 50% of the time.
IE 11 is the hardest hit, failing most tests.
IE 10 tends to fare a little better.
Same tests for Firefox + Chrome are passing.
Dependencies:
ruby '2.3.0'
gem 'selenium-webdriver'
gem 'rspec'
gem 'curb', '~> 0.9.1'
Any ideas?
describe "Testing example.com in production with ie." do
it "loads ads on home page" do
caps = Selenium::WebDriver::Remote::Capabilities.internet_explorer
caps["browser_version"] = "11.0"
caps["os"] = "WINDOWS"
caps["os_version"] = "8"
caps["resolution"] = "1024x768"
caps["browserstack.debug"] = "true"
driver = Selenium::WebDriver.for(:remote,
:url => "http://<my_username>:<my_pw>#hub.browserstack.com/wd/hub",
:desired_capabilities => caps)
driver.navigate.to "http://www.example.com"
wait = Selenium::WebDriver::Wait.new(:timeout => 5) # seconds
verify = []
begin #
wait.until do
verify = driver.find_elements(:css => "div[id^="google_ads"]")
end
ensure
driver.quit
end
expected_ad_count = 5
expect( verify.count ).to eq expected_ad_count
end
end
THE SOLUTION =>
The explicit wait block was failing for IE.
The solution is, after initializing the driver, to configure implicit wait, as follows:
driver = Selenium::WebDriver.for(:remote,
:url => "http://<my_username>:<my_pw>#hub.browserstack.com/wd/hub",
:desired_capabilities => caps)
driver.manage.timeouts.implicit_wait = 5
driver.navigate.to "http://www.example.com"
begin #
verify = driver.find_elements(:css => "div[id^="google_ads"]")
ensure
driver.quit
end
expected_ad_count = 5
expect( verify.count ).to eq expected_ad_count
And -- it works!
As per your test, I believe your script will continue execution even if there are no elements located using the find_elements(:css => "div[id^="google_ads"]") command. This is because explicit wait only waits for a successful execution of the command and a null response for the find elements command is considered successful.
I would suggest you replace explicit wait with implicit wait in your test. This will help you wait until all the elements are loaded in the DOM and then continue with test execution. You can use the following command in your test to add Implicit wait:
driver.manage.timeouts.implicit_wait = 5 # seconds
Alternatively, you can verify whether all the ads have loaded on the webpage either via JavaScript or jQuery command. Once complete, you can continue with test execution.
Related
Issue:
I am not able to login a web application using Capybara, rspec and selenium webdriver.
I am able to fill the username and password to the respective fields, but when i tried to click on login button, application is not logging in. Instead the application returns 'Unprocessable entity' (tried enabling and disabling the cookies). Using Headless chromium 64 Linux.
lib/abcd.rb
def click_login user, password
visit "https://www.******.com/users/sign_in"
fill_in 'user[email]', :with => user
fill_in 'user[password]', :with => password
click_button 'Login'
end
Test case:
require_relative 'lib/*****.rb'
describe 'Visit Websites', type: :feature, driver: :selenium_chrome_headless do
it "TC001_Test case 1" do
click_login "user#account.com", "password123"
expect(page).to have_title "Welcome to home page"
end
output:// application stays in the same page
it "TC002_Test case 2" do
find(:xpath,".account menu").click
expect(page).to have_title "Account details page"
end
driver setup - Approach 1
def setup_driver
Capybara.register_driver :selenium_chrome_headless do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome, options: driver_options, :driver_path => 'bin/chromedriver')
end
Capybara.configure do |config|
config.run_server = false
config.default_driver = :selenium_chrome_headless
end
end
def driver_options
options = Selenium::WebDriver::Chrome::Options.new(binary: 'bin/headless-chromium')
arguments = %w[--headless --disable-gpu --window-size=1280x1696
--disable-application-cache --disable-infobars --no-sandbox
--hide-scrollbars --enable-logging --log-level=0
--single-process --ignore-certificate-errors --homedir=/tmp]
arguments.each do |argument|
options.add_argument(argument)
end
options
end
driver setup - Approach 2
def setup_driver
Capybara.register_driver :selenium_chrome_headless do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome, options: driver_options, :driver_path => 'bin/chromedriver')
end
Capybara.configure do |config|
config.run_server = false
config.default_driver = :selenium_chrome_headless
end
end
def driver_options
options = Selenium::WebDriver::Chrome::Options.new(binary: 'bin/headless-chromium')
arguments = %w[--headless --disable-gpu --window-size=1280x1696
--disable-application-cache --disable-infobars --no-sandbox
--hide-scrollbars --enable-logging --log-level=0
--single-process --ignore-certificate-errors --homedir=/tmp]
arguments.each do |argument|
options.add_argument(argument)
end
options
end
You haven't explained exactly what you're trying to do here (test a local rails app, test a remote app, etc) but overall everything sounds like it is working exactly as expected in a default setup. By default every RSpec test is expected to be fully independent of every other test (you should be able to run any test singly and/or run them all in a random order), so everything gets reset between each test (it block). This means you would need to log in for every test (before blocks can help DRY that up). Also feature tests are different from normal unit tests, you should be testing whole user flows/behaviors rather than just single expectations - otherwise your tests will end up taking hours to run.
For the login issue it sounds like you haven't actually created the account in the system you're testing. If this is a local app you're testing, where you have direct connectivity to the DB you should look into fixtures or factories to help with setting up the correct state for a test. Check your logs to confirm but my guess is you'll see the login is actually failing due to invalid username/password combo.
I'm running automated tests in several environments and need to know what is actually being used at run time.
I'm seeing different issues with identical Ruby scripts and would like to be able to capture as many environmental parameters as possible during the runs so they can be included in the run reports to help narrow down possible causes for the differences.
All environments are running Windows 7 64 SP1 and Ruby 2.0.0p451 (2014-02-24) [i386-mingw32]. Most serious issues are with IE (really??) and all environments are running the same IE version and build.
Any suggestions are most welcome.
pat
You can get the version of a gem from the source_location of a method of one of its classes. For example:
Selenium::WebDriver.method(:for).source_location.first[/selenium-webdriver-\d+(?:\.\d+)*/]
=> "selenium-webdriver-2.53.0"
A bit ugly but I finally got something that works for iedriverserver and chromedriver, the trick being to get the sysout and syserr as well as the pid so the process can be killed.
r, w = IO.pipe
pid1 = Process.spawn('iedriverserver', :out => w, :err => [:child, :out])
puts "#{__LINE__}: #{pid1}"
sleep(1)
k = Process.kill('KILL', pid1)
puts "#{__LINE__}: #{k}"
w.close
pid2, status = Process.wait2
puts "#{__LINE__}: #{pid2}, #{status}"
out = r.read
r.close
puts out
(Finally figured out the code markup... ;) )
You could get the version of the driver by sending the status command to the driver:
require "selenium-webdriver"
driver = Selenium::WebDriver.for :ie
driver.navigate.to "http://stackoverflow.com/"
puts driver.send(:bridge).status
First an introduction to the problem.
We have been testing 5 websites that has 3 instances of testing environments (testing environment, pre-production environment and production environment), so, 3 different URLs, but exact same website.
The workaround with selenium-webdriver and ruby that we use is to set an environment variable, and in the webdriver test cases, we add a "case" in the "before" section of the tests, so is easier to set which instance we need to run our tests.
Now, problem is, that we are starting to use appium to test our APKs, and we are facing the same situation, we have some APKs, that also has 3 instances of testing environments.
Now the question is, if it's possible to implement this with appium, we have the appium.txt but maybe there's another method in which we can have the capabilities and apk in the same ruby file, so we can use a "case" as we do with the websites, because we can't use a case in the appium.txt file.
Here's the appium.txt file:
[caps]
platformName = "Android"
deviceName = "Android"
app = "./application.apk"
appPackage = "com.application.android.player"
appActivity = ".Main"
And here's my spec_helper.rb file:
# encoding: UTF-8
require 'rubygems'
require 'appium_lib'
def setup_driver
return if $driver
#caps = Appium.load_appium_txt file: File.join(Dir.pwd, 'appium.txt')
if using_sauce
upload_app
end
$driver=Appium::Driver.new(#caps)
end
RSpec.configure do |config|
config.before(:each) do
$driver.start_driver
set_wait(10) #Implicit Wait
wait = Selenium::WebDriver::Wait.new(:timeout => 30)
wait.until { find_element(:name,'TÉRMINOS Y CONDICIONES') }
find_element(:id, 'com.application.android.player:id/acceptButton').click
end
config.after(:each) do
$driver.driver_quit
end
end
I've tried a few times now to run a Watir browser and then use the AutoIt ruby library (au3) to access a right click context menu but it wasn't working, turns out the au3 library is disappearing for some reason (I'm a little new to Ruby but when I require it again after the browser opens it comes back false for some reason:
irb(main):001:0> require "au3"
=> true
irb(main):002:0> require "watir-webdriver"
=> true
irb(main):003:0> browser = Watir::Browser.new :chrome
Starting ChromeDriver (v2.3) on port 9515
[4868:5640:1025/104947:ERROR:textfield.h(176)] NOT IMPLEMENTED
=> #<Watir::Browser:0x449008c8 url="about:blank" title="about:blank">
<to "https://github.com/lmmx/watir-paper-scanner/blob/master/bookworm.rb"
[WARNING:..\..\..\..\flash\platform\pepper\pep_module.cpp(63)] SANDBOXED
=> "https://github.com/lmmx/watir-paper-scanner/blob/master/bookworm.rb"
irb(main):005:0> require "au3"
=> false
irb(main):006:0>
I'm guessing that whatever's SANDBOXED is crucial to running au3? The browser still works fine... Will try and update the watir-related things, but I only installed it a week or 2 so it shouldn't be out of date already - anyone help me fix it?
The reason it's returning false is because you have already used
require "au3"
on the top line of your code, so when you require it again it's already there.
I'm using watir in a Windows environment with FireFox 3.6 via FireWatir. I can successfully run a single watir test without issue. I need to be able to either:
a. Create and manage multiple browser instances or tabs from a single test script
or
b. Run two test scripts simultaneously from separate instances of ruby
Currently attempts at both a and b result in both Browser.new commands returning the same browser instance, thus the scripts step all over one-another.
Are either of these scenarios possible? I've seen some posts from 2008/2009 about a multiple browser branch, did this code eventually make it into the general release?
Thanks,
Jeff
I have just tried it with watir-webdriver gem (installation instructions), and it works:
$ irb
>> require "watir-webdriver"
=> true
>> b1 = Watir::Browser.new :ff
=> #<Watir::Browser:0x101574930 url="about:blank" title="">
>> b1.goto "google.com"
=> "http://www.google.hr/"
>> b2 = Watir::Browser.new :ff
=> #<Watir::Browser:0x1023658f0 url="about:blank" title="">
>> b2.goto "yahoo.com"
=> "http://www.yahoo.com/"
Vapir-firefox is a much-improved fork of Firewatir that resolves its issues with handling multiple windows (among many other improvements).
http://vapir.org/