How should I test a selenium application with capybara? - selenium

Here is my problem:
I am writing an application that uses selenium-webdriver to connect to a site a click/fill a bunch of things.
Obviously, I want to test my code... And this is where it gets difficult! How do I do this?
Here is my test:
require 'spec_helper'
require 'capybara/rspec'
module MyModule
Capybara.run_server = false
describe "the method", :type => :request do
it "should open a browser and go to the site" do
MyClass.open_site("http://google.com")
page.has_content? "Google"
end
end
end
Here is the code:
require 'selenium-webdriver'
module MyModule
class MyClass
def self.open_site(url)
#driver = Selenium::WebDriver.for :firefox
#driver.navigate.to url
end
end
end
Here is the error I am getting:
Failures:
1) the method should open a browser and go to the site
Failure/Error: page.has_content? "Google"
ArgumentError:
rack-test requires a rack application, but none was given
# (eval):2:in `has_content?'
# ./spec/integration/myclass_spec.rb:10
I can understand the test is confused because usually Capybara runs Selenium to vist a site and check that everything looks good. But here Selenium is running on its own as part of the code...
How could I tell rack-test to use the running Selenium as its application?
Is Capybara even the right solution to test this code?
Thanks for your help!

One of the functions that you are using must be using a rack application.
The problem should not be with the line:
page.has_content? "google"
because that works fine for me with selenium driver. I suspect it is the way you have set up the driver.
I had a similar problem with running my capybara tests until I discovered these posts:google groups
They gave me a few pointers to get my test running.
In the end I ended up having these lines to configure my tests.
I am using chrome but Internet explorer and firefox would work this way too.
require 'selenium-webdriver'
Capybara.register_driver :selenium_ie do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.default_driver = :selenium_chrome
Capybara.app_host = 'http://www.google.com'

Here's what I did with my Sinatra application running MongoDB. Comment out the selenium code to try pure selenium without capybara. Install the test-unit, capybara, capybara-webkit, selenium-webdriver gems. For capybara-webkit do brew install qt4 (mac) or install qt4 another way.
require './app'
require 'test-unit'
require 'capybara'
require 'capybara-webkit'
require 'selenium-webdriver'
class IntegrationTest < Test::Unit::TestCase
include Capybara::DSL
def setup
# Clear database first
MongoMapper.database.collections.select { |c| c.name != 'system.indexes' }.each(&:drop)
# For pure selenium: #b = Selenium::WebDriver.for :firefox
# For pure selenium: #w = Selenium::WebDriver::Wait.new(:timeout => 15)
Capybara.run_server = false
Capybara.default_selector = :css
Capybara.default_wait_time = 5
Capybara.ignore_hidden_elements = false
Capybara.javascript_driver = :webkit # Comment out to use :selenium
Capybara.default_driver = Capybara.javascript_driver
Capybara.app = Sinatra::Application.new
Capybara.app_host = "http://crowdfundhq.dev:3001"
Capybara.server_port = 3001
end
def teardown
# For pure selenium: #b.quit
Capybara.reset_sessions!
Capybara.use_default_driver
end
def test_root
# For pure selenium: #b.get "http://crowdfundhq.dev:3001"
# For pure selenium: assert #b.page_source =~ /#pricing/
# Change driver during test: Capybara.current_driver = Capybara.javascript_driver
visit("/")
assert(page.body =~ /highlight/)
end
end

Related

How do I correct this Selenium initialisation command deprecation warning?

Using Rails 6 I'm trying to set up selenium in headless mode for system tests, I'm using this statement in application_system_test_case.db:
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
(according to Agile Web Dev Rails 6 tutorial)
but it gives me this deprecation warning:
Selenium [DEPRECATION] [:browser_options] :options as a parameter for driver initialization is deprecated. Use :capabilities with an Array of value capabilities/options if necessary instead.
I've done some searching in Selenium docs but I my basic code skills still leave me unclear as to how I should correct this. Can anyone advise how I can correct this?
(My amateur guesswork trials of things like:
driven_by :selenium, :capabilities['headless_chrome', 'screen_size: 1400, 1400']
all result in errors)
Updated version for the new warning with options instead of capabilities
Capybara.register_driver :headless_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
options: options
)
end
Capybara.register_driver :chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
options: options
)
end
Capybara.default_driver = :chrome
In Selenium 4, the options must be passed in array capabilities:
def selenium_options
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options
end
# optional
def selenium_capabilities_chrome
Selenium::WebDriver::Remote::Capabilities.chrome
end
def driver_init
caps = [
selenium_options,
selenium_capabilities_chrome,
]
Selenium::WebDriver.for(:chrome, capabilities: caps)
end
driver = driver_init
I stumbled upon this thread a couple of times already. What was bothering to me were not only the deprecated messages, but also the puma server logs while launching the test suite. I've ended up fixing the deprecation warning and shutting the puma logs. Here's my current setup:
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
# provides devise methods such as login_session
include Devise::Test::IntegrationHelpers
# removes noisy logs when launching tests
Capybara.server = :puma, { Silent: true }
Capybara.register_driver :headless_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new(args: %w[headless window-size=1400,1000])
Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: options)
end
Capybara.register_driver(:chrome) do |app|
options = Selenium::WebDriver::Chrome::Options.new(args: %w[window-size=1400,1000])
Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: options)
end
ENV['HEADLESS'] ? driven_by(:headless_chrome) : driven_by(:chrome)
end
So you can launch tests, for instance, with:
HEADLESS=1 rails test:all
Suppress the warning
One line fix:
# rails_helper.rb
Selenium::WebDriver.logger.ignore(:browser_options)
Suggested here
OR
(probably) Any version of Capybara > 3.36.0
Edit: #silvia96 has 3.38.0 and still getting warning
It's quite a confusing bug because if you look at the Capybara driver registration you can see it already knows about using capabilities. The actual bug is because the Gem version test is set as ~ instead of >=. The fix is in main and any version of Capybara after 3.36.0 will, likely, fix it.
Combining the useful solutions from others, here's what mine looks like.
Remove puma logs, make headless chrome, ignore browser options error:
require "test_helper"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome
Capybara.server = :puma, { Silent: true }
Selenium::WebDriver.logger.ignore(:browser_options)
end

