Rails: Capybara doesn't find a div element - ruby-on-rails

I'm using Capybara with RSpec to check my Rails project.
I'm testing errors when form fields are not correctly filled. Here is the form (using haml):
= form_tag '/objects', :class => 'objects-form' do
%ul
%li= select_tag 'object', options_for_select([['Select an object', ''], ['Car', 'CAR'], ['Keys', 'KEYS'], ['Ambrella', 'AMBRELLA']]), :id => 'select-object'
%li= text_field_tag :quantity, nil
%li= submit_tag 'Buy', :id => 'object-submit'
When an error occurs (in this case, not choosing an object but only a quantity), a flash message is displayed (with a .flash-error class name):
- flash.each do |type, msg|
= content_tag :div, msg, :class => "flash-#{type}", :id => 'flash-msg'
So, here is my Capybara test:
it 'Should return error when no object selected' do
within 'form.objects-form' do
fill_in 'quantity', :with => '1'
click_button 'object-submit'
current_path.should == objects_path
save_and_open_page
page.should have_css 'div.flash-error'
end
end
But I get the following Capybara error:
Failure/Error: page.should have_css 'div.flash-error'
expected #has_css?("div.flash-error") to return true, got false
The opened page (using save_and_open_page) shows the error message with the appropriate div:
div#flash-msg.flash-error
I'm using the latest version of Capybara (since many similar problems on Stackoverflow are relative to old versions of Capybara) using gem 'capybara', :git => 'https://github.com/jnicklas/capybara.git'
Any idea? Thank in advance.
EDIT:
Corrected typing mistake on Capybara code, as detected by Alex.

The problem is your selector you are using in capybara is div#flash-error but your div is div#flash-msg.flash-error or more simply div.flash-error.

Related

Rails, Capybara - click_link on remote links doesnt work

