Capybara and page.body - capybara

I've got Capybara installed on Rails but, if I drop into the debugger in my steps.rb file, and check out the contents of page.body it's always empty.
Completely clueless how to proceed.
Should I check if Capybara is loaded in the environment - if so, how?
Should I initialize Capybara somewhere - if so, how?

Did you visit your page? Sorry, I know it sounds silly but it's all I can think of given the above information. Can you try page.find('body') work instead?
Like this:
describe 'home page' do
before :each do
visit root_path
end
it 'should have a body' do
page.find('body').should_not be_nil
page.find('body').text.should_not == ''
end
.
.
.
end

Related

RSpec : Multiple scenarii for same context

How to create multiple scenarii without to have to reinit context between 2 tests with RSpec ? I don't need context reinitialisation (that is very slow), but I need to check multiple things for the same given context. The example below works, but it's a bad example : the context is reinitialized. If I do before(:all), it doesnt works because of the stubs. Any idea ?
feature 'Aids page' do
context 'No active user' do
before(:each) do
create_2_different_aids
disable_http_service
visit aids_path
end
after(:each) do
enable_http_service
end
scenario 'Should display 2 aids NOT related to any eligibility' do
display_2_aids_unrelated_to_eligibility
end
scenario 'Should not display breadcrumb' do
expect(page).not_to have_css('.c-breadcrumb')
end
end
end
feature specs often have more than one expect in the same scenario. They are not like unit tests where each it should test only one thing... they are more like what a user actually does on a page: "go here, click on this thing, check I can see that thing, click there, check that the thing changes" etc... so you can just do something like this:
feature 'Aids page' do
context 'No active user' do
scenario 'Sees aids not related to eligibility' do
create_2_different_aids
disable_http_service
visit aids_path
expect(page).not_to have_css('.c-breadcrumb')
display_2_aids_unrelated_to_eligibility
enable_http_service
end
end
end
Alternatively... it's possible to use either shared setup (as you have already done). That is fairly common.
Found. Actually there is a hack you can use to initialize your test only once, as the example shown below :
feature 'Aides page' do
context 'No active user' do
that = nil
before do
if !that
create_2_different_aids
disable_http_service
visit aides_path
that = Nokogiri::HTML(page.html)
end
end
after do
enable_http_service
end
scenario 'Should display 2 aids NOT related to any eligibility' do
display_2_aids_unrelated_to_eligibility(that)
end
scenario 'Should not display breadcrumb' do
expect(that.css('.c-breadcrumb').size).to eq(0)
end
end
end

Capybara: is it possible to specify the Scenario name for save_and_open_page

I was wondering if it's possible to rename the default file that's created when using save_and_open_page in Capybara for the Scenario name?
I've created the following so far:
After do |scenario|
if(scenario.failed?)
save_and_open_page
end
end
Cheers!
save_and_open_page can take an optional filename parameter:
save_and_open_page('page.html')

How do I re-use Capybara sessions between tests?