:driver_opts is deprecated. Use :service with an instance of Selenium::WebDriver::Service instead

2019-06-19 15:44:43 WARN Selenium [DEPRECATION] :driver_opts is deprecated. Use :service with an instance of Selenium::WebDriver::Service instead.
Screenshot error, but continue to execute.
wrong number of arguments (given 0, expected 1)
2019-06-19 15:44:43 WARN Selenium [DEPRECATION] :driver_opts is deprecated. Use :service with an instance of Selenium::WebDriver::Service instead.
2019-06-19 15:44:43 WARN Selenium [DEPRECATION] :driver_opts is deprecated. Use :service with an instance of Selenium::WebDriver::Service instead.
visit in hook, after scenario +1s, #1s
2019-06-19 15:44:43 WARN Selenium [DEPRECATION] :driver_opts is deprecated. Use :service with an instance of Selenium::WebDriver::Service instead.
I've been using the below code snippet to init a session with old 'selenium-webdriver' v3.6.0 and got the above error:
Updated on June 23rd.
if Capybara.default_driver == :selenium
Capybara.register_driver :selenium do |app|
# In the block, we build up an `options` hash to pass to
# Capybara::Selenium::Driver.new(app, options)
# which in turn calls
# Selenium::WebDriver.for(options[:browser], options)
browser = Configuration.fetch('browser.type', :firefox)
options = {
browser: browser, # chrome
}
if Configuration.fetch('options.webdriver.use_hub', false)
{...}
elsif browser == :firefox
{...}
elsif browser == :chrome
chrome_logpath = "../chromedriver.log"
options[:service] = ::Selenium::WebDriver::Service.chrome(
args: {
verbose: true,
log_path: chrome_logpath,
}
)
chrome_options = Selenium::WebDriver::Chrome::Options.new
chrome_options.add_argument("user-agent='QA Test'")
chrome_options.add_option('w3c',false)
options[:options] = chrome_options
end
Capybara::Selenium::Driver.new(app, options)
end
end
After bumped that gem to v3.142.0 then I got that error. Tracing back to the Selenium Webdriver Changelog in https://github.com/SeleniumHQ/selenium/blob/master/rb/CHANGES then i found the following description, which might break the current code
3.141.592 (2019-04-18)
Chrome:
Added support for instantiating service class directly and moved all driver executable configuration there (command-line arguments, port, etc.)
Passing driver_opts, driver_path and port to driver initializer is now deprecated
so use Selenium::WebDriver::Service.chrome instead,
which allows to customize executable behavior in similar way.
Once initialized, this object can be passed as :service keyword
during driver initialization.
* Deprecated Chrome.driver_path= in favor of Service::Chrome.driver_path=
Googling for a while i found some results and workaround like using 'webdriver' gem but i don't like it that much.
So wonder if something that i can change my snippet above to adapt with that selenium-webdriver ver 3.142.0 and onwards? I'm using Capybara v3.18.0 at the moment.
Thanks everyone,
That's not an error, it's a deprecation warning. It's telling you that you will need to change your code before selenium-webdriver v4.0 is released. If you feel you must update your code today it would be something like
elsif browser == :chrome
options[:service] = ::Selenium::WebDriver::Service.chrome(
args: {
verbose: true,
log_path: "../chromedriver.log",
}
)
chrome_options = Selenium::WebDriver::Chrome::Options.new
# add user agent to that class options
chrome_options.add_argument("user-agent='QA Test'")
options[:options] = chrome_options
end
The other stuff you show
Screenshot error, but continue to execute.
wrong number of arguments (given 0, expected 1)
is something different and isn't coming from any of the code you're showing.

How to stop capybara/selenium chrome window from coming to front/focus?

