nested feature in capybara 2.0+ - ruby-on-rails-3

i want to do something like this:
feature "sign-up" do
before {visit signup_path}
let(:submit) {"Create my account"}
feature "with invalid information" do
scenario "should not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
feature "with valid information" do
scenario "should create a user" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
expect {click_button submit}.to change(User, :count).by(1)
end
end
end
but when i run rspec i get
in `block in <top (required)>': undefined method `feature' for #<Class:0x000000039e0018> (NoMethodError)
if i change it a bit to look like this it works:
feature "with invalid information" do
before {visit signup_path}
let(:submit) {"Create my account"}
scenario "should not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
feature "with valid information" do
before {visit signup_path}
let(:submit) {"Create my account"}
scenario "should create a user" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "nirnir"
fill_in "Confirmation", with: "nirnir"
expect {click_button submit}.to change(User, :count).by(1)
end
end
EDIT:
plus, the following code works(describe nested inside feature) - but is it wrong in any way?
feature "sign-up" do
background {visit signup_path}
given(:submit) {"Create my account"}
scenario "with invalid information" do
expect {click_button submit}.not_to change(User, :count)
end
describe "with valid information" do
background do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
end
scenario { expect {click_button submit}.to change(User, :count).by(1) }
scenario "after submission" do
click_button submit
page.html.should have_content("Registration successful")
end
end
end

EDIT (23/01/2014): Nested features are available since version 2.2.1. See here
EDIT (24/07/2013): Nested features will be allowed in Capybara > 2.1.0. See here
You can't. This is what the mantainer of the gem says about it
I guess you could call this a limitation. feature can not be nested.
You can use either context or describe instead, but I would
suggest not going wild with these, it tends to make tests pretty
unreadable.
In some other cases the convenience of this might be argued but in this specific one you should use scenario instead of the nested feature.
Also if you want to consistent and use the new DSL everywhere, use background instead of before and given instead of let. Like this:
feature "sign-up" do
background {visit signup_path}
given(:submit) {"Create my account"}
scenario "with invalid information" do
expect {click_button submit}.not_to change(User, :count)
end
scenario "with valid information" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
expect {click_button submit}.to change(User, :count).by(1)
end
end
You have to remove the it because scenario is just an alias for it and you cannot nest it either.
Or you can always switch back to the old DSL if you find it more readable. In that case I would do something like this:
describe "sign-up" do
before {visit signup_path}
let(:submit) {"Create my account"}
context "with invalid information" do
it "does not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
context "with valid information" do
before
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
end
it "creates a user" do
expect {click_button submit}.to change(User, :count).by(1)
end
end
end
But as long as the spec checks what it has to check, you should be fine anyways. The rest is all a matter of style, readability and good practices, which are important but more open to discussion and disagrement. In this case the author of the gem didn't allow nested feature's. Maybe for readability or maybe didn't feel it was needed or maybe didn't think about it... If you really want to nest features you can always try to implement it and pull request it.

Related

Test lengthy form without re-writing all the fill_ins everytime

I have a long form, and for 3 of the fields, I need to test whether those were filled out right or wrong individually, because errors lead to very different actions. But it's very tedious and not DRY to write integration tests like this:
# Test 1
describe "test where field3 fails" do
before do
fill_in "field1", with: "passing info"
fill_in "field2", with: "passing info"
fill_in "field3", with: "not passing info"
...
end
it "should lead to an error specific to field3" do
...
end
end
# Test 2
describe "test where field2 fails" do
before do
fill_in "field1", with: "passing info"
fill_in "field2", with: "not passing info"
fill_in "field3", with: "passing info"
...
end
it "should lead to an error specific to field2" do
...
end
end
# Test 3
describe "test where field1 fails" do
before do
fill_in "field1", with: "not passing info"
fill_in "field2", with: "passing info"
fill_in "field3", with: "passing info"
...
end
it "should lead to an error specific to field1" do
...
end
end
In that case ,I would suggest to write data driven tests like below
describe "test all form fields" do |data|
before do
fill_in "field1", with: data[0]
fill_in "field2", with: data[1]
fill_in "field3", with: data[2]
...
end
it "should lead to an error message" do |CorrespondingErrorMsg|
...
end
This way all the combinations will be defined inside test data ,not in the code so in future if no. of validations even increase or decrease you don't have to touch the code.Only the data.
I hope it makes sense to make the solution dry.

RSpec: how to write tests with accents?

