Capybara integration test object creation - ruby-on-rails

I have a basic integration test that is using Capybara, the problem is that if I do not create the required objects firstly the integration test fails. Am I required to create all objects as the first step in an integration test using Capybara? I am using Rails 4.2.4 with Capybara 2.4.3
Fail
scenario 'if media content contains more than 10 items display pagination links' do
sign_in
# Object creation
11.times do
FactoryGirl.create(:media_content)
end
within '.pagination' do
expect(page).to have_content '1'
end
end
Success
scenario 'if media content contains more than 10 items display pagination links' do
# Object creation
11.times do
FactoryGirl.create(:media_content)
end
sign_in
within '.pagination' do
expect(page).to have_content '1'
end
end

If the objects creation affects the page that you are visit-ing in your capybara test then yes, you need to create the objects before you test for elements on that page because upon visiting the page, its content is already grabbed by the test browser.
I assume that you have a visit "some_login_page" and perhaps a redirect upon successful login in your sign_in method, so when finishing the sign_in, the test browser already visited (i.e. grabbed) the page on which you are trying to test content later.
The only exception that comes to my mind is if you used a delayed AJAX request to grab the newly created elements from the server to the page dynamically - in that case creating the objects after page visit might work ok.

Related

Rspec testing, Capybara unable to find link or button

This the part of my requests test that fails:
scenario 'Admin destroys a job posting + gets notified' do
parent = create(:parent)
create(:assignment, user_id: #user.id, role_id: 1)
demand = create(:demand, shift_id: 4)
sign_in(#user)
visit demands_path
click_on 'Destroy'
expect(page).to have_content('successfully')
end
This is the error:
Failure/Error: click_on 'Destroy'
Capybara::ElementNotFound:
Unable to find link or button "Destroy"
And here is the corresponding index view, including a "Destroy" link in the app:
Any idea why this test fails??
Odds are the data you assume is on the page actually isn't. This could be for a number of reasons.
Your page requires JS and you're not using a JS capable driver - see https://github.com/teamcapybara/capybara#drivers
Your sign_in method is defined to fill in user/pass and then click a button, but doesn't have an expectation for content that confirms the user has completed login at the end. This can lead to the following visit occurring before login has completed and therefore not actually logging in. Verify that by inspecting the result of page.html or calling page.save_and_open_screenshot before the click.
Your 'Destroy' "button" is neither an actual <a> element or <button> element. Fix that by either using semantic markup or swapping to find(...).click
You are using a JS capable driver but your records aren't actually visible to the app - this would affect all your tests though so I assume it's probably not this. If this was the case the login would fail and you'd probably need to install database_cleaner and configure for use with RSpec & Capybara - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example

How to correctly test one object on the page

I'm creating rails application with posts and likes.
feature "Create like" do
include_context "user signed in"
def have_updated_likes_count
new_likes_count = bonus.likes_count
have_content("Likes #{new_likes_count}")
end
let!(:bonus) { create(:bonus) }
let(:decorated_bonus) { bonus.decorate }
before { visit root_path }
scenario "User likes bonus", js: true do
find(".like").click
expect(bonus).to have_updated_likes_count
expect(page).to have_content(current_user.full_name)
end
end
Bonus = post. As u see here I check if User likes bonus. But in this root_path (main page) I have a lot of posts (20), and each of post has likes. My test trying to check expect(bonuses).to have_updated_likes_count and expect(page).to have_content(current_user.full_name) and it always true both, because it check full page, but I need to check only one post (where I did find(".like").click). How can I solve my problem?
It depends on what your page structure is but generally you want to scope your actions to a specific element using within.
page.within('selector that finds the post element') do
find(".like").click
expect(bonus).to have_updated_likes_content # issues
expect(page).to have_content(current_user.full_name) # issues
end
That answers your question, however the rest of the test has a few issues you'll need to work out too.
Once you click the .like element the bonus object gets updated asynchronously, so trying to access it immediately is going to be flaky and you should really be checking for some other visual change on the page before checking it.
You're not reloading the bonus object from the database so it'll probably still have the same value

End of file Rspec error with AJAX

I'm trying to test that I can POST a survey via AJAX
Test code:
describe "when completing the survey" do
before do
visit "/orders/#{#order.disguised_id}?key=#{ENV['admin_code']}"
find("#show-survey").click
find(".modal#survey-box select[name='heard']").find("[value='Other']").select_option
find("#submit-survey").click
end
it "should submit correctly" do
#order.reload
#order.heard.should == "Other"
end
# test post survey
end
First off, I can confirm via manual testing that this works. The issue is that the spec fails:
1) when completing the survey should submit correctly
Failure/Error: find("#submit-survey").click
EOFError:
end of file reached
# ./spec/features/edit_order/editing_order_spec.rb:<<the line with find("#submit-suvery")>>
When it fails, the Rspec auto ends the run and I'm left with an open browser window (using Selenium) and a regular command line interface. This is the controller that receives the POST
def survey
#order = Order.find_by_disguised_id(order_params[:disguised_id])
#order.update_attributes(order_params)
render nothing: true
end
If you're using chrome with selenium make sure you're running the latest version of chromedriver (2.24 as of this answer).
Additionally - click is asynchronous so reloading the order immediately after clicking #submit-survey is going to be flaky at best since it's highly likely it will be reloading #order before the ajax request is processed. You need to wait for whatever visual change on the page would indicate the survey has been submitted after clicking.
find("#submit-survey").click
page.should have_text('something') # whatever shows up when the survey finishes submitting - or use have_css, etc
Also the previous line find(".modal#survey-box select[name='heard']").find("[value='Other']").select_option can be written in a more readable manner as
find(".modal#survey-box").select('Other', from: 'heard')

RSpec and Capybara setup, have_no_content doesn't seem to be working

I'm creating an app where I have a simple delete record on the index of the records once a user logs in. When I don't have the user logging in under my rspec specs, the delete works. Meaning that the has_no_content test returns true. But once I put in place the authentication required to access the index of records, the test fails. Any thoughts?
before do
#records = Factory(:record)
login_user
end
it "should delete a record" do
visit records_path
find("#record_#{#records.id}").click_link 'Delete'
page.should have_content "Record has been deleted"
page.should have_no_content "Record 1"
end
Nevermind - I figured it out with the help of using launchy.
My initial thought was that I was some how losing the "session" and that once the delete link was clicked, then the login page was being displayed again. That wasn't the case at all. I did notice though that the header of my app also contained "Record 1" in it. Therefore the spec would fail for obvious reasons. Head to desk - sorry about that, but I figured I'd post my own stupidity and looking way deeper than I needed to.

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