Rspec/Capybara - Select Form should trigger Onchange event when testing - ruby-on-rails

I'm new to TDD and I actually wrote the code before the tests. The code itself works fine and from the main page the onChange event applies. However, when testing, even though a different option is chosen as the selected option(so the option does change), it seems that the onchange event is not actualled trigger when testing and it stays on the same page.it says expected: "/ctscans/index", got: "/" (using ==)
welcome_spec.rb
require 'spec_helper'
describe "Welcome Page" do
before {visit root_path}
subject{page}
describe "with Ctscan selected" do
before {select("CT Scan", :from => "procedure")}
it {should have_select('procedure', :selected => 'CT Scan')}
it "redirects to" do
select 'MRI', :from => 'procedure'
current_path.should == ctscans_index_path
end
end
end
views/welcome/index.html.erb
<%=select_tag(:procedure, options_for_select(#paths, :selected => #paths[0]),:onchange => "gotoNewPage()")%>
<script type="text/javascript">
function gotoNewPage() {
if (document.getElementById('procedure').value){
window.location.href = document.getElementById('procedure').value;
}
}
</script>

You haven't indicated that the spec needs to use a javascript driver. Try
describe "with Ctscan selected", js: true do ...

Related

Capybara cannot find a link on a modal which changes on button press

I have a rails project using rspec 3.4.0 capybara 2.6.2 and capybara-webkit 1.8.0.
I am writing a feature test for a flow on my site which looks like the following:
scenario "Buyer creates a seller profile", :js => true do
click_link("SELL ON MYSITE",match: :first)
expect(page).to have_text("Reach thousands of customers in your area")
click_link("Create an Activity",match: :first)
expect(current_path).to eql (new_seller_profile_path)
fill_in "seller_profile[business_name]", :with => "Test company"
fill_in "seller_profile[business_email]", :with => "test#email.com"
fill_in "seller_profile[business_phone_number]", :with => "07771330510"
fill_in "seller_profile[business_description]", :with => "This is a test company"
find('label[for="social"]').click
find("#facebook-placeholder").click
fill_in "seller_profile[business_facebook_url]", :with => "https://www.facebook.com/test"
click_button("CREATE AN ACTIVITY")
------this button opens a modal after the page changes --------
fill_in "seller_profile[requested_postcode]", :with => "EH21 8PB"
click_button("Submit")
save_and_open_screenshot
------this is where it goes wrong-------
click_link("Continue")
expect(page).to have_text("Choose the type of activity that you want to create")
end
The click_link continue fails with error:
Failure/Error: click_link("Continue")
Capybara::ElementNotFound:
Unable to find link "Continue"
The link actually does exist - when you click on the submit button some javascript executes which changes the contents of the modal to display some new text and a new button. However for some reason click_link does not wait or look in the modal, it fails straight away.
Having added a save_and_open_screenshot call we can see this situation as the modal javascript has yet to execute as we can still see the submit button :
Interestingly the mouse seems to not be on the Submit button as it should have just clicked it?
How can I make the click_link wait until the continue button appears?!
This is the javascript which executes on press of 'submit' added to the modal which changes it:
$('#gate .modal-body .intro').text('Congratulations, we are available in your location, please continue to create your activity.');
$('#gate .modal-footer').append('<a class="btn btn-lg btn-primary" href="/events/new/">Continue</a>');
Seemingly adding a couple of sleeps in has fixed it. I don't know if this is 'right' solution. If somebody has a better way or potentially a better way I would love you to help me find it :
fill_in "seller_profile[requested_postcode]", :with => "EH21 8PB"
sleep 2
click_button("Submit")
sleep 2
click_link("Continue")

Rspec with Capybara sometimes not pass tests

I have problem with testing Rails Application. My tests generally work perfectly. But sometimes tests will fail when I type some features test for modal bootstrap window, or notify with success/error [js]. How can I resolve this problem ?
I'm using Rspec, Capybara, Rails4.2, PhantomJs, Poltergeist as JS driver. Tests is running locally and in Wercker. In test mode, every bootstrap animation is disabled. What perhaps I do wrong ?
Test:
scenario 'return deutsch default title' do
find('.f-edit-item', match: :first).click
find('a', :text => 'Lang').click
find('a', :text => t('menu.languages.de')).click
find('.f-reset-button', match: :first).click
expect(page).to have_field('menu_item[title]', with: 'Exhibitions_de')
end
Output:
Objects Restore Language restore title translations exist for deutsch translation return deutsch default title
Failure/Error: expect(page).to have_field('object_item[title]', with: 'Exhibitions_de')
expected to find field "object_item[title]" with value "Exhibitions_de" but there were no matches. Also found "", "", which matched the selector but not all filters.
When I click manually, everything is working. When I run this test, sometimes passed, sometimes not. Form is in bootstrap modal. Curiosity: When I add save_and_open_page before find('.f-reset-button', match: :first).click test is passed always(5x in a row)
Because the tests are to do with a Bootstrap modal, my guess is that the test is searching the page for the matching elements, BEFORE the modal has loaded in the DOM.
Edit: As #TomWalpole pointed out, it should be enough to override Capybara's max wait time like so:
expect(page).to have_field('menu_item[title]', with: 'Exhibitions_de', wait: 1.0)
But if you are loading the contents of your modal via AJAX, you may need to force a wait for AJAX to complete the expect line. Here is a good guide on how to do this.
Specifically you need:
# spec/support/wait_for_ajax.rb
module WaitForAjax
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
loop until finished_all_ajax_requests?
end
end
def finished_all_ajax_requests?
page.evaluate_script('jQuery.active').zero?
end
end
RSpec.configure do |config|
config.include WaitForAjax, type: :feature
end
And then your test would become:
scenario 'return deutsch default title' do
find('.f-edit-item', match: :first).click
find('a', :text => 'Lang').click
find('a', :text => t('menu.languages.de')).click
find('.f-reset-button', match: :first).click
wait_for_ajax
expect(page).to have_field('menu_item[title]', with: 'Exhibitions_de')
end

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

Capybara isn't checking a checkbox in rspec feature test

I am attempting to create a feature test where a checkbox needs to be checked and for whatever reason Capybara is not checking the box.
I am using:
rspec: 3.0.4 and capybara: 2.4.1
When I print out a snapshot of the view, the checkbox isn't checked.
When I run the checkbox code in pry it returns the string "checked" but when I print a snapshot the checkbox still is not checked and my test does not pass. I'm curious if there is another way to get this checkbox to check.
Here is my current code so far:
Feature Test:
background do
discussion_group
#user2 = FactoryGirl.create(:user)
add_user_to_user_role_for_group(group, #user2)
admin_login
add_user_to_admin_role_for_group(group, #user)
visit groups_path
click_on 'Email Group'
end
scenario 'sending a valid email' do
valid_form
expect(page).to have_content group_email_success_notification
expect_count_of_deliveries_to_be 1
end
Macro:
def valid_form
fill_in 'group_email_subject', with: new_text
fill_in 'group_email_body', with: Faker::Lorem.words(200).join("\s")
check "group_email_#{#user2.id}_"
click_on "Send Email"
end
The output of my test is that I must have 1 user selected meaning that I don't have a user checked. When I run the check line in console here is what I get:
[10] check('group_email_10_')
=> "checked"
Any help is greatly appreciated.
I'd use:
page.check('insert #id, .class, or value')\
for example:
input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes"
page.check('puppy_gooddog') or page.check('puppy[gooddog]')

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!)

Resources