While using cucumber for BDD, i have found a very strange scenario where my "I should see" method (default implementation is failling).
Here is my scenario definition:
When I go to signup page
And I fill in "Username" with "ben#test.com"
And I press "Sign up"
Then I should see "Anything that i type here. ABC XYZ"
Obviously, the text "Anything that i type here. ABC XYZ" is not on the page but the cucumber wouldnt fail the scenario. Here is the definition of "I should see"
Then /^(?:|I )should see "([^"]*)"$/ do |text|
if page.respond_to? :should
page.should have_content(text)
else
assert page.has_content?(text)
end
end
A bit more digging, and it seems that the problem is that 1.8.7 is not supported in capybara. Instead of complaining loudly, it simply performs badly. Things like filling in forms work etc but the has_content fails miserably. Maybe it would be better if it shouted loudly that it needed 1.9.x.
Anyway I changed my Gemfile to
gem "capybara", "1.1.4", :group => :test
and it all seems to be working again.
Should I log this as an issue against capybara? The idea would be to just scream that it wont work with 1.8.7.
More on this discussion: https://groups.google.com/forum/?fromgroups=#!topic/cukes/B3UbbyG5k6s
Related
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.
UPDATE 2 - adding before(:each) block
before(:each) do
...
post_via_redirect(
sub_domain(
path: login_view_path(
#p
),
subdomain: #account.subdomain
),
first_name: "Capybara",
last_name: "RSpec"
)
expect(response).to render_template(:show)
end
UPDATE
response.body has the data I'm looking for
but page.html only has a doctype.
ORIGINAL
I'm trying to do some integration testing. I have this:
require "spec_helper"
feature "Tracking without Javascript" do
...
scenario "when navigating to a content" do
...
# this passes so I know there is a body
expect(response.body).to include(c.name)
find(:xpath, "/html") # see if xpath works...
end
end
and I get the error:
Failure/Error: find(:xpath, "/html")
Capybara::ElementNotFound:
Unable to find xpath "/html"
any ideas?
post_via_redirect doesn't involve Capybara - that directly (more-or-less) interacts with Rails, but not through a browser. That would be why Capybara never points an actual page.
Original (misguided) answer for posterity:
If you are using the newest versions of everything, then Capybara will not find invisible elements by default. Could you try find(:xpath, "/html", visible: false) and see if that works? The other thing I can think of is that your XPath may not be matching as you expect. Try //html instead.
On the meta level, you'll almost never see this kind of assertion, as the end-user doesn't care if you have an html element or not. You will get more useful tests by checking for things that the user can see. I also prefer to use CSS selectors, as other things (JavaScript and CSS) tend to care about them as well. Our whole test suite has maybe one or two XPath selectors for very ugly cases.
I've just started using cucumber to test my Rails apps. I've been very successful blindly following the many good examples.
Given /^I visit (.*) web page$/ do |page|
visit page
page.should have_text("some text")
end
Obviously, the call to visit populates the page object. And I have surmised that multiple calls to visit, or click_link, will re-fill the page object. But I'd like a better idea of where and when the page object is instantiated and its scope. Is it global or do I have to set #page= page after I call visit?
I've looked through the capybara source too and really don't have a good feel for the page object. Where can I find good documentation?
Edit: Even more confusion
It appears that I should be using have_content instead of have_text. My confusion today is that:
page.should have_content("this text does not exist on the page")
always passes. I don't understand why this does not fail?
My issue has been solved. Capybara fails silently if you are using ruby 1.8.7 (which is what I am using on my mac)
https://groups.google.com/forum/?fromgroups#!topic/cukes/B3UbbyG5k6s
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'm starting to explore BDD and Cucumber.
So I want to check if my page displays the content of 2 articles I have.
This is the step I'm using the check if the content is there:
Then /^I should see "([^"]*)"$/ do |desc|
page.should have_content desc
expected = Article.find_by_description(desc)
page.should have_content(expected.navision_code)
page.should have_content(expected.category.name)
end
Normally this should do the trick I guess but when I run the test I got this error message:
expected there to be content "---\n- tenetur\n" in "Alfa Paints Order System\n\n\n\nAlfa Paints\n\n\n\nSeth abernathy, admin\n\n\nVerander paswoord\n\nLogout\n\n\n\n\n\n\n\n\n\n\n\nAlfa Paints\nordering system\n\n\n\n\n\nOverzicht van alle artikelen\n\n\n\nBack\n\n\n\n\n\n\nProduct ID\nBeschrijving\nCategorie\n3001\nPaint\n---\n- tenetur\n\n3002\nBrush\n---\n- tenetur\n\n\n\n\n\n\n\n\n\n\n
(RSpec::Expectations::ExpectationNotMetError)
./features/step_definitions/admin_articles_steps.rb:41:in `/^I should see "([^"]*)"$/'
features/admin_articles.feature:10:in `Then I should see "Paint"'
As you can see I expect paint and the error message shows the content has paint inside.
But somehow cucumber isn't recognizing it.
I'm new to cucumber and I'm probably missing something but maybe somebody could help me on my way.
You are testing for three things at once, so it is difficult to tell which of the expectations is failing. As a first step, try commenting out everything but the first expectation just to make sure its failing where you think.
Then /^I should see "([^"]*)"$/ do |desc|
page.should have_content desc
// expected = Article.find_by_description(desc)
// page.should have_content(expected.navision_code)
// page.should have_content(expected.category.name)
end
If you still have the same problem, add debugger so that you can experiment and see what is going on from inside your test environment. This is a skill worth developing if you plan to do much cucumber testing.
Then /^I should see "([^"]*)"$/ do |desc|
debugger
page.should have_content desc
end
From debug console, see what the desc variable and page look like:
p desc
p page.content