I am following the tutorials at http://www.railstutorial.org/ and everything development wise is going well so far. I run into a problem, however, when I get the starting to work on the unit tests.
For example, one of the tests is the following:
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the content 'Sample App'" do
visit '/static_pages/home'
expect(page).to have_content('Sample App')
end
.
.
.
end
end
In order to get the test to work, I have to change it to require 'test_helper' but then when I try to bundle exec rake test it gives me errors about no such describe method.
One test that I am able to get to run successfully is the following:
require 'test_helper'
class StaticPagesTest < ActionDispatch::IntegrationTest
def test_connection
get "/about"
assert_response :success, "missing about page"
assert_select 'title', "About Us"
end
end
I am just wondering if there was some change in the way the unit testing is parsed, because it seems that the syntax is quite different. Is there something I need to do differently to get the "describe" method to work, or is there just a new way of accomplishing the same task?
The first code block uses the rspec framework, while the second one uses Test::Unit framework.
Both are legitimate unit-testing frameworks, each with its own strengths, and each with its own syntax...
Both have been around for quite awhile now, so, to answer your question - no, nothing has changed...
Related
I'm using Rspec Rails with Capybara for testing and I want to use the new feature spec in RSpec Rails 3 as they read more as customer tests and acceptance tests. However, one thing I find missing from the older (Describe/It) style is nesting. When trying to nest scenarios or use background inside any scenario block, I get an undefined method error. Is there anyway I could achieve nesting with feature specs to get something like this (from Michael Hartl's Ruby On Rails Tutorial:
describe "Authentication" do
subject { page }
describe "authorization" do
let(:user) { FactoryGirl.create(:user) }
describe "for non-signed in users" do
describe "when attempting to visit a protected page" do
before { visit edit_user_path(user) }
it "should redirect_to to the signin page" do
expect(page).to have_title('Sign in')
end
describe "after signing in" do
before do
valid_signin user, no_visit: true
end
it "should render the desired protected page" do
expect(page).to have_title('Edit user')
end
Or should I be thinking in a different way about integration tests ?
As described in https://www.relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec, feature corresponds to describe and scenario corresponds to it. So, you can nest instances of feature, but you cannot nest a scenario within a scenario, just as you cannot nest an it within a it.
Nested feature with scenarios is available in Capybara version 2.2.1
In Gemfile include
gem "capybara", "~> 2.2.1"
and bundle install
As per official documentation of Capybara
feature is in fact just an alias for describe ..., :type => :feature,
background is an alias for before, scenario for it, and given/*given!*
aliases for let/*let!*, respectively.
Here is the original issue and later it was accepted and merged in version 2.2.1
I'd like to isolate specific nodes to test on.
e.g. instead of
get :show
response.should have_content(#user.name)
it would be more descriptive/correct to be able to write something like
get :show
profile = response.find_selector("div.user-profile")
profile.should have_content(#user.name)
is it possible?
UPDATE
Got a bit further with this after reading Peter's answer but still not finding elements.
in app\views\users\index.html.erb
<h1>Users</h1>
<div id="test"></div>
in spec\controllers\users_controller_spec.rb
require 'spec_helper'
describe UsersController do
render_views
it "should should have header" do
get :index
response.should have_selector("h1", content: "Users")
end
it "should show user profile" do
get :index
node = page.find_by_id("test")
p node
end
end
The first test passes, the second test gives ElementNotFound error. I'm possibly just doing something stupid as this is my first go at Rails.
Yes, it is possible. Capybara doesn't have find_selector, but it does have find and derivatives which take a locator and behave as you imply above. See http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Finders
For example, instead of:
page.should have_selector('foo', text: 'bar')
you can say:
node = page.find('foo')
node.should have_content('bar')
While following Michael Hartl's Rails tutorial, I was experimenting with some custom functions in my test section, and ran into a restriction that surprised me. Basically, global path variables (eg "root_path") only work within the "do...end" block of an "it" section within a "describe" block of the RSpec tests.
I believe the following details boil down to the question, what is special about the "it" block which enabled "root_path" to work there while not working outside of the "it" block?
(I've determined a workaround, but I'm curious whether there's a solid explanation of this behavior.)
File: spec/requests/static_pages_spec.rb
This fails:
require 'spec_helper'
def check_stable(path)
it "should be stable" do
get path
response.status.should be(200)
end
end
describe "StaticPages" do
describe "Home => GET" do
check_stable(root_path)
end
end
This succeeds:
require 'spec_helper'
describe "StaticPages" do
describe "Home => GET" do
it "should be stable" do
get root_path
response.status.should be(200)
end
end
end
The failure is basically:
$ bundle exec rspec spec/requests/static_pages_spec.rb
Exception encountered: #<NameError: undefined local variable or method `root_path' for #<Class:0x00000004cecd78>>
... any idea why?
I tried all of the suggestions on these two threads:
Hartl's Tutorial Section 5.3.2: Rails Routes
Rspec and named routes
None worked until I sussed out the issue above.
Yes, named routes work only within it or specify blocks. But it's easy to modify the code:
def should_be_stable(path)
get path
response.status.should be(200)
end
describe "StaticPages" do
describe "Home => GET" do
it { should_be_stable(root_path) }
end
end
You steel need to include url_helpers
it blocks (or specify blocks) are what denote actual tests. Inside a test, you will have access to the full complement of Rails and Rspec helpers; outside the test, not so much (as you have worked out).
I'm currently going through the Ruby on Rails Tutorial by Michael Hartl, and in Section 3.2.2 of the tutorial, he talks about using RSpec to test for the titles of the page. My tests (which I wrote myself, following his tutorial) kept failing the title tests (it can find the tag, but the title is always a blank string), and some searching on Google told me I needed to include the function render_views to pass the tests. My problem is that no matter what I try, RSpec returns a NoMethodError for render_views. The things I've tried:
config.render_views in spec_helper.rb
describe "Static Pages" do
render_views
...
end in the spec file
describe "Static Pages" do
RSpec::Rails::ViewRendering.render_views
...
end in the spec file
All of them return a NoMethodError.
I'm not following his Gemfile exactly, so the versions of Ruby and the relevant gems are:
Ruby: 1.9.3-p125
rails: 3.2.9
rspec: 2.12.0
rspec-rails: 2.12.0
capycabra: 2.0.1
I'm working in RubyMine 4.5.4, on Windows 7. Running the test in a command prompt returns the same errors however. The spec file is static_pages_spec.rb and is located in spec/requests
The code in my static_pages_spec.rb:
require_relative '../spec_helper'
describe "Static Pages" do
#RSpec::Rails::ViewRendering.render_views, returns NoMethodError
#render_views, returns NameError
describe "Home Page" do
it "should have the h1 'Sample App'" do
visit '/static_pages/home'
page.should have_selector('h1', :text => "Sample App")
end
it "should have the title 'Home'" do
visit '/static_pages/home'
page.should have_selector('title', :text => "Ruby on Rails Tutorial Sample App | Home")
end
end
describe "Help Page" do
it "should have the h1 'Help'" do
visit '/static_pages/help'
page.should have_selector('h1', :text => "Help")
end
it "should have the title 'Help'" do
visit '/static_pages/help'
page.should have_selector('title', :text => "Ruby on Rails Tutorial Sample App | Help")
end
end
describe "About Page" do
it "should have the h1 'About Us'" do
visit '/static_pages/about'
page.should have_selector('h1', :text => "About Us")
end
it "should have the title 'About Us'" do
visit '/static_pages/about'
page.should have_selector('title', :text => "Ruby on Rails Tutorial Sample App | About Us")
end
end
end
My spec_helper.rb is the spec_helper.rb automatically generated by creating running rails generate integration_test after creating the project with --no-test-framework, with these lines added in the config block:
# Fix NoMethodError for method 'visit'
config.include Capybara::DSL
config.include Capybara::RSpecMatchers
EDIT
After some testing, I've managed to get the tests to pass by changing the capybara version to 1.1.2, while still using rspec 2.12.0 and rspec-rails 2.12.0 and not using render_views. While I'm glad the tests are passing, it still doesn't solve the problem of the missing render_views method, which still crops up if I try to use it.
Well, after a bit more testing, the mystery of the missing render_views method is solved. To include the render views method, apparently config.include RSpec::Rails::ViewRendering in the spec_helper is needed before calling config.render_views in the spec_helper or render_views in the spec file.
Secondly, with regards to the tests passing or failing, the problem seems to be in Capybara itself. Apparently, it seems that the way the visit method is implemented in 1.1.2 and 2.0.1 is significantly different in what it returns; even after including render_views, the test still fails (without using config.include Capybara::RSpecMatchers). Using it seems to provide an insight into its implementation though; the failure message from Capybara on using the RSpecMatchers is that it is looking for CSS instead of HTML. I don't claim to fully understand why it fails, however, so if anyone can enlighten me as to why Capybara 2.0.1 causes the tests to fail while 1.1.2 allows the tests to pass, that would be great.
Capybara 2.0 requires all tests to be in spec/features, and not in spec/requests.
You can read all about it here.
I would suggest that you stick to the versions mentioned in Hartl's tutorial, atleast in your beginner days. Will help you get through the tutorial faster!
I am trying to test my rails app with rspec 2.10.0 + capybara 1.1.2. Here is my test file
require 'spec_helper'
describe AdminPanelController do
describe "index" do
it "should have return code 200" do
visit '/admin'
page.should have_content "hello"
#response.status.should be(200)
end
end
end
And here are test result
Failure/Error: page.should have_content "hello"
Capybara::ElementNotFound:
Unable to find xpath "/html"
I google about this issue but find only information that webrat can be a problem however i do not have this gem installed. Thanks for any suggestions.
Wrong type of test. This looks like a controller test, which does tests with methods like get and post and is in the spec/controllers folder. Request specs, which use capybara, reside in spec/requests. Run $ rails generate scaffold SomeModel to see how they each should look.
If you understood the above but would still like to use capybara for your controller test, modify your describe block:
describe AdminPanelController, :type => :request do
...
end