I'm using Capybara to test my project. But i have a problem.
I have some remote forms on my project. They add records via ajax. When i'm testing with capybara it works well on development environment. It visits the page, fills in the form and submits. Booom, record has been added and test didnt fail.
But when i run rspec with test environments i'm getting unknown format exception.
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
I've also tried to respond via js from controller like;
def create
request.format = :js
end
Then it returns;
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/javascript"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
And my scenario if u want more info;
scenario 'user adds new address' do
expect(page).to have_content 'Kayıtlı Adreslerim'
find("a[title='Adres Ekle']").click
expect(page).to have_content 'Yeni Adres Ekle'
expect(page).to have_content 'Adres Başlığı'
fill_in 'address[name]', with:'Izmir Ofisi'
select('Izmir', :from => 'address[city_id]')
fill_in 'address[address]', with: 'Lorem ipsum dolor sit amet.'
find("input[value='Adres Ekle']").click # It submits remote: true form.
expect(page).to have_content 'Success!'
end
PS: my create action doesnt render something like that.
its like;
def create
#new_address = Address.new
#address = #current_account.addresses.new(address_params)
if #address.save
#check = true
else
#check = false
end
end
it renders: create.js.erb
<% if #check %>
if($('.addresses').length) {
$('.addresses').append('<%= j(render('account/addresses/address', address: #address)) %>');
}
if($('#did-addresses').length){
$('#did-addresses').append("<%= "<option selected='true' value='#{#address.id}'>#{#address.name}</option>".html_safe %>").selectpicker('refresh');
}
$('#new-address').html('<%= j(render('account/addresses/form', new_address: #new_address)) %>');
swal({
type: 'success',
title: "<%= t('response.success') %>",
text: "<%= t('flash.actions.create.notice', resource_name: Address.model_name.human) %>",
timer: 2000
});
quickview.close('#new-address');
<% else %>
<% #address.errors.each do |error| %>
<% end %>
<% end %>
$('.preloader').fadeOut();
I was facing the same case in rails 6 but I fixed it be adding js: true to the scenario and it automatically worked well.
scenario 'Should delete the feature', js: true do
# Your logic
# Your expectations
end
Since copying your development config over your test config fixed your issue, it sounds like you probably an error in one of your JS files. Normally in the test and production environment all of your JS assets get concatenated into one file which means an error in any one of them can prevent the code in the others from being executed. In the development environment each JS file is loaded separately which means an error in any file can only affect the rest of the code in that file. Check your the console in your browser for any JS errors when going to the page in question and fix them.

How to have capybara see page change after ajax call to rails?

I am writing a feature spec:
the steps are:
List item
I add a new record
I overwrite its verification_date to be nil
This makes it list with a 'verify' link
I click the verify link
If the url is valid the screen should (via ajax) update the 'verify' link to be '2014' text.
This is current working fine in the actual application, the problem is in trying to add some tests that will replicate the behaviour and reflect a working process.
I can't seem to get the test to recognize changed text from the ajax call.
I can do the steps manually but when I use the spec it doesn't see an updated page.
I make sure (in the spec) that I only have (and have added only) 1 record.
Whatever I do I get
1) verification lets me verify a link
Failure/Error: expect(page).to have_content(this_year)
expected to find text "2014" in "Test Linker Links New Link Gr...
The spec is:
...
describe "verification", :type => :feature do
before :all do
User.create(:username => 'x#google.com', :password => 'xyz')
end
before :each do
visit '/ladmin/login'
fill_in 'username', :with => 'x#google.com'
fill_in 'password', :with => 'xyz'
find('input[value="Login"]').click
end
it "lets me verify a link" do
Link.delete_all
expect(Link.count).to eq 0
this_year=Time.now.strftime('%Y') # This is what the screen gets after verification
visit links_path
expect(page).to_not have_content(this_year) # true
l=FactoryGirl.create(:valid_url_link)
l.save
l.update_column(:verified_date, nil) # Force condition that makes 'verify' appear
expect(Link.count).to eq 1
visit links_path
find('a', text: "verify") # This seems to work. The one record has a 'verify' link
click_link("verify", match: :first) # This should change the text to 2014
sleep(7)
expect(page).to have_content(this_year)
end
end
the link factory is:
FactoryGirl.define do
factory :link do
group {FactoryGirl.create(:group)} #:group
url_address {"http://test.com"+SecureRandom.uuid}
alt_text "examples of common situations amnd solutions"
end
factory :valid_url_link, parent: :link do
group {FactoryGirl.create(:group)} #:group
url_address {"http://www.google.com"}
alt_text "valid url"
end
...
end
The js (though probably not where the issue is imho) is:
$ cat app/assets/javascripts/verifying_link.js
$(function(){
$("a[data-verifying-link]='yes'").click(function(event){
event.preventDefault();
a=$(this).parent();
a.html('<img src="assets/ajax-loader.gif">');
var id= $(this).data("id");
var row = $(this).data("tableRow");
$.ajax({
url: "/verify_link/"+id+"&table_row="+row,
type: 'GET',
success: function(r) {
$("span#verify_link_"+row).html('<span class="done">Verified</span>');
},
error: function(r) {
$("span#verify_link_"+row).html('<span class="undone">Unverified</span>');
}
});
});
});
The code for the actual display of the field is a bit messy (but has worked for 378 links so far...) is:
%td.column_align
%span{id: "verify_link_#{index}"}
- if link.verified_date
- link_text = session[:full_details] == 'true' ? long_form(link.verified_date) : short_form(link.verified_date)
= render :partial => 'link_toggle', :locals => { :content => [long_form(link.verified_date), short_form(link.verified_date)], :url => verify_link_path(id: link.id, table_row: index) }
- else
- if session[:user_id]
%a{href: "#", :data => {verifying_link: 'yes', id: link.id, table_row: index}}
verify
- else
No
The partial involved is:
- if session[:full_details] == 'true'
%span{class: "show_hide shown"}
= link_to content[0], url, title: 'Reverify this link', remote: true
%span{class: "show_hide hidden"}
= link_to content[1], url, title: 'Reverify this link', remote: true
- else
%span{class: "show_hide shown"}
= link_to content[1], url, title: 'Reverify this link', remote: true
%span{class: "show_hide hidden"}
= link_to content[0], url, title: 'Reverify this link', remote: true
That needs work but has been working that way for a while in the live app.
Why does the test keeps showing the page with the links added but not verified and showing 2014?
The spec shown does not have the required :js => true
e.g.
describe "verification", :js => true, :type => :feature do
This will then require you (via an error) to add capybara-webkit to your Gemfie, e.g.
gem 'selenium-webdriver'# For rspec capybara javascript tests
and of course
bundle

How can I test a rails 4 confirm dialog with Capybara and Poltergeist?