I run a test suite locally that takes about 15 minutes. During this time it's impossible to get any work done because every feature spec brings the chrome window to the front. Is there a configuration option to avoid this, to NOT bring the capybara/selenium window to the front?
This is my current config:
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app,
browser: :chrome,
desired_capabilities: {
"chromeOptions" => {
"args" => %w{ window-size=1740,768 }
}
}
)
end
Capybara.server_port = 57124
Capybara.app_host = "http://localhost:#{Capybara.server_port}" # S3 accesss control blocks default capybara 127.0.0.1
Capybara.default_max_wait_time = 10 #default is 2
You can't if you want/need to run it in non-headless mode, but if you run in headless mode you won't have that issue.

undefined method `visit' for Selenium::WebDriver::Driver

Trying to write a simple capybara example against google but getting
undefined method `visit' for #<Selenium::WebDriver::Driver:0x000000055f8cc8>
I can use
driver.get("http://www.google.com/")
but I can't use
driver.visit("http://www.google.com/")
I have:
require "rspec"
require 'selenium-webdriver'
require "capybara"
require "capybara/rspec"
require "capybara/dsl"
RSpec.configure do |config|
config.include Capybara::DSL
end
Capybara.configure do |config|
config.run_server = false
config.default_driver = :selenium
config.app_host = 'https://www.google.com'
end
describe "Google Search", type: :feature do
it "Tests Google" do
driver = Selenium::WebDriver.for :chrome
driver.visit "http://www.google.com/" <-- Error
fill_in('input', with: '123')
find_element('input', "Google Search").click
driver.quit
end
end
Note that I have to use chrome as my selenium firefox setup is out of sync (common problem over time - it's unable to start firefox in 60 secs). But chrome works and the browser comes up.
This simple ruby only example does work however so seems like some sort of rspec setup issue
require 'rubygems'
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.get "http://google.com"
element = driver.find_element :name => "q"
element.send_keys "Cheese!"
element.submit
puts "Page title is #{driver.title}"
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.title.downcase.start_with? "cheese!" }
puts "Page title is #{driver.title}"
driver.quit
You should not be using the driver directly - you should be calling visit on the session (if you're managing your own sessions you would call it on whatever variable you used, if you're letting Capybara manage the sessions you should be calling it on page).
The reason Firefox isn't working for you is because Firefox 47 broke something with selenium - https://github.com/SeleniumHQ/selenium/issues/2110 - it will be fixed in a 47.0.1 release soon, or you can revert to 46. If you want to stick with chrome you should register a version of the driver using chrome in your spec/rails_helper and specify that
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.default_driver = :selenium_chrome # for most people this would normally be assigned to javascript_driver, but since you're using selenium for all tests we can just assign to default_driver
Then you would just do
describe "Google Search", type: :feature do
it "Tests Google" do
page.visit "http://www.google.com/" #technically the page may not be required here but it can prevent method name collisions with other libraries
page.fill_in('input', with: '123')
find_element('input', "Google Search").click # I'm guessing this is your own defined method since Capybara doesn't have a find_element method?
end
end

Set up selenium webdriver with ruby(i have ruby mines), cucumber and capybara in windows 7

I want to setup selenium webdriver with ruby cucumber and capybara in window 7 to practice at home. Can some one provide detail steps.
selenium comes by default with capybara, add :js => true to your cucumber steps and you should be good to go. I am using rspec without cucumber but i have something like
describe "Something" do
it "should use selenium", js: true do
page.should have_content "It works!"
end
you should see firefox come up
you may wanna consider a headless driver to cut down on the browser startup cost
Here's a project from Rails 3 in Action that has some features using selenium
https://github.com/rails3book/ticketee
I put an example:
require "selenium-webdriver"
gem "test-unit"
require "test/unit"
class Papidal < Test::Unit::TestCase
def setup
#driver = Selenium::WebDriver.for :firefox
##base_url = "http://localhost:8090/"
#accept_next_alert = true
#driver.manage.timeouts.implicit_wait = 30
#verification_errors = []
end
def teardown
#driver.quit
assert_equal [], #verification_errors
end
def test_papidal
#driver.get("http://localhost:8090/myproject/")
#driver.find_element(:xpath, "//a[#wicketpath='showModalLink']").click
end
def element_present?(how, what)
#driver.find_element(how, what)
true
rescue Selenium::WebDriver::Error::NoSuchElementError
false
end
def verify(&blk)
yield
rescue Test::Unit::AssertionFailedError => ex
#verification_errors << ex
end
def close_alert_and_get_its_text(how, what)
alert = #driver.switch_to().alert()
if (#accept_next_alert) then
alert.accept()
else
alert.dismiss()
end
alert.text
ensure
#accept_next_alert = true
end
end
If you want use this with Internet Explorer:
Change #driver = Selenium::WebDriver.for :firefox by this #driver = Selenium::WebDriver.for :ie
Put in your PATH (environment variables): IEDriverServer.exe (you can download this from: http://code.google.com/p/selenium/downloads/detail?name=IEDriverServer_x64_2.30.2.zip) and execute this before execute the script