Rails, Capybara - click_link on remote links doesnt work - ruby-on-rails

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.

Related

Capybara::ElementNotFound: Unable to find file field "file"

Hi i am a beginner in rails and encounter some issues when i try to run rspec capybara test.
require 'rails_helper'
describe "Upload Process", :type => :feature do
it "Can upload a file" do
visit new_document_path
page.attach_file('file', '/Users/yaomin/Desktop/my_travel_pic/uploadtest.jpg', visible: false)
click_button 'Upload'
page.should have_content("Uploadtest")
end
end
but i got the error
Failures:
1) Upload Process Can upload a file
Failure/Error: attach_file('file', '/Users/yaomin/Desktop/my_travel_pic/uploadtest.jpg', visible: false)
Capybara::ElementNotFound:
Unable to find file field "file"
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/node/finders.rb:44:in `block in find'
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/node/base.rb:85:in `synchronize'
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/node/finders.rb:33:in `find'
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/node/actions.rb:256:in `attach_file'
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/session.rb:769:in `block (2 levels) in <class:Session>'
# /Users/yaomin/.rvm/gems/ruby-2.3.1/gems/capybara-2.13.0/lib/capybara/dsl.rb:52:in `block (2 levels) in <module:DSL>'
# ./spec/features/upload_test.rb:9:in `block (2 levels) in <top (required)>'
Finished in 0.40034 seconds (files took 1.99 seconds to load) 1 example, 1 failure
Failed examples:
rspec ./spec/features/upload_test.rb:5 # Upload Process Can upload a file
my view codes are
h1 Listing documents
table
thead
tr
th
th
th
tbody
- #documents.each do |document|
tr
td = link_to 'Show', document
td = link_to 'Edit', edit_document_path(document)
td = link_to 'Destroy', document, data: { confirm: 'Are you sure?' }, method: :delete
br
= link_to 'New Document', new_document_path
below is the new document view
h1 New document
= render 'form'
= link_to 'Back', documents_path
- if #document.folder
= link_to "Back to '#{#document.folder.name}' Folder", browse_path(#document.folder)
- else
= link_to "Back", root_url
and my form partial
= form_for #document do |f|
- if #document.errors.any?
#error_explanation
h2 = "#{pluralize(#document.errors.count, "error")} prohibited this document from being saved:"
ul
- #document.errors.full_messages.each do |message|
li = message
= f.label :file
= f.file_field :file
- f.hidden_field :folder_id
= f.submit "Upload"
For information, i can actually upload files manually but the upload test i run fails.
Thanks in advance for all your help :)
The first parameter passed to attach_file needs to be either the id, name, or associated labels text. In your case that's probably not 'file'. You state the associated label text is "Choose File" so probably something like
attach_file('Choose File', file_path)
is what you want (impossible to say exactly what the first parameter should be without the actual HTML). Other things that may work would be
attach_file('document_file', file_path) # match the elements id
attach_file('document[file]', file_path) # match the elements name
but again, the first parameter could be slightly different, the HTML will show what they should be.
The other issue that is common with file inputs is that they may be hidden with CSS (made transparent, etc) in order to style the same across browsers. If that is the case and you are using a JS capable driver you can use something like
attach_file('Choose File', file_path, make_visible: true)
which will attempt to make the field visible, set the file, and then restore the original CSS.

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

Capybara::ElementNotFound - How to click on specific button with id using Capybara

Trying to access this button on root url:
here is html
with this test:
feature "New comment button" do
scenario "User can add new comment on root page", :js => true do
visit root_path
id = 152
click_button("#button_#{id}")
within("#comment_row_#{id}") do
fill_in('content', :with => 'this is a comment')
click_button('create comment')
page.must_have_flash_message('Successfully created')
end
end
and geting this:
Capybara::ElementNotFound: Unable to find button "#button_152"
How to get this element using id ?
I am using selenium-web-driver
EDIT
WHAT I TRIED
# page.driver.browser.switch_to.frame 'top-frame' # Selenium::WebDriver::Error::NoSuchFrameError: Unable to locate frame: top-frame
# page.find('#button_152').click # not working
# click_button("#button_152") # not working
# first(:xpath, '//button[#id="button_152"]').click
2.This is an overview of frames :
all iframes are just google chrome addons
4.link to full html
You can read about switching windows and frames here: http://docs.seleniumhq.org/docs/03_webdriver.jsp#moving-between-windows-and-frames
Ruby specific bindings here: https://code.google.com/p/selenium/wiki/RubyBindings
Capybara handling iframes: handling iframe with capybara ruby
As for your problem, here's an example you can edit:
within_frame 'evernoteFilingTools' do
click_button("#button_#{id}")
#button_#{id} # not working
#page.find("#button_#{id}",:visible => true).click # does not work as well
within("#comment_row_#{id}") do
fill_in('content', :with => 'this is a comment')
click_button('create comment')
page.must_have_flash_message('Successfully created')
end
end
You should replace evernoteFilingTools with the iframe ID that contains the content you want to manipulate
Sometimes, it can be thrown off by invalid markup. This HTML has a div (<div class="icons">) inside a table, which is not valid. Try running the markup through a validator such as http://validator.w3.org/ and fix any errors it reports. That might fix your Capybara problem as well.

Failing Spec for button

So I recently took on a project upgrading a Ruby 1.9.3 / Rails 3.2 application to Ruby 2 / Rails 4.0.2. All seems to be well, but I have a failing spec. I'm trying to test that a button is working at the bottom of the page for a "suggestions" box.
Failure message is:
Failures:
1) StaticPages Scheduler Page after authenticating filling in the suggestion form after submitting the form should send an email request with the form contents
Failure/Error: click_button("suggestion-button")
ActionController::UnknownFormat:
ActionController::UnknownFormat
# ./app/controllers/static_pages_controller.rb:39:in `suggestion'
# ./spec/features/static_pages_spec.rb:93:in `block (6 levels) in <top (required)>'
Spec reads:
context "after submitting the form" do
before(:each) do
click_button("suggestion-button")
end
Controller reads:
def suggestion
if user_signed_in?
user = current_user.email
else
user = "< not logged in >"
end
if params[:suggestion]
ContactMailer.suggestion_email(params[:suggestion], params[:pathname], user).deliver!
end
respond_to do |format|
format.json { render json: params[:suggestion] }
end
end
The source for the button on the page is:
<button type="submit" class="btn" id="suggestion-button">
Tell Us!
</button>
</form>
<script>
// After form submission, gray out and disable the form
$(document).ready(function(){
$("#footer-suggestion-form").bind("ajax:complete", function(event, xhr, status){
console.log($("#footer-suggestion-form input"));
$("#footer-suggestion-form input").attr("disabled","disabled");
$("#footer-suggestion-form button").attr("disabled","disabled").html("Thanks!");
console.log("did it!");
});
$("#suggestion-pathname").val(location.pathname);
});
</script>
Is it because it's an AJAX form? Or just a test that worked in Rails 3.2 but no longer works in 4 because of some change? I appreciate any help, I am truly lost.
I did try using :js => true in the spec and downloading the capybara-webkit gem, but when I try to run the spec it gets to that test and then just hangs there waiting for something to happen that never does.
EDIT: Progress. Now it gets to that test, sits for a big, and then fails with
1) StaticPages Scheduler Page after authenticating filling in the suggestion form after submitting the form should send an email request with the form contents
Failure/Error: before { visit scheduler_path }
RuntimeError:
Rack application timed out during boot
./spec/features/static_pages_spec.rb:31:in `block (3 levels) in

Resources