I'm trying to test that a link to a destroy action throws a native browser confirm box with the correct message.
The link is being generated using rails' link_to:
link_to 'Delete', user_path, method: :delete, data: { confirm: "Are you sure?" }
And generates the following html:
<a data-confirm="Are you sure?" data-method="delete" href="/users/6" rel="nofollow">Delete</a>
The functionality is working correctly in the browser, but I want to test for it in my rspec feature spec.
I'm trying to stub out the browser's confirm function as described here and in this gist, however I can't get it to work.
it 'requests confirmation', js: true do
visit user_path(user)
page.execute_script "
window.confirmMsg = null;
window.confirm = function(msg) { window.confirmMsg = msg; return true; };"
click_link 'Delete'
expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end
Gives the following error from rspec:
Failure/Error: expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
expected: "Are you sure?"
got: nil
(compared using ==)
However, if I call a confirm directly via page.execute_script:
it 'requests confirmation', js: true do
visit user_path(user)
page.execute_script "
window.confirmMsg = null;
window.confirm = function(msg) { window.confirmMsg = msg; return true; };
window.confirm('Are you sure?');"
expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end
Then the test passes.
Also clicking the Delete link will cause the test to fail, even if confirm has been called directly for page.execute_script:
it 'requests confirmation', js: true do
visit user_path(user)
page.execute_script "
window.confirmMsg = null;
window.confirm = function(msg) { window.confirmMsg = msg; return true; };
window.confirm('Are you sure?');"
click_link 'Delete'
expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end
Gives the same error from rspec:
Failure/Error: expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
expected: "Are you sure?"
got: nil
(compared using ==)
Why is the test failing? And, how can I test confirm dialogues correctly?
Context:
I'm running my tests from a Vagrant virtual machine, which is Ubuntu 12.04.4 LTS and running ruby 2.1.2p95.
My Gemfile.lock shows that I have the following versions:
rails (4.1.4)
poltergeist (1.5.1)
capybara (2.4.1)
page.driver.browser.accept_js_confirms is deprecated. Instead use
page.accept_confirm do
click_link 'Delete'
end
Unfortunately, you cannot do this, because Poltergeist does work only in one window.
For that specific test you will need to use Selenium and this API:
page.driver.browser.switch_to.alert.accept
If you are concerned about wanting to run your tests headless, you can use Xvfb (X Virtual Framebuffer) like this:
Xvfb :1 -screen 0 1024x768x24+32
Alternatively you can also use capybara-webkit:
page.driver.browser.accept_js_confirms
page.driver.browser.reject_js_confirms
However, I have made the best experience using a mixture of (mostly) Poltergeist and Selenium where necessary.
To expand on the above, when using Selenium you can test the actual text of the confirm dialog using the following:
click_link 'Delete'
a = page.driver.browser.switch_to.alert
expect(a.text).to eq("Are you sure?")
a.accept
Also, just found a good test for whether the alert is present here: selenium 2.4.0, how to check for presence of an alert I slightly modified it, put in my spec_helper file as:
def alert_present?
begin
page.driver.browser.switch_to.alert
return true
rescue
return false
end
end
And then in your test just do:
click_link 'Delete'
expect(alert_present?).to eq(true)
Given this Javascript:
confirm('You have unsaved changes, do you want to continue?')
For Poltergiest I found the following to work:
expect(page.driver.browser.modal_message).eq 'You have unsaved changes, do you want to contine?'
page.driver.browser.dismiss_confirm
page.driver.browser.accept_confirm
This is how I am doing in Rails 3.2 and capybara (~> 2.18.0)
context 'when `All listing` overlaps with listing 1' do
it 'displays warning' do
set_weekday_times('.show_window','10:00 AM', '02:00 PM', listing1.address)
set_weekday_times('.show_window:last-child', '11:00 AM', '03:00 PM', 'All Listing')
# button click event that triggers the confirm to appear
submit_weekdays_form
# Get the message in the confirm dialog
confirm_text = page.driver.browser.switch_to.alert.text
expect(confirm_text).to include('overlapping show windows on Sunday')
end
end
It's tough to test JavaScript behavior. But if you want to check confirmation message, it might be okay to test link attribute only without Poltergeist:
it 'requests confirmation' do
visit user_path(user)
delete_link = find_link 'Delete', href: user_path(user)
expect(delete_link['data-confirm']).to eq 'Are you sure?'
end
Here is the alternative:
it 'requests confirmation' do
visit user_path(user)
expect(page).to have_selector "a[data-confirm='Are you sure?'][href='#{user_path(user)}']", text: 'Delete'
end
This test cannot check if JS is working correctly, but it might be enough for the most of cases. (And fast!)

Why would this functional test be failing?