I'm new in cucumber and rspec, and I'm trying to test a button whose text is "Regístrate" (look at the accent "í").
In my app, I have a lot of controls written in spanish, with accents á é í ó ú. But I get an error because of these vowels with accents. I'm sure there is an easy solution but I don't achieve to find a solution.
I could change the tests descriptions, but not the words in the user application... any suggestion?
describe "signup" do
before { visit signup_path }
let(:submit) { "Regístrate" }
describe "con información válida" do
it "no debería crear el usuario" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "con información válida" do
before do
fill_in "Nombre", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmación", with: "foobar"
end
it "debería crear el usuario" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
error:
user_signup_steps.rb:3: syntax error, unexpected $end, expecting keyword_end
"Regístrate"
^ (SyntaxError)
Looks like an encoding error. Try adding this line to the top of the spec file:
# encoding: utf-8

Hartl Rails Tutorial (3.2) 8.2.5 Rspec failure

UPDATE:
My test was not submitting the user info. The relavant code was in the previous chapter's exercises:
describe "after saving user" do
before { click_button submit }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Profile') }
end
/UPDATE
I've completed section 8.2.5 (Signin upon signup) and the app behaves exactly as described:
the user is signed-in upon signup
then redirected to their profile page
where the header has been changed to include a 'Sign out' link.
But my test for the 'Sign out' link fails. Here's my code, all copied from the tutorial:
relevant controller code (users_controller.rb):
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
relevant view code (_header.html.erb):
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
relevant test code (user_pages_spec.rb):
describe "signup" do
before { visit signup_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving user" do
it { should have_link('Profile') }
end
end
end
The error is rspec ./spec/requests/user_pages_spec.rb:47 # User pages signup with valid information after saving user
Thanks!
I think the last 'describe' block should look like this:
describe "after saving user" do
before { click_button submit }
it { should have_content('Profile') }
end
The test missed clicking the "submit" button before examining if there is appropriate content on a page.

undefined method `change'

I'm doing the ruby on rails tutorial, I specifically adding listing 8.21 to spec/requests/users_spec.rb
require 'spec_helper'
describe "Users" do
describe "signup" do
describe "signup failure" do
lambda do
it "should not make a new user" do
visit signup_path
fill_in "Name", :with => ""
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Password confirmation", :with => ""
click_button
response.should render_template('users/new')
response.should have_selector("div#error_explanation")
end
end.should_not change(User, :count)
end
end
end
as far as I can tell, this is exactly like the listing in 8.21; however, when I run
rspec spec/requests/users_spec.rb -e "Users"
I got the following error ...
#> rspec spec/requests/users_spec.rb -e "Users" No DRb server is running. Running in local process instead ... /Users/bryanjamieson/rails_projects/sample_app/spec/requests/users_spec.rb:17:in `block (3 levels) in ': undefined method `change' for
# (NoMethodError)
any help would be appreciated.
I'd use User.count
end.should_not change(User.count)
Depending on which rails version and rspec version you're using (assuming Rails 3.1, Rspec2) the tutorial may be a little of out date

Rails Capybara Problems

I am trying to get tests working after switching from Webrat to Capybara. When I try to sign in to the application I am getting a "Invalid username/password" error, despite just having created the user in a Factory using factory_girl. The way I understand it, the user should persist for the entirety of the fixture, right?
factories.rb:
Factory.define :user do |user|
user.firstname "Test"
user.lastname "Test"
user.email "test#test.com"
user.password "testtest"
user.password_confirmation "testtest"
end
layout_links.spec.rb:
describe "LayoutLinks" do
before(:each) do
wrong_user = Factory(:user)
integration_sign_in(wrong_user)
end
it "should have a dashboard page" do
get '/dashboard'
page.should have_css('h1', :text => "Navigation#dashboard")
end
spec_helper.rb
def integration_sign_in(user)
visit signin_path
fill_in :email, :with => user.email
fill_in :password, :with => user.password
click_button "Sign in"
puts page.body
end
Also in spec_helper.rb is the following:
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
Shouldn't the user persist and then be successful in the integration_sign_in function? I can still sign in correctly through the browser in the development environment, which has a user and the sign in was working correctly with webrat before the migration, so I am not sure what to think. Thanks!
UPDATE: It looks like the session isn't going to the server correctly. On the server, when I check the value of email and password in the session, the values are incorrect:
puts "Post Email: " + params[:session][:email]
puts "Post Password: " + params[:session][:password]
the email variable has the password variable, and the password variable has no value. Why would this be? The client integration test maps the fields correctly:
fill_in :email, :with => user.email
fill_in :password, :with => user.password
How can I test this further? Thanks.
So this worked for me
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
whereas using the symbols failed
It looks like the session wasn't going to the server correctly. I am not sure how to account for this.