Rspec Test Won't Pass using assigns() - ruby-on-rails

Here is my current users_controller_spec.rb file
require 'spec_helper'
describe UsersController do
render_views
.
.
.
describe "success" do
before(:each) do
#attr = { :name => "New User", :email => "user#example.com",
:password => "foobar", :password_confirmation => "foobar" }
end
it "should create a user" do
lambda do
post :create, :user => #attr
end.should change(User, :count).by(1)
end
it "should redirect to the user show page" do
post :create, :user => #attr
response.should redirect_to(user_path(assigns(:user)))
end
end
end
end
When I run this I get the following:
Failures:
1) UsersController POST 'create' success should redirect to the user show page
Failure/Error: response.should redirect_to(user_path(user))
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"users"}
# ./spec/controllers/users_controller_spec.rb:95:in `block (4 levels) in <top (required)>'
Which leads me to believe that :user isn't an actual object. How can I test this and how can I change :user into an object that user_path understands.
Thanks in advance for any help.
UPDATED:
def create
#title = "Sign up"
#user = User.new(params[:user])
if #user.save
redirect_to #user, :notice => "Signed Up!"
else
#title = "Sign up"
render "new"
end
end
When I run the following:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
user.should_not be_blank
puts "user errors are: #{user.errors.full_messages.inspect}" unless user.is_valid?
user.should be_valid
response.should redirect_to(user_path(user))
end
I get:
1) UsersController POST 'create' success should redirect to the user show page
Failure/Error: user.should_not be_blank
expected blank? to return false, got true
# ./spec/controllers/users_controller_spec.rb:94:in `block (4 levels) in <top (required)>'

Try using assigns with brackets instead of parenthesis.
assigns[:user]
(RSpec docs)
EDIT
One pattern I always use when testing controller actions is to ensure that a variable required by the associated view(s) is assigned. For example,
it "should assign an #user variable" do
post :create, :user => #attr
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end

You've got a typo
response.should redirect_to(user_path(:user))
should be
response.should redirect_to(user_path(user))
Edit:
Try checking that the user is valid with:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
user.should_not be_blank
puts "user errors are: #{user.errors.full_messages.inspect}" unless user.is_valid?
user.should be_valid
response.should redirect_to(user_path(user))
end
I know it works on the previous test case... but still worth checking extensively at least once here. You can remove all that guff when you're certain.