My haml :
- for status in current_account.job_statuses.active
= link_to status.name, '#', :class => params[:job_status_id].to_i == status.id ? "current status block" : "status block", :rel => status.id
My html :
<a rel="1" class="status block" href="#">in progress</a>
<a rel="2" class="status block" href="#">in progress</a>
<a rel="3" class="status block" href="#">in progress</a>
<a rel="4" class="status block" href="#">in progress</a>
My Test :
test 'index - job_status: set' do
job_status = #account.job_statuses.create! :name => 'foo'
job_status.reload
#job.update_attribute :job_status_id, job_status.id
#job.reload
get :index, :job_status_id => job_status.id.to_s
assert_response :success
assert_template 'jobs/index'
jobs = assigns(:jobs)
assert jobs.include?(#job)
assert_select 'div.status[rel=?]', job_status.id
end
But I get this failure :
3) Failure:
test_index_-_job_status:_set(NewJobsControllerTest)
[test/functional/new_jobs_controller_test.rb:127:in `block in <class:NewJobsControllerTest>'
test/test_helper.rb:221:in `run'
test/test_helper.rb:221:in `run']:
Expected at least 1 element matching "div.status[rel='16']", found 0.
<false> is not true.
Is this for an obvious dumb reason? I apologize if it is.. I can't figure it out.
Oh. It's always the little things we never think to check... After staring uselessly at that HAML I asked for for five minutes it hit me:
Those ain't DIVs. Those are As.
Cheers!

Cucumber `press button` failure (Capybara::ElementNotFound)

I'm a relative newbie starting up a new Ruby on Rails app. I started by following a combination of instructions at https://github.com/intridea/omniauth, http://www.communityguides.eu/articles/16, http://intridea.com/2011/1/31/easy-rails-admin-login-with-google-apps-and-omniauth?blog=company . At the point everything appeared to work correctly, I started to write my very first cucumber features and steps. I was able to get a couple of steps up and running, but I've been bogged down on a step that I thought was built in. I have a form with two submit_tags but I can't get a scenario to successfully pass a basic And I press "button" step.
possibly relevant gems:
rails (3.1.0.rc4)
capybara (1.0.0)
cucumber (1.0.1)
cucumber-rails (1.0.2)
nokogiri (1.4.7)
gherkin (2.4.5)
rack-test (0.6.0)
selenium-webdriver (0.2.2)
section of the form in question:
<%= form_tag :controller => "services", :action => "newaccount" do %>
<%= submit_tag "confirm", :id => "confirm", :title => "confirm", :value => "confirm", :text => "confirm", :name => "confirm" %>
<%= submit_tag "cancel", :id => "cancel", :title => "cancel", :value => "cancel", :text => "cancel", :name => "cancel" %>
<% end %>
scenario in question:
Scenario: I register with a valid and currently active google account
Given I am not registered
When I sign in with a valid and currently active google account
And I press "confirm" # <-- THE PROBLEMATIC STEP
Then I should see "Your account has been created and you have been signed in!"
I think this is the relevant web_step (straight from the default web_steps.rb which I have not edited at all):
When /^(?:|I )press "([^"]*)"$/ do |button|
click_button(button)
end
relevant cucumber output:
Scenario: I register with a valid and currently active google account # features/auth_and_auth/initial_tests.feature:6
Given I am not registered # features/step_definitions/authentication_steps.rb:1
When I sign in with a valid and currently active google account # features/step_definitions/authentication_steps.rb:5
And I press "confirm" # features/step_definitions/web_steps.rb:52
no button with value or id or text 'confirm' found (Capybara::ElementNotFound)
(eval):2:in `click_button'
./features/step_definitions/web_steps.rb:53:in `/^(?:|I )press "([^"]*)"$/'
features/auth_and_auth/initial_tests.feature:9:in `And I press "confirm"'
Then I should see "Your account has been created and you have been signed in!" # features/step_definitions/web_steps.rb:105
relevant html output:
<input id="confirm" name="confirm" text="confirm" title="confirm" type="submit" value="confirm">
<input id="cancel" name="cancel" text="cancel" title="cancel" type="submit" value="cancel">
As is obvious, I've accounted for value, id, text, as well as name and title. I also saw a post that said the input type had to be specified as submit which it appears to have been. And I've tried it with both the confirm button and the cancel button.
After searching everywhere that I know about, and trying every suggestion that looked even remotely relevant, I'm at an impasse. What am I missing?
I'm not sure if the code below is the best way to deal with the problem I encountered, but it is getting the relevant step to pass.
When /^(?:|I )press "([^"]*)"$/ do |button|
# click_button(button) # the original web_steps.rb version that fails
%{I press (button)} # my revised version that passes
end
I'd still appreciate any feedback on:
why the original web_steps.rb version fails,
whether this is an appropriate approach or not, and
if there is a more 'rails' way to deal with this.

Resources