filling hidden fields with capybara - ruby-on-rails

I am proceeding to integration testing and I have to populate some hidden field. The problem is this seem not to be taken into account
it "submits project form" do
page.all("#project_description", :visible => false).set(#project.description)
click_button "submit"
expect(page).to have_content #project.description
end
the problem is that I get this error message when launching the task Description can't be blank. I am sure the the hidden field is found, but the filling is not done. How can I fix it ? (I set Capybara.ignore_hidden_elements to false)

It may not be the best solution, but you could do it with javascript. For exemple, if you're using jQuery:
page.execute_script "$('#project_description').val('#{#project.description}')"
If there are some ' characters in the #project.description, you need to escape them (see JavaScriptHelper, not sure how to use it in integration test).

Related

Rails, Capybara - capybara cannot find added html elements sometimes

I have a function below
def fill_in_sources_details
click_button 'New Source'
assert_text 'Sources'
fill_in 'text', :with => #source.text
fill_in 'url', :with => #source.url
end
After New Source clicked, new fields added to the page. Sometimes the test fails because the test doesn't wait for new elements to be added so new fields cannot be found be Capybara. I tried to add assert_text 'Sources' which is obvious but it still fails sometimes. Any idea how to fix it?
A number of things could be going on here, some of which depend on which driver and driver version you're using.
You don't actually have a field that matches 'text' - That's not likely here since it works sometimes.
The initial click_button 'New Source' is missing the actual button. This could happen depending on which driver you're using if the button animates on to the page (slide in, zoom in, etc). You can tell if that's what's happening by putting a sleep 5 before the click_button. If that fixes the issue then you should look into disabling animation in test mode. It will speed up your tests and make them more reliable.
The click_button is happening but it takes too long for the fields to show on the page (slow ajax request, etc). Putting the sleep 5 after the click_button should have diagnosed that, however maybe it's taking longer than 5 seconds. The assert_text 'Sources' is a good attempt to diagnose that, as long as the text 'Sources' would only be on the page when the input is visible but that text seems too generic for that (it's probably on the current page already). You can always pass a wait option to fill_in, which will make it wait longer for the element to appear
fill_in 'text', :with => #source.text, wait: 20
You have an intermittent error in your app that's preventing the fields from showing. Diagnose that by catching the ElementNotFound, pausing the app and looking at the errors in your browser
begin
fill_in 'text', :with => #source.text, wait: 20
rescue Capybara::ElementNotFound
binding.pry # byebug, etc - whatever debugging you use
end

Why Capybara feature tests don't wait?

I have a small trouble with my tests suite: when I run spec which the checking ajax action on the page, sometimes I get random error
Failure/Error: expect(page).to have_content 'DHH'
This error shows very rarely (about 1/100), but this very confused me. I decided this a 'race condition' cause, and I add this config in my spec/rails_helper.rb
Capybara.default_max_wait_time = 10
but this is don't help for me, and I decided add timestamps
it 'adds new DHH', js: true do
find('#modal_new_dhh').click
fill_in('name', with: 'DHH')
p 'click button'
p Time.now.strftime('%H:%M:%S.%L')
click_button('Submit')
p 'checking content'
p Time.now.strftime('%H:%M:%S.%L')
expect(page).to have_content 'DHH'
p 'after checking content'
p Time.now.strftime('%H:%M:%S.%L')
end
and see that
"click button"
"17:34:43.083"
"before checking content"
"17:34:43.127"
"after checking content"
"17:34:43.213"
why Capybara don't wait after click button?
sorry for my bad English
The wait in your example occurs in the have_content matcher. Where you're outputting times from will never show a delay because click_button has nothing to wait for, it just clicks a button and moves on (because it has no idea what it would wait for, clicking a button could do anything), however the have_content matcher will wait up to Capybara.default_max_wait_time for the content to appear.
Note your find, 'fill_in' and click_button calls also wait for the relevant elements to appear BEFORE performing their actions
As you said this is a race condition. As to why it happens, I can't really say, the only reason I could think of would be that there is a difference between a user experience and an automated testing, because computers are very fast.
I had faces the same challenge sometime ago and I found this tutorial which showed me a way to go about resolving these kind of issues. I hope it would be useful to you too.

How to test that a form successfully submitted using Rspec?

