Capybara click_link works wrong - ruby-on-rails

I have such bug. Here is my code:
it "shows places sorted by date of creation" do
click_button( I18n.t("models.places.actions.index.sort_by"))
click_link(I18n.t("models.places.actions.index.date_of_creation"))
sorted_places_names = places.map(&:name).reverse
link_names = all("a.place-link").map(&:text)
expect(link_names).to eq(sorted_places_names)
end
And my problem is that click link here must to send params:
"?by_created_at: true" and controller response with sorted places by date of creation, in descendant order.
My problem is when capybara clicks on this link, GET request have only path, without params needed.I`m using poltergeist here.
Also I have such test:
it "shows orders today" do
today_order.customer.reputations << create(:reputation, place: place)
visit place_statistics_loyalty_path(place)
click_link(I18n.t("statistics.loyalty.today"))
expect(page).to have_selector("#order_#{today_order.id}")
end
It tests out similar behaviour. And it works properly, but here I am not using js.
Is it javascript driver problem ?
Thanks. Sorry for bad text, it`s my first question.

What you're looking to do is use Poltergeist's "send_key" method as shown here in the documentation:
https://github.com/teampoltergeist/poltergeist#sending-keys
Setting the keys using that method and then proceeding with clicking the link should work.

Are you sure you're actually using poltergeist for that test since there is no js: true or driver: :poltergeist metadata on it? If it was not using poltergeist and actually just using the rack_test driver then no JS would get excuted and you would likely see the behavior you're seeing.
If you are actually using the poltergeist driver then it's possible you have a race condition, due to click_button being asynchronous, which could cause the by_created_at parameter not to be set before the link click actually happens. You can test if that is the issue by putting a sleep 2 between the click_button and click_link calls

Related

Capybara webkit doesn't pass params from angular

I am trying to port a selenium test suite to capybara-webkit. The Rails app has an angular app embedded in the rails views and is not behaving as expected with webkit.
A test like this:
require 'spec_helper'
feature 'Editing company profiles' do
before do
#user = create(:employee)
#company = Company.find(#user.employer.id)
sign_in_as! #user
end
scenario 'successfully', js: true do
click_link 'Dashboard'
click_link #company.name
click_button 'Edit'
fill_in 'company_name', with: 'new name'
click_button 'Save'
expect(page).to have_content "Your company profile has been updated!"
end
end
Will pass without issue in selenium, but with webkit I get the error
Failure/Error: Unable to find matching line from backtrace
ActionController::ParameterMissing:
param is missing or the value is empty: company
# ./app/controllers/api/v1/companies_controller.rb:23:in `company_params'
# ./app/controllers/api/v1/companies_controller.rb:10:in `update'
The trace is missing, maybe because it's from angular land, but the error is reporting that no params are coming from the client. I've tried the capybara-angular gem, but it has not helped. I've also tried saving the page with capybara and nothing looks out of place there, are there any ways to access the PATCH request inside of webkit that's being generated in this test? I've also gotten similar errors with poltergeist.
Has anyone setup headless rspec testing with angular + rails? Any tips on how to debug why data isn't being sent over from the client?
Without seeing all of your code, this feels like it could be a problem associated with a known issue in the capybara-webkit gem is unable to pass entity bodies to the server.
I suspect that the update request is being sent as a PATCH request (which is appropriate), but the issue with the gem results in failure for your tests.
A workaround to your problem is to change the method of the request to PUT or POST, the issue linked above shows some options. You will be able to get your test to pass, but it's up to you to decide if changing the request type is worth getting your test to pass.
Note: In practice it may not matter if you don't actually use PATCH, as you could technically use (some of) the other http methods interchangeably -- but use caution as there are reasons to use a specific http method for a given situation. See this rubyonrails.org post from a few years ago for some details.

Capybara Selenium webdriver Transactional Rollbacks work arounds

I'm writing a couple of Feature Specs for an app and using the default Selenium webdriver that comes with Capybara. This is the spec I have written.
DatabaseCleaner.cleaning do
find(:css,'.dropdown-toggle').click
click_on "Locations"
find(:css, "#location-8-upgradesub-60").click
value1 = find(:css, "#location-8-review-subscription").text
value1.should be == '(2) Reviews (Paid)'
end
I'm facing 2 issues with this snippet:
1) Capybara isn't waiting for the XHR to get over and is coming out of the test before that. It works if I give a sleep condition for about 10 sec.
UPDATE
Solved 1) by setting Capybara.default_wait_time = 15 and writing a helper to make sure jQuery isn't active. page.evaluate_script('jQuery.active').zero?
2) I'm not able to rollback the DB transaction that takes place when selenim simulates the test. I see an INSERT and COMMIT in the test.log but no ROLLBACK because of which I need to keep changing my specs every time I run the test. If I use,DatabaseCleaner.strategy = :truncation, my entire DB gets wiped out and that is not something I want.
I've done some extensive googling on this issue and haven't been able to find an efficient work around. I've tried using the same transactional thread too, for the test server. Haven't had fruitful results with too! Any heads up or help would be greatly appreciated. Thanks in advance!
UPDATE
I followed this link https://relishapp.com/rspec/rspec-rails/docs/transactions and put my spec inside a before(:each) block and stored the value in an #value1 instance variable to compare it with the desired value within the it block. I haven't had any luck with that too.
before(:each) do
find(:css,'.dropdown-toggle').click
click_on "Locations"
find(:css, "#location-8-upgradesub-60").click
wait_for_ajax #Helper method to wait for ajax call to get over
find(:css, "#location-8-review-subscription").should be_visible
#value1 = find(:css, "#location-8-review-subscription").text
end
it "should open the dropdown, find Location and open it's modal", js:true do
#value1.should be == '(2) Reviews (Paid)'
end
With 1), I think have_content or have_selector will work. These methods will wait for some seconds before checking the content/selector exist. You could config this time via spec_helper.rb. You could put have_content/have_selector BEFORE your find(..).click to make sure it is exist before next tests.
Finally found a work around. I added this code snippet in spec_helper.rb. Not using Database Cleaner anymore.
Reference: http://www.opinionatedprogrammer.com/2011/02/capybara-and-selenium-with-rspec-and-rails-3/#comment-441060846. The entire comment thread is pretty useful.
ActiveRecord::ConnectionAdapters::ConnectionPool.class_eval do
def current_connection_id
# Thread.current.object_id
Thread.main.object_id
end
end

