Weird behavior from capybara when passing a symbol to select - ruby-on-rails

I just spent half an hour fixing error messages I got from rspec when doing the following:
click_button 'Create Paste'
I tried it with save_and_open_page and the button was definitely there. The error message I got was:
Failure/Error: click_on 'Create Paste'
ActionView::Template::Error:
Invalid id given:`
Turns out that the problem wasn't even related to that click_on call but rather caused a line a bit above:
select #paste.language, :from => 'paste_language'
#paste.language was a symbol and adding .to_s fixed the problem.
I am new to Ruby, Rails, Capybara, RSpec and that whole stack so this might be obvious but isn't this something that should have been caught earlier? If so I might file a bug report, but I just want to make sure first.

From the documentation: "The select box can be found via its name, id or label text".
So you need text, i.e. string, and not a symbol. If you want the method to accept symbol (which makes sense), discuss it with the capybara's author (set up an issue on the project's gihub page) and send him a pull request.

Related

Cucumber/Capybara: Test is not accurately reflecting real world use. It is ignoring page errors and passing tests

I did a total rearrangement of my routes so I'm having to go back and change some path names. I ran a cucumber test for my navigation and it came back a success. Knowing that I have some old routes to change I thought that was an odd result so I did some manual checking to confirm my suspicions.
As an example I clicked on a page that was supposed to have a old and obsolete path <li><%= link_to p.title, forum_post_path(p) %></li> that's breaks the page when I am manually clicking around I get a no method error as I should.
But, when I run the cucumber test and use launchy to save and open page. I don't get that error. It loads like there isn't a problem at all. The launchy page that I'm given loads the link_to helper with the bad _path like there isn't a problem at all...
The only thing I can think of is that the words that it is expecting would be there and perhaps the page is loading correctly for a brief moment before Rails spits out the method error and Cucumber is picking up on the positive result first before it returns an error.
Any possible things I can look at? I would hate to get false positives.
Edit: I just added a 1 second sleep timer (should be more than enough) and cucumber still gives me a pass.
Here are the tests so you can view it:
# navigation.feature
Scenario: As a user I want to be able to view a specific forum and it's posts within.
Given There is a User
Given There is a Forum
Given I am on the index
When I click the "Test forum name" link
Then I should see "Name: Test forum name"
Then I should see "Description: test description with a minimum of 20 characters.."
And...
#navigation_steps.rb
Given(/^There is a User$/) do
User.create!(email: "user#test.com", password: "password#1")
expect(User.first.email).to eq("user#test.com")
end
Given(/^I am on the index$/) do
visit root_path
end
Given(/^There is a Forum$/) do
Forum.create!(name: "Test forum name", description: "test description with a minimum of 20 characters..", user_id: User.first.id)
expect(Forum.last.name).to eq("Test forum name")
end
When(/^I click the "([^"]*)" link$/) do |link|
click_link link
end
Then(/^I should see "([^"]*)"$/) do |message|
expect(page).to have_content(message)
end
Screenshots:
You don't say what exactly your tests are checking for, but a couple of possible reasons for this are:
You're using something like spring to keep your test environment loaded - If you are it may not be seeing changing to routes.rb and may require restarting before it knows the routes have changed. Solution: Restart spring or whatever your are using to keep the test env loaded
You incorrectly have the web-console gem in the test environment (it should only be in the development environment) which catches any errors and produces the nice error page. If that error page has the text on it your test checks for (possible since it includes the surrounding code) then your test can pass - Solution: remove web-console from the test environment in your Gemfile.

Capybara click_link works wrong

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

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.

Inconsistent errors with Rspec, Capybara and phantom.js

I have a pretty basic test that sometimes works, and sometimes fails with inconsistent error messages such as:
Failure/Error: Unable to find matching line from backtrace
AbstractController::ActionNotFound:
The action 'location_states' could not be found for LocationController
Or:
Failure/Error: select 'Nationwide', from: 'location_type'
Capybara::ElementNotFound:
Unable to find option "Nationwide"
Or:
Failure/Error: Unable to find matching line from backtrace
RuntimeError:
Circular dependency detected while autoloading constant LocationOptions
The AJAX callback that calls location_states to initialize the location_type dropdown is in an Angular scope, so I'm wondering if that's why there's this inconsistent behavior. I tried increasing Capybara.default_wait_time to 10, but that didn't seem to change anything.
The specific line that seems to be causing all of this:
select 'Nationwide', from: 'location_type'
since Capybara's select ultimately relies on find, I thought I wouldn't run into synchronization issues, but I guess I'm missing something here.
I'm using the phantom.js driver through poltergeist.
I'm having a similar problem using rspec, capybara, and poltergeist. Capybara is reporting that it cannot find an element that is clearly on the page. I use save_and_open_page and verify that it is there. Of course, when I put a "sleep 5" statement before my "page.find(:css, '#element_id')", well then the test passes.

Sporadically succeeding cucumber tests

I have a cucumber step that involves the following:
When /^I select from the Open table project with details "([^"]*)"$/ do |details|
find('.details', :text => details).click
end
It fails with the following error message Unable to find css ".details" (Capybara::ElementNotFound)
This step fails about 90% of the time I run it, but occasionally it works. I inspect the page source, and the page does indeed have a css class .details with text that corresponds to details.
Is this some kind of timing issue or issue with cucumber? Or is it more likely that, now that Cucumber has driven me bat-poop insane, I'm not seeing things correctly?
Based on this post: Why does it seem like the Capybara "wait for page to load" timer works for matchers but not finders?
It seems that the find method does not wait for the page to be loaded before doing it's thing. Which means you have a race condition, and cucumber is losing about 90% of the time.
You can warp it in a wait_until block to specify your own timeout and pass the test
page.wait_until(5) { find('.details', :text => details) }
find('.details', :text => details).click

Resources