I want to keep on using the same session and by that I mean Rails' session between various Test::Unit integration tests that use Capybara. The Capybara::Session object is the same in all the tests as it is re-used, but when I access another page in another test, I'm immediately logged out.
Digging in I found that capybara_session.driver.browser.manage.all_cookies is cleared between one test and the next.
Any ideas how? or why? or how to avoid it?
Trying to work-around that, I saved the cookie in a class variable and re-added later by running:
capybara_session.driver.browser.manage.add_cookie(##cookie)
and it seems to work, the cookie is there, but when there's a request, the cookie gets replaced for another one, so it had no effect.
Is there any other way of achieving this?
Add the following after your capybara code that interacts with the page:
Capybara.current_session.instance_variable_set(:#touched, false)
or
page.instance_variable_set(:#touched, false)
If that doesn't work, these might help:
https://github.com/railsware/rack_session_access
http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/
If what you are doing is trying to string together individual examples into a story (cucumber style, but without cucumber), you can use a gem called rspec-steps to accomplish this. For example, normally this won't work:
describe "logging in" do
it "when I visit the sign-in page" do
visit "/login"
end
it "and I fill in my registration info and click submit" do
fill_in :username, :with => 'Foo'
fill_in :password, :with => 'foobar'
click_on "Submit"
end
it "should show a successful login" do
page.should have_content("Successfully logged in")
end
end
Because rspec rolls back all of its instance variables, sessions, cookies, etc.
If you install rspec-steps (note: currently not compatible with rspec newer than 2.9), you can replace 'describe' with 'steps' and Rspec and capybara will preserve state between the examples, allowing you to build a longer story, e.g.:
steps "logging in" do
it "when I visit the sign-in page" #... etc.
it "and I fill in" # ... etc.
it "should show a successful" # ... etc.
end
You can prevent the call to #browser.manage.delete_all_cookies that happens between tests by monkey patching the Capybara::Selenium::Driver#reset! method. It's not a clean way of doing it, but it should work...
Add the following code to your project so that it is executed after you require 'capybara':
class Capybara::Selenium::Driver < Capybara::Driver::Base
def reset!
# Use instance variable directly so we avoid starting the browser just to reset the session
if #browser
begin
##browser.manage.delete_all_cookies <= cookie deletion is commented out!
rescue Selenium::WebDriver::Error::UnhandledError => e
# delete_all_cookies fails when we've previously gone
# to about:blank, so we rescue this error and do nothing
# instead.
end
#browser.navigate.to('about:blank')
end
end
end
For interest's sake, the offending line can be seen in Capybara's codebase here: https://github.com/jnicklas/capybara/blob/master/lib/capybara/selenium/driver.rb#L71
It may be worth posting the reason why you need this kind of behaviour. Usually, having the need to monkey patch Capybara, is an indication that you are attempting to use it for something it was not intended for. It is often possible to restructure the tests, so that you don't need the cookies persisted across integration tests.

Where do you put your paths in Cucumber 1.1+ for Ruby on Rails?

Since the paths.env file is not generated for Cucumber 1.1+, if for example if I use the visit login_path frequently for my test steps, should I create an individual step for it or should I just use visit login_path everywhere? If it ever changes, I can easily do a string replace under the features directory.
Thanks!
If it's really just a matter of DRYing up your calls to visit login_path I'd just leave them be since they are clear and concise as they stand, and you (probably) ain't gonna need to change the login path helper.
However if you start seeing slightly more complicated steps like this,
# in features/step_definitions/profile_steps.rb
When /^I go to my profile$/ do
visit user_path(#current_user)
end
consider using the paths.rb model:
# in features/step_definitions/common_steps.rb
Given /^I go to (.+)$/ do |page_name|
visit path_to(page_name)
end
# in features/support/paths.rb
module NavigationHelpers
def path_to(page_name)
when /my profile/
user_path(#current_user)
...
end
end
World(NavigationHelpers)
That's right, I like paths.rb and selectors.rb and copy them to new projects :) I am glad to see the "kitchen sink" web_steps.rb go though. For examples of how I use the support files: https://github.com/coshx/green-eggs/blob/master/features/support

Problems matching class with Capybara/RSpec

I'm trying to match a class attribute using Capybara with RSpec.
I can very clearly see the elements and their classes but no matter what I try, Capybara seems to know nothing about the classes. But it can find id's no problem. Any clues, please? https://gist.github.com/1428472
visit "/admin/staff?mobile=1"
page.should have_selector("ul") #works
page.should have_selector("body#page") #works
page.should have_selector("html.ui-mobile") #fails
page.should have_selector("body.ui-mobile-viewport") #fails
save_and_open_page # this launches the page so I can see it and verify these attributes are indeed there.
The html:
< html class="ui-mobile" >
< body class="ui-mobile-viewport" id="page" >
I also set a breakpoint and did this stuff which also didn't work right.
#works
p find('body')[:id]
p find(:xpath, '//body[#id="page"]')
# doesn't work
p find('body')[:class]
p find(:xpath, '//html[#class="ui-mobile"]')
What's going on?
UPDATE: It turns out that it does actually work, however the problem here is that the html displayed by save_and_open_page differs from what capybara sees. When I break right after save_and_open_page and puts page.html, it's different. It's generally the same but a bunch of class attributes are gone as well as some other stuff. Very odd.

Resources