Ruby on Rails - RSpec Javascript Test with Capybara (new to RoR)

New to Ruby, Rails and TDD. I'm using RSpec with Capybara and Capybara webkit.
Trying to test if a div element exists on a page.
Test Code:
require 'spec_helper'
describe "Login module" do
before do
visit root_path
end
it "should have a module container with id mLogin" do
page.should have_css('div#mLogin')
end
it "should have a module container with id mLogin", :js => true do
page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
end
end
The first test passes but the second test fails with:
Login module should have a module container with id mLogin
Failure/Error: page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
expected: "mLogin"
got: nil
Ran the JS in browser dev tools and get "mLogin" rather than nil.
Any ideas? Thanks.
find('div#mLogin')[:id].should eq 'mLogin'
See this from doc:
#evaluate_script
Evaluate the given JavaScript and return the result. Be careful when using this with scripts that return complex objects, such as jQuery statements. execute_script might be a better alternative.
evaluate_script always return nil, as far as I remember.
Anyway, your second test seems like is testing if capybara works, because your first test is enough.
One likely problem is that the have_css matcher supports Capybara's synchronization feature. If the selector isn't found right away, it will wait and retry until it is found or a timeout elapses.
There's more documentation about this at http://rubydoc.info/github/jnicklas/capybara#Asynchronous_JavaScript__Ajax_and_friends_
On the other hand, evaluate_script runs immediately. Since this is the first thing you do after visiting the page, there's a race condition: it's possible that it executes this script before the page has finished loading.
You can fix this by trying to find an element on the page that won't appear until the page is loaded before you call evaluate_script.
Alternately, you can wrap your call in a call to synchronize to explicitly retry, but this is not generally recommended. For situations like this, you're much better off using Capybara's built-in matchers. The evaluate_script method should only be used as a last resort when there is no built-in way to accomplish what you need to do, and you need to take a lot of care to avoid race conditions.

Capybara with RSpec returning empty body for page object

When working with Capybara and Rspec in my features spec, after calling "visit", page.body returns:
"<html><head></head><body></body></html>"
This, of course, causes all my "find"s to fail, as there is nothing there. save_and_open_page care of launchy shows me the complete, accurate page, chock full of HTML tags.
Any thoughts on why Capybara is not setting the page element correctly?
turns out this was due to a conflict between webrat and capybara. Diving into the source for where "visit" and "page" are referenced, I discovered that visit is declared in both Webrat and Capybara; however, the effect of "visit" in each differs. Capybara sets the page variable, while webrat sets a response variable. I don't yet know enough about how to use both of them, as they seem to both be useful for different purposes - if anyone wants to leave some comments with some resources I certainly would appreciate it!
I was getting this too.
When I puts out the markup from the visit call, I found that the page was actually throwing a 404, but I wasn't getting a Capybara 404 error.
If you run something like the following, it will print out the markup so you can debug more easily:
When /^I view the front page$/ do
#visit = get "#{host}/frontpage"
puts #visit
end
Hope that helps someone.

Capybara click_button works, but how do I evaluate the JSON response?

Soo, if Capybara can interface with the DOM and my app makes a form submit via AJAX and returns some JSON, can Capybara see that at all? I'm not finding any way to get to the AJAX response in the Capybara API.
Here's an example of kinda what I'm doing:
# Cucumber step_definition
Then(/^I should be able to create a household$/) do
click_link 'Next'
page.should have_selector 'form#household-form'
fill_in 'Name', with: name = Faker::Name.last_name
click_button 'Create'
page.wait_until do
page.evaluate_script('$.active') == 0 # really awesome hack to wait for ajax
end
#user.reload.households.first.name.should eq name
end
I'd rather not hit the database again to test the result, but instead do something like:
xhr.response_data.should be_json
Verifying that my json response is what I thought it should be.
I'm just experimenting here, trying to get used to Cucumber and Capybara.
You should mark your scenario / feature to run as a JavaScript feature by tagging it with #javascript:
#javascript
Scenario: Title goes here
What this will do is to tell Cucumber to run the selenium-webdriver gem which will launch a real browser (Firefox) and run the test inside that browser. The browser will of course evaluate the JavaScript and then Capybara will be able to see what it outputs.

Resources