In your test:
it "should redirect to the user show page" do
#user = Factory(:user)
post :create, :user => #attr
user = assigns(:user)
response.should redirect_to(user_path(#user))
end
Your #attr hash is different from #user. You are creating user with attributes of #attr, and asserting that it should redirect to #user show (which is different from one created). Change to:
it "should redirect to the user show page" do
post :create, :user => #attr
user = assigns(:user)
response.should redirect_to(user_path(user))
end

Related

Can't get my rspec test to pass

I have a test I'm trying to pass but I can't get it to pass, I am new to this.
Here's a link to my git repository https://github.com/FrankWiebe/nameofapp
The failure message comes up like so:
1) UsersController GET #show No user is logged in redirects to login
Failure/Error: expect(response).to redirect_to(root_path)
Expected response to be a <redirect>, but was <200>
# ./spec/controllers/users_controller_spec.rb:24:in `block (4 levels) in <top (required)>'
This is the code:
require 'rails_helper'
describe UsersController, :type => :controller do
before do
#user = User.create(email: "doe#example.com", password: "1234567890")
end
describe "GET #show" do
context "User is logged in" do
before do
sign_in #user
end
it "loads correct user details" do
get :show, id: #user.id
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #user
end
end
context "No user is logged in" do
it "redirects to login" do
get :show, id: #user.id
expect(response).to redirect_to(root_path)
end
end
end
end
Perhaps #user is carried on as being logged in from one test to the next, so the 2nd show succeeds. Try to sign off the user whithin the first test.
As this is not the case, check your config/routes.rb.
Resources requiring login should be wrapped within a do...end
authenticate(:user) do
resources :user
...other stuff
end

rspec shared_examples_for method

I have this controller spec file.
describe BriefNotesController do
render_views
before(:all) do
#customer=Factory(:customer)
#project=Factory(:project_started, :owner => #customer)
end
context 'get :new' do
it 'should redirect to login page for not signed in users' do
get :new, :project_id => #project.id
response.should new_user_session_path
end
end
context 'get :create' do
it 'should redirect to login page for not signed in users' do
post :create, {:project_id => #project.to_param, :brief_note => Factory.attributes_for(:brief_note, :project_id => #project.id)}
response.should redirect_to new_user_session_path
end
end
In these tests I repeat the same authentication test for each action and thus I want to recode it with dry way.I tried to recode this test with shared_examples_for method but I didn't handle with it.
Something like this can work
shared_examples_for 'redirects to login page if not signed in' do
context 'get :new' do
it 'should redirect to login page for not signed in users' do
get :new, :project_id => resource.id
response.should redirect_to new_user_session_path
end
end
context 'get :create' do
it 'should redirect to login page for not signed in users' do
post :create, resource_params
response.should redirect_to new_user_session_path
end
end
end
You would use it like this:
describe BriefNoteController do
let(:customer) { Factory(:customer) }
let(:project) { Factory(:project_started, :owner => customer) }
let(:resource) { project }
let(:resource_params) do
{
:project_id => project.to_param,
:brief_note => Factory.attributes_for(:brief_note, :project_id => project.id)
}
end
it_behaves_like 'redirects to login page if not signed in'
end

Rails 3 tutorial Ch. 10.6 ex 5 rspec failure

In solving exercise 5, I ran into a similar issue as this question. I refactored based on the answer given to that question but am still receiving the failure:
1) UsersController DELETE 'destroy' as an admin user should not self-destruct
Failure/Error: lambda do
count should have been changed by 0, but was changed by -1
# ./spec/controllers/users_controller_spec.rb:354:in `block (4 levels) in <top (required)>'
My spec:
it "should destroy the user" do
lambda do
delete :destroy, :id => #user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => #user
response.should redirect_to(users_path)
end
it "should not self-destruct" do
lambda do
delete :destroy, :id => #user.id
end.should change(User, :count).by(0)
end
and my controller:
def destroy
#user = User.find(params[:id])
if current_user == #user
flash[:notice] = "You cannot destroy yourself"
else
#user.destroy
flash[:success] = "User destroyed"
end
redirect_to users_path
end
I've checked the behavior in the browser and it works as expected. As always, any help is appreciated. Thanks!
The updated, working code:
describe "as an admin user" do
before(:each) do
#admin = Factory(:user, :email => "admin#example.com", :admin => "true")
test_sign_in(#admin)
end
it "should have links to destroy a user" do
get :index
response.should have_selector("a", :content => "delete" )
end
it "should destroy the user" do
lambda do
delete :destroy, :id => #user
end.should change{ User.count }.by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => #user
response.should redirect_to(users_path)
end
it "should not be allowed to delete itself" do
lambda do
delete :destroy, :id => #admin
end.should_not change{ User.count }
end
end
I just realised that I read the wrong one of the three tests you posted (it would be clearer if you only posted the failing test :)
However I'm confused, your "it should not self destruct" test is exactly the same as "it should destroy the user":
it "should destroy the user" do
lambda do
delete :destroy, :id => #user
end.should change(User, :count).by(-1)
end
it "should not self-destruct" do
lambda do
delete :destroy, :id => #user.id
end.should change(User, :count).by(0)
end
You're running the same test both times but expecting different outcomes. I would take a look again at the "it should not self destruct" and see what you mean by that (I'm not sure).
I would guess that what needs to change is whatever is in the `change( xxxx ).by(0). What is it that shouldn't be changing through the test?
This bit me for a long time too. Try changing your syntax from:
should change(User, :count).by(-1)
to:
should change{ User.count }.by(-1)
Or try doing:
This is getting a little away from the book but you could try changing your syntax. The RSpec recommendation for this type of expectation is:
it "should destroy the user" do
expect{
delete :destroy, :id => #user
}.to change{ User.count }.by(-1)
end
Which I actually think is much cleaner and more readable anyway. Could you provide a link to the example as it is in the book?

Factory girl with rails 3 gives error message: 'Validation failed: Name can't be blank'

I'm running rails 3.0.9 and ruby 1.9.2 and working from the Hartl ruby on rails tutorial. I'm also running spork. Using factory_girl_rails v. 1.1.0
Failures:
1) UsersController GET 'show' should be successful
Failure/Error: #user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Name can't be blank
# ./spec/controllers/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Finished in 0.38122 seconds
3 examples, 1 failure
Failed examples:
rspec ./spec/controllers/users_controller_spec.rb:12 # UsersController GET 'show' should be successful
Mr factories.rb file
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
User_controller_spec.rb file
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'show'" do
before(:each) do
#user = Factory(:user)
end
it "should be successful" do
get :show, :id => #user
response.should be_success
end
# it "show the right user" do
# get :show, :id => #user
# assigns(:user).should == #user
# end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get :new
response.should have_selector('title', :content => "Sign up")
end
end
end
show.html.rb file
<%= #user.name %>, <%= #user.email %>
Just a thought, but did you restart the Spork server? This is sometimes necessary, see Spork: how to refresh validations and other code? for more info.

Simple RSpec tests failing

I'm following this tutorial here, and everything has worked out very well so far.
But now that I've progressed to sessions, some simple rspec tests are failing:
describe SessionsController do
#[...]
describe "GET 'new'" do
it "should have the right title" do
get :new
response.should have_selector( "title", :content => "Sign in" )
end
end
#[...]
describe "POST 'create'" do
#[...]
it "should have the right title" do
post :create, :session => #attr
response.should have_selector("title", :content => "Sign in")
end
#[...]
end
end
When I run rspec, I always get:
1) SessionsController GET 'new' should
have the right title
Failure/Error: response.should have_selector( "title", :content =>
"Sign in
)
expected following output to contain a Sign in tag:
w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/sessions_controller_spec.rb:14:in
`block (3 levels) in '
When I access the sessions/new page, the page contains a title tag like the following:
<title>Ruby on Rails Tutorial Sample App | Sign in</title>
Why do those tests fail, while all other similar (= tests for the title tag) tests work fine?
Here's the SessionController:
class SessionsController < ApplicationController
def new
#title = 'Sign in'
end
def create
user = User.authenticate( params[:session][:email], params[:session][:password] )
if user.nil?
flash.now[:error] = "Invalid email/password combination."
#title = 'Sign in'
render 'new'
else
sign_in user
redirect_to user
end
end
def destroy
sign_out
redirect_to root_path
end
end
What am I doing wrong here?
thx for your help
You need to add render_views to the top of the class. Without it, the actual html will not be generated and your have_selector tests will fail.

Resources