I'm writing feature specs for my Article form.
In one test, I have RSpec look for certain form inputs using the labels:
expect(find_field("Title")).to_not be_nil
Now I'd like to know if the form was submitted properly. How can I do this using RSpec, if you aren't supposed to check the database from a feature spec?
For example, what if I mistyped the name attribute on the Title input? The label would still be found by my find_field() call, and controller specs would have me specify the title in a hash.
In this case one would assume a Title would be required for an Article so if the name attribute was misspelled the creation of the Article would fail and you'd end up on an error page (Also an unpermitted parameter would raise in the creation by default in test mode with strong parameters). If its a field not required for creation of the Article then the assumption is that the info is displayed in the app somewhere and can be checked for on that page.
As an aside your sample expect would read much clearer if rewritten as
expect(page).to have_field('Title')
There are loads of way to approach this:
expect(page).to have_field('Title')
expect(page).to have_css('#someSelector')
expect(current_path).to eq article_path (for example)
expect(page).to have_content "ABC" (i.e. some content which will be rendered)
The Capybara readme on Github is a really good one full of easy to follow examples - https://github.com/jnicklas/capybara.

Rspec with capybara facing issue with page.should have_content

I am new to Rspec and here I am trying to test one of the integration test. When I (Using Capybara) clicks button then page content gets replaced with post response. Now i am checking for page content, it present on the page but still my test is failing.
Below is the spec
it "get force check takeover1" do
visit('/las_xml')
select('Showroom', :from => 'urlVal')
fill_in('fpHeaderForce', :with => 'PSD.L.Syn')
fill_in('currentDate', :with => '2013-09-11')
click_button('submit')
page.should have_content('Buy 2013 Labor Law Posters')
end
But Result is,
1) las box get force check takeover1
Failure/Error: page.should have_content('Test page')
expected #has_content?("Buy 2013 Labor Law Posters") to return true, got false
# ./integration/las_box_spec.rb:19:in `block (2 levels) in <top (required)>'
and resulted response html contains,
<div class="las-link" id="">
<div class="laborLink_actual labor_01">
<span class="laborLink"></span>
Buy 2013 Labor Law Posters
</div>
</div>
Possible causes
Provided you're indeed testing a html page as your result excerpt seems to show, there may be several possibilities, here :
the text you're trying to test is not the actual one. Double check there's no typo and you use the same locale if multiple language website
the element containing the text may be hidden. Capybara won't consider the content to exist if it is not visible
the previous click on button may simply not work or may lead to an other page
Ways to isolate problem
As often with capybara since fails are just symptoms of real problem, we can deal with all problems using debugging features :
page.save_screenshot( filename ) : saves a screenshot to given file name (for example, 'shot.png')
save_and_open_page : open an inspectable html page in your browser
binding.pry : from pry gem, always useful to inspect context
For an example of screenshot creation through poltergeist, see this.
Edit : dynamic page problems
As mentioned in comments, problem seems to be tied to javascript content editing.
You should still use debugging mentioned before to be sure to isolate your problem. Once done, you can use capybara's #synchronize method to wait for your content :
page.document.synchronize( 10 ) do
result = page.evaluate_script %($(':contains("Post")').length)
raise Capybara::ElementNotFound unless result > 0
end
The synchronize method will be retried for 10 seconds, as long that the containing block raises a Capybara::ElementNotFound exception (any other exception is not catched). So basically, here, we check (using jQuery) if the "Post" content is present in page, and retry until it is or until ten seconds have passed.
If element was not found, test will fail by raising an uncaught exception.
If element is found, you can now proceed with your regular test. This allow to add timing condition in specs.

how to test a stale link click (or link I can't get to) using capybara/rspec

Artists cannot rate their own artworks
it "should display error if voting on own artwork", :js => true do
sign_in
visit "/upcoming"
click_link "like_post_1"
page.should have_content("Can't vote on your own artwork")
end
This was passing just fine.
However, I can't click on like_post_1 anymore because I added a feature to prevent voting links from appearing next to your own artworks.
Does this mean I no longer need test coverage for this scenario because it's extremely rare that someone can click on a voting link for their own artwork? Or should still have coverage to test the ajax response, because it's not tested anywhere else and it's possible for some stale page of links to somehow exist in a tabbed browser window. If so... how do I test it if I cannot call click_link?
I could try to create a POST request to create the vote, but capybara doesn't support posts, and I can't test the ajax response that way...
Or is there a way to simulate tabbed browsing in capybara?
Suggestions?
You can use CSS display:none or visibility:hidden for the own artwork instead of eliminating the link from the DOM. You might have to set
Capybara.ignore_hidden_elements = false
Another way is giving up Capybara and putting them into the controller/model spec. Controller/model spec might be a better place for the extremely rare case or safeguarding your app case.
Please try this:
Use sleep function.
sleep 10 use to wait process upto 10 seconds..
it "should display error if voting on own artwork", :js => true do
sign_in
visit "/upcoming"
click_link "like_post_1"
sleep 10
page.should have_content("Can't vote on your own artwork")
end

Resources