I'm trying to test my cucumber scenarios with capybara and selenium but I get blank pages all the time.
I read this: Capybara + RSpec only sees blank pages in controller specs. Why?
But It's not exactly the same because that is with rspec.
My env.rb has:
Capybara.default_driver = :webkit
I have try to change it to :selenium but it's the same story.
Any help?
Why not use these drivers only for javascript, do you really need them as default driver?
Do you want to always use them?
It could just be a timeout issue..
If you want to set them for JavaScript only do this instead (env.rb):
Capybara.javascript_driver = :webkit
And decorate your scenarios with #javascript as such:
#javascript
Scenario: Customers List
Related
I'm in the process of migrating from Poltergeist to headless Chrome.
Gemfile:
group :test do
# Capybara - Headless, JavaScript-executing browser for Selenium
gem 'selenium-webdriver' # Selenium webdriver (needed to use Chrome driver)
gem 'webdrivers', '~> 4.0', require: false # Run Selenium tests more easily with automatic installation and updates for all supported webdrivers.
gem 'capybara-screenshot' # Automatically save screen shots when a scenario fails
...
end
spec/support/capybara.rb:
Capybara.javascript_driver = :selenium_chrome_headless
I have spec which tests whether focusing an element applies a CSS class to an element.
it 'shows the fullscreen toggler on focus', js: true do
visit new_user_path
page.execute_script("$('#user_about').focus()")
expect(page).to have_css '.textarea-fullscreenizer-toggler'
end
With Poltergeist it passed. With :selenium_chrome_headless it does not:
expected to find visible css ".textarea-fullscreenizer-toggler" within #<Capybara::Node::Element tag="div" path="/HTML/BODY[1]/MAIN[1]/DIV[1]/DIV[1]/FORM[1]/FIELDSET[1]/DIV[1]/DIV[1]/DIV[5]"> but there were no matches. Also found "", which matched the selector but not all filters.
With :selenium_chrome though, it passes! So it seems that the headless and non-headless driver do different things! This is pretty uncomfortable.
Interestingly, when putting a save_screenshot after focusing the element, the spec passes with headless chrome, too!
What can I do here? I'm on the right track? Should I try https://github.com/twalpole/apparition driver instead?
You can also try something like this for headless chrome in the helper capybara.rb file.
require "selenium/webdriver"
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) }
)
Capybara::Selenium::Driver.new app,
browser: :chrome,
desired_capabilities: capabilities
end
Capybara.javascript_driver = :headless_chrome
This worked for me. Might work for you as well.
Seems like a timing issue to me. My guess would be that the jQuery call you use to trigger focus takes some time while the matcher is already executed. However, since it finds an element, which is not yet visible though, it raises the error. Inserting the screenshot may consume just enough time to have JavaScript evaluated your command.
Have you tried to explicitly match for a visible element like expect(page).to have_selector('.textarea-fullscreenizer-toggler', visible: true)?
Also, the focus trigger could also be done like that: find('#user_about').trigger('focus'). This may also resolve the issue since it returns after it triggered the event.
The error you provided is obviously not being returned for the code as shown, since the code you've provided isn't scoping anything or checking for text. In the future it would be much better if the error matched the code. That being said the answer below is a guess based on the info available.
The issue is most likely that your JS execution is happening before the page has fully loaded and therefore the page is resetting focus. This can happen because visit does not guarantee the page is fully loaded/stable when it returns. To synchronize that you need an expectation before the execute_script call that checks for something on the page that would indicate the page is loaded/stable.
visit new_user_path
expect(page).to have_css('input#first_input:focus') # wait until the initially focused element is loaded/displayed/focused
page.execute_script("$('#user_about').focus()")
Note that using execute_script is generally a bad idea in tests though since it's not doing what a user would - you'd be much better off having Capybara do whatever actions a user would perform to make the element you care about focused.
I'm starting in the automated testing area and am having the error below when I am running one of my tests. The test would be to fill in a datetime field, of type input, with the start time that the machine stopped. I'm running Cucumber with Capybara on a system written in Ruby on Rails and Ext Js.
Error: wrong number of arguments (given 1, expected 0) (ArgumentError)
Bellow is my env.rb for the project:
require 'capybara'
require 'capybara/cucumber'
require 'report_builder'
require 'selenium-webdriver'
require 'webdrivers/chromedriver'
Capybara.javascript_driver = :webkit
Capybara.configure do |config|
config.default_driver = :selenium_chrome
config.default_max_wait_time=10
config.app_host='http://localhost:3000/'
end
My exemple.feature is like:
Scenario: start of the machine stop
Given that I accessed the system
And marked 'Yes' in 'Did the machine stop?'
And I fill the start of the machine stop with '2020-05-12 16:00:00' #UTC
When saving the form
Then the success message should appear
My steps.rb is something like below:
And("I fill the start of the machine stop with {string}") do
#machine_stop = machine_stop
#MD.machine_stop_start(#machine_stop)
end
My page.rb:
class Machine_downtime
include Capybara::DSL
def machine_stop_start
find('input[id="datetimefield-1312-inputEl"]').click
end
end
I've done a Google search to find possible solutions but I haven't found any similar cases. I tried to look at the Cucumber documentation but I didn't find anything specific to my problem or Rails.
I can stop using a strings in the step and use a table, but I have more scenarios in this case and I would like to continue using strings, for easier maintenance and to avoid having to change more than 100 test scenarios.
I appreciate anyone who can help me with the problem.
P.s. Ruby on Rails runs on a different project.
Update:
I insert in the machine_stop_start method the variable I created in the step and the error no longer occurs.
class Machine_downtime
include Capybara::DSL
def machine_stop_start (machine_stop)
find('input[id="datetimefield-1312-inputEl"]').click
end
end
Now I am able to click on the desired field but it is not being filled with the desired information.
I will try to find what I may be doing wrong.
So im running SQLite and attempting to use fixtures to load in the proper data to display and test through the browser with capybara.
My test suite uses a Minitest w/Capybara and Poltergeist for the driver. the relevant portion of my test_helper.rb file looks like so:
require "minitest/reporters"
reporters = []
reporters << Minitest::Reporters::SpecReporter.new
Minitest::Reporters.use! reporters, ENV, Minitest.backtrace_filter
require "minitest/rails/capybara"
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :js_errors => false)
end
Capybara.default_driver = :poltergeist
Capybara.current_driver = :poltergeist
Capybara.javascript_driver = :poltergeist
However I have a simple test that stubs a User access level login for the web application this is running on, and then simply visits the route.
However it's failing at what seems to be the "User Access Stubbing" method that im using. Which looks like Core::User.any_instance.stubs(etc...) which is just returning a user model.
Anyways the exact error I get is:
ActiveRecord::StatementInvalid: ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
Since im using fixtures would this maybe be a DB cleaner issue(Im not using it right now as im only using pre-created fixtures currently) I've never used DB cleaner with minitest as im only familiar with using it with rspec and factory girl.
The error is telling you that another DB connection already has sqlite open for writing (it can handle multiple readers but only one writer at a time). You don't show your actual test or your stub so it's impossible to say specifically where your issue is, but odds are you've made a request and then are running some other database access while it's occurring (for instance have you preloaded the object the stub returns, or does it get loaded when the stub is executed?).
If your app doesn't use sqlite as it's database then swap over to testing on the DB the app will use in production. Additionally, stubbing is an anti-pattern in feature tests, you should just be creating proper records, and dealing with them.
Assuming I have PhantomJS installed on Mac OS X, can I write a plain old Ruby script (no Cucumber, no RSpec) to drive Poltergeist? In other words, I want to require some gems, set the Capybara driver to Poltergeist and then start calling page.fn() to pull down pages, analyze contents, etc?
UPDATE: Here is what I have created. It seems to work.
require 'awesome_print'
require 'capybara'
require 'capybara/dsl'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.run_server = false
Capybara.app_host = 'http://www.google.com'
Capybara.current_driver = :poltergeist
include Capybara::DSL
visit '/'
page.driver.network_traffic.each do |request|
ap request.response_parts
end
I know the naked include is bad, but I am just hacking at the moment before I encapsulate this in a class.
Feedback?
Yep, you can definitely use capybara & poltergeist without cucumber or rspec. What you have looks like a pretty good start.
However, you will probably want to use some standardized testing library to provide you with assertion methods & a test runner so you don't have to recreate all that stuff yourself. Your primary options are:
test/unit (now minitest under the hood)
minitest/spec (a spec-like wrapper for minitest)
rspec
Here are the capybara integration instructions for each:
test/unit
minitest/spec
rspec
Ive setup capybara-webkit for my integration tests and Im running into a very simple problem. My session is not being stored. The use case is pretty simple
1. Login
2. Go to a specific page
3. Check if it has the approp content
Now at step 2 my app is returning the test case to the login page - which means the session is not being set properly.
any help is much appreciated
If I use #culerity instead of #javascript then this test case passes so the problem seems to be the capybara-webkit setup
My env.rb for capybara-webkit support is as follows
Spork.prefork do
require 'cucumber/rails'
require 'capybara'
require 'capybara/dsl'
require 'capybara/cucumber'
require 'capybara-webkit'
Capybara.run_server = false
Capybara.javascript_driver = :webkit
Capybara.default_selector = :css
# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
# order to ease the transition to Capybara we set the default here. If you'd
# prefer to use XPath just remove this line and adjust any selectors in your
# steps to use the XPath syntax.
# Capybara.default_host = "127.0.0.1:3000"
Capybara.app_host = "http://localhost:3000"
end
Update 1:
Looks like the sessions is being set. I used the following code to dump the session in my steps
puts(Capybara.current_session.driver.browser.get_cookies)
and I got the follwoing - so looks like cookie is being set but not being sent back
["_jqt_session=BAh7CEkiD3Nlc3Npb25faWQGOgZFRiIlYmMwYzNjYjY0MGU3NTg0OWFlNTcwODhmM2I2MzE1YmRJIhBfY3NyZl90b2tlbgY7AEZJIjEwRzN6NG1NTzZqamNCNC9FdWZWeXBCMHdoeThueXBnaTJDcTVzbmJqQlBZPQY7AEZJIgpmbGFzaAY7AEZJQzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2h7BjoKYWxlcnRJIh9JbnZhbGlkIGVtYWlsIG9yIHBhc3N3b3JkLgY7AFQGOgpAdXNlZG86CFNldAY6CkBoYXNoewY7B1Q%3D--3fbe1c2a77a433228e7b7f2d8c8f0aec3ad5fb5f; HttpOnly; domain=localhost; path=/"]
Update 2:
was barking up the wrong tree. Seems that the user I was creating in my test case was not being seen by the rails app as my database cleaner strategy was set to transactional. see more info at
https://groups.google.com/forum/#!msg/ruby-capybara/JI6JrirL9gM/R6YiXj4gi_UJ
To add more clarity,
Capybara webkit or selenium driver is running in a different thread then app, so if you are using transactional fixtures or database_cleaner with strategy :transaction and your data isn't commited to db and another thread won't see it.
Possible solutions are:
Use database_cleaner with strategy :truncation. (solid, but a slow)
Add code to force active record using single transaction for all threads. (faster, but may have some issues, ex.: after_commit hooks aren't called, as there's no commit)
#Capybara use the same connection
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
I'm using 2-nd option, but it's arguable.