After adding selenium-webdriver gem, when started capybara test, browser started to show home page and after it, refreshed with the blank page.
It cause to fail my tests that previously passed. Showing Capybara::ElementNotFound error.
I use capybara 2.2.1; selenium 2.42.0; ruby 2.1.0; rails 4.1.0; rspec 3.0
Here is my test:
require 'spec_helper'
describe "Navigation" do
it "changing active menu element depending on route", js: true do
visit '/'
first(:link, 'WHAT IS DREAMDO?').click
expect(find('.navigation').find('.active').find('a').text).to eq('WHAT IS DREAMDO?')
first(:link, 'DISCOVER DREAMS').click
expect(find('.navigation').find('.active').find('a').text).to eq('DISCOVER DREAMS')
first(:link, 'DREAMDO WEEKLY').click
expect(find('.dreamdo-menu-items').find('.active').find('a').text).to eq('Dreamdo Weekly')
end
end
describe "Search", js: true do
it "checks for the availability and search results" do
search_text = find(:xpath, '//input[#id="search_text"]').set("chocolate")
search_text.native.send_keys :return
page.should have_content "chocolate"
end
end
Could you, please, recommend me what to do?
Actually, it is not good to use selenium, because it can't run multiple instances:
http://robots.thoughtbot.com/capybara-webkit
Try to use capybara-webkit, hope it will solve your problem.
Related
I have below spec code for testing user login feature.
feature "User login" do
context "using browser", :js => true do
before(:each) do
visit "/"
first(:link, "Login", visible: :any).click
end
scenario "with valid details" do
...
# rest of code.
end
end
end
It is working fine in my local machine with headless chrome. Here is my Capybara javascript_driver config in spec_helper.rb.
Capybara.register_driver :headless_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new(
args: %w[headless disable-gpu no-sandbox]
)
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
Capybara.javascript_driver = :headless_chrome
But not working with gitlab-ci, below is error i am getting.
Failure/Error: first(:link, "Login", visible: :any).click
NoMethodError: undefined method 'click' for nil:NilClass
./spec/features/user_login_spec.rb:6:in 'block (3 levels) in '
/usr/local/bundle/gems/rspec-retry-0.5.6/lib/rspec/retry.rb:115:in
'block in run'
/usr/local/bundle/gems/rspec-retry-0.5.6/lib/rspec/retry.rb:104:in
'loop'
/usr/local/bundle/gems/rspec-retry-0.5.6/lib/rspec/retry.rb:104:in
'run'
/usr/local/bundle/gems/rspec-retry-0.5.6/lib/rspec_ext/rspec_ext.rb:12:in
'run_with_retry'
I found this blog to use headless chrome but nothing helped.
Here are the versions of dependencies i am using.
google-chrome-stable (63.0.3239.108-1)
chromedriver (2.34)
By default first doesn't have waiting/retrying behavior, which means if a matching link doesn't exist when it runs it won't wait for one to appear. Additionally passing visible: :any to find an element that you're then going to call click on doesn't make any sense since you can't click on non-visible elements so that would cause an error too. If you do actually need/want to use first (multiple matching links that you can't scope down to one) then you should be using
before(:each) do
visit "/"
first(:link, "Login", minimum: 1).click
end
The minimum: 1 option will trigger first to wait/retry up to Capybara.default_max_wait_time seconds for a matching link to appear on the page. This is one of the reasons using first and all are generally
bad choices when looking for elements to actually interact with (unless you've done a previous find for something that guarantees the page is in a stable state, or use any of the count options to trigger waiting/retrying behavior). If there aren't actually more than one matching link on the page then you should just be using
before(:each) do
visit "/"
click_link('Login') # same as find(:link, 'Login').click
end
I have this integration test for my Rails App:
require 'test_helper'
class StudyCapybaraTest < ActionDispatch::IntegrationTest
def setup
#user = users(:archer)
#vocabs = #user.vocabs
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.current_driver = :selenium_chrome
#Capybara.default_wait_time = 5
visit login_path
fill_in "session_email", with: #user.email
fill_in "session_password", with: 'password'
click_button "session_commit"
end
test "full study process" do
assert_title "Home | Word Up"
visit study_user_path(#user)
....
end
end
Weirdly, when I remove the first line of the first test "full study process"
assert_title "Home | Word Up"
the test fails because the test user doesn't seem to be logged in. The same problem occurs when I move
visit study_user_path(#user)
into the setup function (as it was before).
But that doesn't change anything about the sequence and logic, right?
The only thing I can think of, is that the assertion comes to early, and the
app doesn't have time to execute the instructions needed to meet the assertions.
Is this a timing issue, and if so, how can I prevent them from happening in the future? Thx!
First, your intuition on it being a timing issue is correct. click_button does just that - it clicks the button. It doesn't wait for a form to post, it doesn't wait for any ajax to occur, etc. So without the assert_title your test is clicking the button, and immediately changing the url in the browser. The changing the url in the browser would have the effect of canceling any form submission or behavior that was triggered by the click_button call. You need to wait after the click_button for something that changes on the page as a result of clicking the button, along the lines of
assert_text('You are now logged in')
Secondly, the setup method is run before each test so you really don't want to be registering the driver in there, since it only needs to be done once.
I have the following Cucumber feature testing an input form using typeahead.js:
#javascript
Scenario: Creating a battery using typeahead
When I create a new battery using typeahead
Then I should be on the show battery page
And I should see the battery created message
The test fails on the second step with the following error message:
ActiveRecord::RecordNotFound (ActiveRecord::RecordNotFound)
./features/step_definitions/admin/car_part_steps/battery_steps.rb:37:in `/^I should be on the show battery page$/'
features/admin/creating_car_parts/creating_batteries.feature:20:in `Then I should be on the show battery page'
The relevant step definitions are as follows:
When /^I create a new battery using typeahead$/ do
select_from_typeahead :field => 'battery_manufacturer_typeahead',
:select => #manufacturer.name
fill_in 'Type', :with => '700W'
click_button 'Create Battery'
end
Then /^I should be on the show battery page$/ do
battery = Battery.find_by_type_and_manufacturer_id!('700W', #manufacturer.id)
current_path.should == admin_battery_path(battery)
page.should have_content(battery.type)
end
The select_from_typeahead function is as follows:
def select_from_typeahead(params)
params[:js_field] ||= params[:field]
params[:select_typeahead] ||= params[:select]
fill_in params[:field], :with => params[:select][0, 2]
page.execute_script "$('##{params[:js_field]}').trigger('focus')"
page.execute_script "$('##{params[:js_field]}').trigger('keydown')"
sleep 0.5
page.execute_script "$('.tt-suggestion:contains(\"#{params[:select_typeahead]}\")').trigger('mouseenter').trigger('click')"
end
The problem appears not to have anything to do with the typeahead itself however, as the code works in the browser, and if I add some debug output, I notice that the battery gets saved to the database in the first step when running the test as well, it just mysteriously disappears before the second step runs.
I think it's an issue with database_cleaner, as I know that doesn't play nice with Javascript when set to use transactions, but I've already tried setting it to use truncation instead and disabled transactional fixtures and it still doesn't work.
My features/support/env.rb currently looks like this:
require 'simplecov'
SimpleCov.start 'rails'
require 'cucumber/rails'
Capybara.default_selector = :css
Capybara.javascript_driver = :webkit
ActionController::Base.allow_rescue = false
Cucumber::Rails::World.use_transactional_fixtures = false
DatabaseCleaner.strategy = :truncation
Cucumber::Rails::Database.javascript_strategy = :truncation
My environment is as follows:
rails 4.0.2
cucumber 1.3.10
cucumber-rails 1.4.0
capybara 2.2.0
capybara-webkit 1.1.0
database_cleaner 1.2.0
Am I missing something, is there some other way database_cleaner might still interfere with my test, or is it something else entirely that I haven't thought of?
Any ideas would be very welcome!
I don't think it has to do with Database Cleaner. That wouldn't do cleanup until the end of your scenario. To debug, I highly recommend installing Capybara Screenshot so that you can see exactly what is going on in your page. It provides you the method screenshot_and_open_image, which you can use to pop open an image of what the browser looks like at that exact moment. My guesses are that:
Your jQuery isn't doing what you expect because of timing issues - have you tried longer pauses?
Your transaction isn't committed. Have you looked in test.log to see if the transaction was committed?
Is your form failing validation? Try putting a screenshot_and_open_image at the beginning of your I should be on the show battery page step to see. Another thing I use is a shared step like this, so that I can add screenshots in my scenarios for debugging:
And /^I take a screenshot$/ do
Capybara::Screenshot.screenshot_and_open_image
end
Solution
This worked. The main essence is that I have to set the Capybara.server_port and Capybara.app_host and sign in manually in the sign in form. Capybara.app_host cannot be set with a dynamic subdomain unless its declared in a variable. All urls has to be hard coded.
require 'spec_helper'
feature 'customer' do
let(:user) {FactoryGirl.create(:user)}
let(:firm) {user.firm}
let(:customers) {"http://#{firm.subdomain}.lvh.me:31234/customers"}
let(:root_url) {"http://#{firm.subdomain}.lvh.me:31234/"}
before(:all) do
Capybara.server_port = 31234
sub = firm.subdomain
Capybara.app_host = root_url
end
def sign_in_on_js
visit root_url
fill_in "Email", :with => user.email
fill_in "Password", :with => "password"
click_button "Sign in"
page.should have_content("Signed in successfully.")
end
scenario "make new", js: true do
sign_in_on_js
visit customers
page.should have_content("Add new customer")
find("#dialog_customer").click
page.should have_content("Create new customer")
end
end
Original question
I am making a multitenant app in rails. There is going to be a lot of javascript. But, I cant get the testing to work.
When not running :js = true every thing works. The problem arises in specs like this one
let(:customers) {"http://#{firm.subdomain}.lvh.me:3003/customers"}
scenario "Statistics select", :js => true do
visit customers
page.should have_content("Add new customer")
end
The poltergeist web driver for capybara cannot find the url and returns a blank page
Failure/Error: page.should have_content("Add new customer")
expected there to be text "Add new customer" in ""
I have this in my spec_helper.rb
require 'capybara/rspec'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :debug => true)
end
Poltergeist and phantomjs try to deliver. I get this output
{"name"=>"set_debug", "args"=>[true]}
{"response"=>true}
{"name"=>"visit", "args"=>["http://subdomain2.lvh.me:3003/statistics"]}
poltergeist [1362522132943] state default -> loading
{"response"=>{"status"=>"fail"}}
Do I need to have a server running during testing to make this work?
I've tried selenium and capybara-webkit, but phantomjs has gotten closest to success.
I have also tried to change the hosts file in different ways( maybe not correct )
Any tips on setup are welcome!
Update
Starting to get desperate. I now start the rails server
rails s -e test -p 3001
and then run my tests.
Now I get redirected to the sign in page. I have this in the specs
before(:each) do
login_as(user, :scope => :user)
end
How can I sign in the test user on the rails test server without going trough the sign in process manually for every spec
Capybara already starts a server for you, to quote the docs:
Some Capybara drivers need to run against an actual HTTP server. Capybara takes care of this and starts one for you in the same process as your test, but on another thread. Selenium is one of those drivers, whereas RackTest is not.
Within your test you can use the visit method with a relative url, for example:
visit("/statistics")
Capybara will direct this request to the server it just started for this test.
When your want to use an absolute url within your test, you can, but you should also specify the port the server is running on. This port is being randomly chosen during the test. Some drivers have a method available to retrieve the port number.
For example when you use the Capybara-Webkit driver:
Capybara.current_session.driver.server_port
To visit an absolute url you can then use:
port_number = Capybara.current_session.driver.server_port
visit("http://127.0.0.1:#{port_number}/statistics")
Within the test specs probably a method login_as won't work. You have to log in with a few simple steps. For example:
before(:each) do
visit "/login"
fill_in "Email", :with => "my#email.com"
fill_in "Password", :with => "secret"
click_button "Login"
end
To test multiple subdomains you can set the Capybara.app_host. Take a look at this question for a detailed explanation.
UPDATE
Capybara 2 includes a nice feature called always_include_port which will automatically add the port number the server is running on.
Capybara.always_include_port = true
So instead of
visit("http://127.0.0.1:#{port_number}/statistics")
you can now use
visit("/statistics")
and it will automatically connect to http://127.0.0.1:#{port_number}/statistics.
If you want to test multiple subdomains with Capybara.app_host, you could use a domain name which always resolves to 127.0.0.1 for example lvh.me.
For example, if you specify Capybara.app_host = "http://example.lvh.me" it will run the tests using the example subdomain.
Is there any way within an RSpec tests, by convention or code, to have rails start before tests run? I'm trying to setup a testing framework for selenium tests that use chrome, and now I'm only hindered by my lack of a running server.
require 'spec_helper'
describe 'The first tab' do
before(:each) do
#driver = Selenium::WebDriver.for :chrome
end
it 'Shows the list' do
#driver.navigate.to 'index.html'
end
end
I'm new to RSpec, so I'm not sure how I would create a suite of tests that all ran while a rails server was running.
You should be using Capybara to test this stuff instead. It uses selenium-webdriver internally to provide JavaScript testing support.
with Capybara, you put this test in either the spec/integration or spec/requests folder and write it like this:
require 'spec_helper'
describe 'The first tab' do
it "shows the list", :js => true do
visit list_path
end
end
By putting :js => true after the example's name Capybara will know to run this as a JavaScript test.
Just run rails server and kill the process went tests complete.