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.
Related
I am used to PHPUnit, so I found RSpec to be inferior when it comes to showing what has gone wrong, where and why.
For example, in PHPUnit, I can get the stack trace when an exception is raised (and even with -b option in RSpec, all I can get is the stack trace of RSpec exceptions, and not Rails's)
Also, when some error occurs, it shows you the ACTUAL value and the EXPECTED value.
Those two features I'd like to achieve in RSpec. Getting a detailed error message that includes the stack trace, in case of an Exception of Ruby or of Rails, and to know what was the actual value.
Any ideas of how to accomplish this?
If you run
rspec --help
you will see all the options you can pass (or configure via RSpec.configure) to the runner. One of the will force RSpec to show the entire backtrace
-b, --backtrace Enable full backtrace.
You can also configure the excluded/included lines to control how deep you want the backtrace to go.
As for the actuals vs expected value, this is supported by default in RSpec. See for example
For custom-defined objects, it also print out a diff.
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.
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.
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
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.