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
Related
I am experiencing strange very test behavior, with logged in state being handled inconsistently.
The spec logs a user in, visits a (nested or un-nested) index page, and checks that the correct content is displayed. Records are fetched asynchronously, though I don't think this should have an impact.
When each spec is run individually, they each pass. When all specs are run together, they fail because the expected content is missing. Using save_and_open_page reveals this is because the login page is being rendered, rather than the expected index page.
Why does rspec think the user is not signed in when all specs are run together, yet each spec passes individually?
The tests look something like this
let(:user) {create :user}
let(:team) {create :team}
let(:country) {create :country}
before :each do
login_as( user, scope: :user )
end
describe 'unnested' do
it 'should have the expected content', :js do
visit users_path
is_expected.to have_content "some content on the page"
end
end
describe 'nested by team' do
it 'should have the expected content', :js do
visit team_users_path(team)
is_expected.to have_content "some content on the page"
end
end
describe 'nested by nationality' do
it 'should have the expected content', :js do
visit country_users_path(country)
is_expected.to have_content "some content on the page"
end
end
The specs all require javascript (I don't know whether that is important here).
Authentication is handled by Devise, and my rails_helper.rb includes
config.append_after(:each) do
DatabaseCleaner.clean
Warden.test_reset!
end
Why does rspec think the user is not signed in when all specs are run together, yet each spec passes individually?
It took a long time to get to the bottom of this. Posting this hear in case it is of help to anyone else encountering the same issue.
After much searching I eventually found this small mention that login_as may not work with Poltergeist when js is enabled on your test scenarios.
I tried the suggested fix to deal with shared DB connections. Unfortunately this resulted in the following errors:
PG::DuplicatePstatement at /session/users/signin
ERROR: prepared statement "a1" already exists
I tried using the Transactional Capybara gem, but this did not seem to work well with Poltergeist.
Eventually I abandonned login_as completely, and instead wrote a short method that visits the login page, fills in email and password, and logs in that way.
This solution appears to be working. It adds a little overhead, so I'm only using it for tests with JS.
If you are using Capybara gem then there is no need to use :js with test cases
What I did if this helps-
scenario "visit with user signed in" do
user = FactoryGirl.create(:user)
login_as(user, :scope => :user)
visit "/"
expect(current_path).to eq('/')
expect(page).to have_title "Some Random Title"
end
The other way you can login user using feature specs like-
feature 'User signs in' do
before :each do
#user = FactoryGirl.create(:user)
end
scenario "Signing in with correct credentials" do
visit "/"
fill_in "Email", with: #user.email
fill_in "Password", with: #user.password
click_button "Log In"
expect(current_path).to eq("/login/useremail/verification")
expect(page).to have_content "Signed in successfully"
end
end
If your pages are ajax then refer to this https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara
Where may I find guides on how to write a Rails rspec test that utilizes the ajaxful_rating gem. The test I'm writing is something like the one below.
https://github.com/edgarjs/ajaxful-rating
require "rails_helper"
RSpec.feature "Users can create new review" do
scenario "with valid attributes" do
# Put in a 5 star rating here.
fill_in "Review", with: "This place is pretty good."
click_button "Create Review"
expect(page).to have_content "Review has been created."
end
end
This could be a very broad answer however if you want to learn how you can write test case in rspec, this documentation can be helpful to understand the concept of what is test case and how you can make.
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...
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