Rails Tutorial: RSpec test decoupling - ruby-on-rails

I'm trying to do Exercise 2 of Chapter 8.5 in Michael Hartl's Ruby on Rails Tutorial. The exercise is as follows:
Following the example in Section 8.3.3, go through the user and authentication request specs (i.e., the files currently in the spec/requests directory) and define utility functions in spec/support/utilities.rb to decouple the tests from the implementation. Extra credit: Organize the support code into separate files and modules, and get everything to work by including the modules properly in the spec helper file.
Example 8.3.3: utilities.rb
include ApplicationHelper
def valid_signin(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
page.should have_selector('div.alert.alert-error', text: message)
end
end
The defined valid_signin(user) function is used in the following block of authentication_pages_spec.rb and works fine.
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signin(user) }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
So with this example I set about to create my own named valid_signup(user):
def valid_signup(user)
fill_in "Name", with: user.name
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Confirmation", with: user.password_confirmation
end
I'm using this block in user_pages_spec.rb like this:
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email(user.email) }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
It doesn't work. Spork/Guard reports these errors:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: expect { click_button submit }.to change(User, :count).by(1)
count should have been changed by 1, but was changed by 0
# ./spec/requests/user_pages_spec.rb:46:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
3) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
4) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
The errors seem to suggest the user.name in my valid_signup(user) function in utilities.rb isn't defined, but I don't see any reason why. I've restarted Guard several times, and did a rake db:test:prepare to make sure the testing db (using postgresql) was in order.
Here's my factories.rb for completeness:
FactoryGirl.define do
factory :user do
name "Example User"
email "user#example.com"
password "foobar"
password_confirmation "foobar"
end
end
Before I continue to try and decouple more of the testing suite I'd very much like to solve this error and, more importantly, understand the reason for it.
EDIT
I've tried your tips, and edited the function in user_pages_spec.rb as follows:
describe "with valid information" do
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the 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('Sign out') }
end
end
Since I removed let(:user){FactoryGirl.create(:user)} from the function I guessed there was no longer a user created in the function so I needed to define valid_signup(user) as such as the user variable for valid_signup was no longer being filled by FactoryGirl:
def valid_signup(user)
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
This didn't work and gave me the following errors:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method user' for #<RSpec::Core::ExampleGroup::Nested_5::Nested_3::Nested_2:0x007fdafc5088c0>
# ./spec/requests/user_pages_spec.rb:42:inblock (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:inblock (5 levels) in '
I also tried running the test with valid_signup(user) the way I used to have it before (with user.name, user.email, user.password, user.password_confirmation, which didn't work either, with errors:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
Next I tried running it without passing variables in user_pages_spec.rb: before { valid_signup() } and without a variable in the function in utilities.rb:
def valid_signup()
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
This returned:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
Still no closer to the answer. I might be overlooking something simple. No clue what though. I got what I first did wrong though: I just thought FactoryGirl was a way to create variables, and I didn't know it actually did something to my test database.

I will try to explain what is going on in your original test (which I find easier to fix than the edited version):
describe "with valid information" do
let(:user) {FactoryGirl.build(:user)} # FactoryGirl.create will save the instance, you should be using build instead
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
# let(:user) { User.find_by_email(user.email) } # this is not needed any more
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
More info on FactoryGirl usage: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#using-factories

FactoryGirl saves the user to the database, then you visit the sign_in_path with the user already on the database and fill the form for sign_in with valid_sigin(user)
let(:user){FactoryGirl.create(:user)}
before { valid_signin(user) }
When you do:
let(:user){FactoryGirl.create(:user)}
before { valid_signup(user) }
factory girl saves the user in the database, and you fill a form with an email already taken.
EDIT:
describe "with valid information" do
before { valid_signup(user) }
You dont have a variable user defined, since you deleted let(:user){FactoryGilr.create(:user)},and you should visit the right path, your current path is "sign_in_path" and should be "sign_up_path"
You should do something like this:
utilities.rb
def valid_sign_up(user)
fill_in "Name", with: user.name
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Confirmation", with: user.password_confirmation
end
user_pages_spec.rb
describe "with valid information" do
let(:user){User.new(name: "my name", email: "myemail#example"...)
before do
visit sign_up
valid_sign_up(user)
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end

I had the same problem and figured out the solution: when you define valid_signup, it should take 'page' as the argument. After all, you are testing the page elements, not the user.
spec/support/utilities.rb
def valid_signup(page)
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
spec/requests/user_pages_spec.rb
describe "with valid information" do
before { valid_signup(page) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
I hope this helps!
UPDATE I realize now that this works because of the scope of the variable 'page' (since it's the subject). To use "user" I added the line
let(:user) { FactoryGirl.create(:user) }
above
before { sign_up(user) }. This then broke a later spec where I also tried using 'user' as a variable, so I changed the name to 'editeduser'. Here's the full example:
user_pages_spec.rb
require 'spec_helper'
describe "UserPages" do
subject { page }
...
describe "signup page" do
before { visit signup_path }
let(:submit) { "Create my account" }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
describe "after submission" do
before { click_button submit }
it { should have_selector('title', text: 'Sign up') }
it { should have_content('error') }
end
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_up(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:editeduser) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: editeduser.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
end
Hopefully this helps someone!

I was curious about this one as well, and found an answer that may be more in line with what Hartl was expecting (though as just learning, I'm not 100% certain the top answer isn't more elegant or not).
Since we weren't using FactoryGirl to sign up users, but instead to sign them in, I didn't want to use it in my refactoring. This is what I have in my utilities.rb:
def valid_signup
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
and then in user_pages_spec.rb I replaced
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
with
describe "with valid information" do
before { valid_signup }
We don't need a user to be saved to the database just to check a one time sign up, since they don't need to persist through multiple page views. Also, since we don't look up a user, we don't need a (user) argument after valid_signup method (I think I have the terminology correct. Please correct me if I do not.)

Related

Keeping user in the database between tests using Capybara?

My issue is that I have to create a new user and login for each individual capybara test.
An example is below:
require 'spec_helper'
describe "users" do
describe "user registration" do
it "should create a new user and log in" do
# Register a new user to be used during the testing process
visit signup_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
fill_in 'Password confirmation', with: 'testpass'
click_button 'Create User'
current_path.should == root_path
page.should have_content 'Thank you for signing up!'
end
end
describe "user login" do
it "should log in" do
# log in
visit login_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
click_button 'Log In'
current_path.should == root_path
page.should have_content 'Logged in!'
end
end
end
The login test fails because the user no longer exists in the database for that test.
This could be fixed simply by putting both in one test, but I believe that is bad practice.
Also I have another file which currently is registering and logging in between each test using a before_do, which also seems to be quite bad... you can see that code here.
For the record this is my first rails app so perhaps I am trying to do this the wrong way. I would like to dry it up as much as possible..
Is capybara really this bad to use on pages that require user login?
I have done it this way.
require "spec_helper"
describe "Users" do
subject { page }
describe "User Registration" do
before { visit signup_path }
let(:submit) { "Sign up" }
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 "Email", with: "user#example.com"
fill_in "Password", with: "foobar12"
fill_in "Password confirmation", with: "foobar12"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after registration" do
before { click_button submit }
it { should have_content 'Thank you for signing up!' }
end
describe "after registration signout and login" do
let(:user) { User.find_by_email('user#example.com') }
before do
click_button submit
visit signout_path
sign_in user # sign_in is a method which u can define in your spec/support/utilities.rb . Define once and use at multiple places.
end
it { should have_content 'Logged In!' }
it { should have_link('Logout') }
end
end
end
end
# spec/support/utilities.rb
def sign_in(user)
visit sign_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
your every describe and it block will run after the before block in parent that's why we need to click_button in every block in above test cases.

ruby on rails tutorial errors chapter 9

I have been working on the ruby on rails tutorial. I am totally new to this stuff. I am in chapter 9 and totally stuck. I am hoping someone might help me decipher the error messages. Up until now I have just searched them and figured it out but I think it would be more valuable to just learn how to decipher the error message to fix the problem. If it is too long or cumbersome to explain than than I totally understand if no one wants to take it on. I was unable to find something online that helped me with this on my own.
Here are the errors that I am currently getting
1) AuthenticationPages signin with valid information authorization for non-signed-in users when attempting to visit a protected page after signing in should render the desired protected page
Failure/Error: click_button "Sign in"
Capybara::ElementNotFound:
Unable to find button "Sign in"
# ./spec/requests/authentication_pages_spec.rb:61:in `block (7 levels) in <top (required)>'
2) AuthenticationPages signin with valid information authorization for non-signed-in users in the Users controller visiting the edit page
Failure/Error: it { should have_title('Sign in') }
expected #has_title?("Sign in") to return true, got false
# ./spec/requests/authentication_pages_spec.rb:76:in `block (8 levels) in <top (required)>'
3) AuthenticationPages signin with valid information authorization for non-signed-in users in the Users controller as wrong user visiting Users#edit page
Failure/Error: before { sign_in user, no_capybara: true }
NoMethodError:
undefined method `sign_in' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_2::Nested_2::Nested_2::Nested_1::Nested_2::Nested_3::Nested_1:0xabbb9e4>
# ./spec/requests/authentication_pages_spec.rb:87:in `block (8 levels) in <top (required)>'
4) AuthenticationPages signin with valid information authorization for non-signed-in users in the Users controller as wrong user submitting a PATCH request to the User#update action
Failure/Error: before { sign_in user, no_capybara: true }
NoMethodError:
undefined method `sign_in' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_2::Nested_2::Nested_2::Nested_1::Nested_2::Nested_3::Nested_2:0xa82d354>
# ./spec/requests/authentication_pages_spec.rb:87:in `block (8 levels) in <top (required)>'
Finished in 6.6 seconds
65 examples, 4 failures
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:66 #
AuthenticationPages signin with valid information authorization for
non-signed-in users when attempting to visit a protected page after
signing in should render the desired protected page
rspec ./spec/requests/authentication_pages_spec.rb:76 #
AuthenticationPages signin with valid information authorization for
non-signed-in users in the Users controller visiting the edit page
rspec ./spec/requests/authentication_pages_spec.rb:91 #
AuthenticationPages signin with valid information authorization for
non-signed-in users in the Users controller as wrong user visiting
Users#edit page
rspec ./spec/requests/authentication_pages_spec.rb:96 #
AuthenticationPages signin with valid information authorization for
non-signed-in users in the Users controller as wrong user submitting a
PATCH request to the User#update action
authentication_pages_spec.rb
require 'spec_helper'
describe "AuthenticationPages" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_content('Sign in') }
it { should have_title('Sign in') }
end
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_title('Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error', text: 'Invalid') }
end
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email.upcase
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_title(user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
describe "authorization" do
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
expect(page).to have_title('Edit user')
end
end
end
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_title('Sign in') }
end
describe "submitting to the update action" do
before { patch user_path(user) }
specify { expect(response).to redirect_to(signin_path) }
end
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user, no_capybara: true }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_title(full_title('Edit user')) }
end
describe "submitting a PATCH request to the User#update action" do
before { patch user_path(wrong_user) }
specify { expect(response).to redirect_to(root_url) }
end
end
end
end
end
end
end
end
user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
end
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
describe "after submission" do
before { click_button submit }
it { should have_title('Sign up') }
it { should have_content('error') }
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 new user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by(email: 'user#example.com') }
it { should have_title(user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "edit" do
let(:user) {FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
describe "page" do
it { should have_content("Update your profile") }
it { should have_title("Edit user") }
it { should have_link('change', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_title(new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { expect(user.reload.name).to eq new_name }
specify { expect(user.reload.email).to eq new_email }
end
end
end
end
end
end
I am particularly curious what "in 'block(7 levels)in" means. Are the levels something on that page or is it referring to something else? What is 'The block' in reference to?
I also cannot seem to understand the capybara error that I am getting. It appeared in chapter 8, went away and now has come back. The button is there on the page when I bring it up so capybara is just not finding it I guess. Can anyone explain how that works?
What does the 'nested" refer to?
Anyone know a good website that breaks this down? I would be more than happy to do the work myself but I could not find one. I would really love to be able to decipher this myself instead of just googling it and hoping the answer is somewhere or having to rely on someone else to explain it all the time.
Thanks so much for your time and any help.
Now is the time on Stack Overflow when I oversimplify. (Google 'ruby block' to read a lot more on this.) A block in Ruby is a bunch of code that gets passed to a method like an argument. For example,
[1,2,3].each{|n| puts n * n }
each is the method (called on the array [1,2,3]), and everything in the brackets is the block. The way the method each works is, it takes every element in the enumerable it`s called on ([1,2,3]) and yields one element at a time to the code block:
|the first element is 1| puts 1 * 1
|next is 2| puts 2 * 2
|etc| puts 3 * 3
A block can also be written between do...end. The Ruby way is to use brackets if you can fit the block on one line, and do...end otherwise - which is just how you have it in your specs. Everywhere you have a do and a matching end in your specs is a block, nested one inside another. The methods are harder to notice, because RSpec makes it look like natural language, but every time you write describe or it at the start of a line is a method call. (So are let and before and subject and expect, for that matter, which get called with single line blocks in your specs.)
So the message 'block(7 levels)' means your error is nested in that many blocks:
describe "AuthenticationPages" do #starts the first block
...
describe "signup" do #starts the second
and so on.
Now, your error messages. The first and second are basically telling you the same thing - you visit edit_user_path(user) and you don't see a "Sign In" button or "Sign In" in the page title. Check the log/test.log file - what happens when you visit that page? Is it a redirect to the signin page? It ought to be, but it looks like it isn't.
The other two error messages say exactly the same thing - the spec doesn't know what sign_in means. You need to have a method by that name defined somewhere RSpec can find it - either in the spec itself, or the spec_helper file that you require at the top of the spec, or in some file which is itself required inside spec_helper.
Finally, I think Hartl is right - you Google as best you can with error messages and stack traces, ask when you can't find what you're looking for, and you'll get better figuring things out yourself with time.
Re: sign_in -- The sign_in function was added to spec/support/utilities.rb in section 9.1.1, Listing 9.6 (in Rails 4 version of book).
I got the same error because my function in utilities.rb was "signin" without the underscore. Once I added the underscore (and changed the other reference to the same function to match), the test went green.

Ruby on Rails Tutorial by Michael Hartl. Failing test in Chapter 8.29

I am a newbie working through Hartl. Got to the end of Chapter 8 and when I check my browser for the sign in/sign out every things seems AOK. However when I run this test:
$ bundle exec spec spec/
returns
sis-macbook-pro:sample_app Lagaspi$ bundle exec rspec spec/
..............................F
Failures:
1) User pages signup with valid information after saving the user
Failure/Error: it { should have_link('Sign out') }
expected link "Sign out" to return something
# ./spec/requests/user_pages_spec.rb:48:in `block (5 levels) in <top (required)>'
Finished in 0.60715 seconds
31 examples, 1 failure
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:48 # User pages signup with valid information after saving the user
I have an idea but i'm not exactly sure. So here's my user_pages_spec.rb file:
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
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 the user" do
before { click_button submit }
it { should have_link('Sign out') }
end
end
end
end
Go to http://ruby.railstutorial.org/chapters/sign-up?version=3.2#code-after_save_tests, and add those lines into you spec.
could you post your view file? Without it, it's difficult to tell what's wrong. From what I'm seeing, it only says you don't have the link.

Ruby on Rails Tutorial by Michael Hartl Chapter 7.25

Hi i'm a newbie working through Hartl. After a recent disaster I've been able to restore my app to a near working state (thanks Github!). I am now down to one error in my tests. So when I run the test I get:
sis-macbook-pro:sample_app Lagaspi$ bundle exec rspec spec/
..............................F
Failures:
1) User pages signup with valid information after saving the user
Failure/Error: it { should have_link('Sign out') }
expected link "Sign out" to return something
# ./spec/requests/user_pages_spec.rb:48:in `block (5 levels) in <top (required)>'
Finished in 0.61988 seconds
31 examples, 1 failure
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:48 # User pages signup with valid information after saving the user
Here's my user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
describe "signup" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
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 the user" do
before { click_button submit }
it { should have_link('Sign out') }
end
end
end
end
Thanks in advance.
Please check your 'Sign out' link , probably something goes wrong there.

Chapter 7 Ruby on Rails users_controller.rb error

I followed all the instructions in chapter 7 Ruby on Rails tutorial, when I finally run $ Bundle exec rspec spec/ a series of errors are being displayed. I doubled checked if my codes had any spelling mistakes or any symbols left out. Everything seems to fine. Could you please kindly interpret the errors and tell me where I am going wrong??? Thanks
USER_PAGES_SPEC.RB
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before {visit signup_path}
it { should have_selector('h1', text: 'Sign ') }
it { should have_selector('title', text: full_title('Sign up')) }
end
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
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 a user" do
before {click_button submit}
let (:user) {user.find_by_email("user#example.com")}
it {should have_selector('title', text:user.name)}
end
end
end
end
USER_CONTROLLER.RB
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
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
end
ERRORS DISPLAYED ON COMMAND LINE
3) User pages signup page
←[31mFailure/Error:←[0m ←[31mit { should have_selector('title', text: full_
title('Sign up')) }←[0m
←[31mNoMethodError:←[0m
←[31mundefined method full_title' for #<RSpec::Core::ExampleGroup::Neste
d_2::Nested_1:0x461b260>←[0m
←[36m # ./spec/requests/user_pages_spec.rb:11:inblock (3 levels) in '←[0m
4) User pages profile page
←[31mFailure/Error:←[0m ←[31mit { should have_selector('title', text: user.
name) }←[0m
←[31mexpected css "title" with text "Michael Hartl" to return something←[
0m
←[36m # ./spec/requests/user_pages_spec.rb:19:in `block (3 levels) in '←[0m
5) User pages signup with valid information should create a user
←[31mFailure/Error:←[0m ←[31mexpect { click_button submit }.to change(User,
:count).by(1)←[0m
←[31mNoMethodError:←[0m
←[31mundefined method sign_in' for #<UsersController:0x45a8f00>←[0m
←[36m # ./app/controllers/users_controller.rb:14:increate'←[0m
←[36m # (eval):2:in click_button'←[0m
←[36m # ./spec/requests/user_pages_spec.rb:43:inblock (5 levels) in '←[0m
←[36m # ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '←[0m
6) User pages signup with valid information after saving a user
←[31mFailure/Error:←[0m ←[31mbefore {click_button submit}←[0m
←[31mNoMethodError:←[0m
←[31mundefined method sign_in' for #<UsersController:0x46341c0>←[0m
←[36m # ./app/controllers/users_controller.rb:14:increate'←[0m
←[36m # (eval):2:in click_button'←[0m
←[36m # ./spec/requests/user_pages_spec.rb:47:inblock (5 levels) in '←[0m
1) undefined method full_title
Are you defined it?
2) expected css "title" with text "Michael Hartl" to return something
You haven't <title>Michael Hartl</title> in output html.
3, 4) undefined method sign_in
Where are you defined it?
Correct your code and all tests will be passed.

Resources