Rspec tests keep failing with expected ... got nil - ruby-on-rails

I'm trying to get into TDD and i'm currently struggling with this error message:
UsersController GET 'show' should find the right user
Failure/Error: expect(user).to eq(#user)
expected: #<User id: 1, email: "example#example.com", encrypted_password: "$2a$04$AVGGS0XU1Kjmbdc/iZ86iOq2f4k992boP7xfqcg2nl6...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2014-06-08 19:43:41", updated_at: "2014-06-08 19:43:41", name: "Test User", confirmation_token: nil, confirmed_at: "2014-06-08 19:43:41", confirmation_sent_at: nil, unconfirmed_email: nil, account_id: 1, notify: nil>
got: nil
(compared using ==)
# ./spec/controllers/users_controller_spec.rb:28:in `block (3 levels) in <top (required)>'
Here's the particular test:
require 'rails_helper'
include Devise::TestHelpers
describe UsersController do
before (:each) do
#user = FactoryGirl.create(:user)
sign_in #user
end
describe "GET 'show'" do
it "should find the right user" do
get :show, :id => #user.id
puts "user = #{#user.inspect}"
user = assigns(:user)
#assigns(:user).should == #user
puts "assigns user = #{assigns(:user)}"
expect(user).to eq(#user)
end
end
end
Here's the controller:
class UsersController < ApplicationController
...
def show
authorize! :show, #user, :message => 'Not authorized as an administrator.'
#user = current_account.users.find(params[:id])
end
...
end
application_controller.rb:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
check_authorization :unless => :devise_controller?
before_filter :authenticate_user!, :validate_subdomain
helper_method :subdomain, :current_account
layout :set_layout
# This will redirect the user to your 404 page if the account can not be found
# based on the subdomain. You can change this to whatever best fits your
# application.
def validate_subdomain
current_account
end
def current_account
#current_account ||= Account.where(:subdomain => subdomain).first
#puts #current_account
if #current_account.nil?
redirect_to('/accounts/invalid_site')
return
end
#current_account
end
def subdomain
request.subdomain
end
...
end
user factory:
FactoryGirl.define do
factory :user do
name 'Test User'
account_id 1
email 'example#example.com'
password 'changeme'
password_confirmation 'changeme'
# required if the Devise Confirmable module is used
confirmed_at Time.now
end
end
How can I get around this error message? I have a feeling it has something to do with before_filters, but that's just a guess.

Do you have before_filter on your users controller where you need authentication to use the show method? Your before block is making two calls, creating a user and then "sign_in", some kind of authentication. But your test is just to see if the user was created and the show method returns the correct user record with the passed id.
So I would break down your before block. Start by testing that your Factory is being created successfully:
it 'has a valid factory' do
FactoryGirl.create(:user).should eq(true) # or should be_valid..
end
If that passes, I'd comment out any constraint on your users controller (temporarily) for the sign_in method, and test if show receives the id and returns the correct user.
If that passes, then add the constraint back in for validation on your users controller, and figure out how to test your sign_in method. :)

Ok so i figured it out from debugging through the current_account not getting set. I found this answer Rails rspec set subdomain.
I guess i left out a major piece of the puzzle in my original question so i apologize about that as I had no idea that would affect my rspecs.
The trick was to
before(:each) do
#account = FactoryGirl.create(:account)
#request.host = "#{#account.subdomain}.example.com"
end

Related

Rails controller tests with devise sign in unexpected behavior

I am trying to create a simple tests on my application with devise. I have a redirect set up if the user is not logged in, but even though I use sign_in before the test I still get redirected. When I manually test this, it works fine.
users.yml
george:
name: George
email: george#example.com
encrypted_password: <%= Devise::Encryptor.digest User, '123456' %>
addresses.yml
georges_home:
title: Home
receiver: George
street: '132 Mitchell St SW'
country: 'US'
city: 'Atlanta'
postal_code: '30303'
phone: '+1 404-524-5665'
state: 'Georgia'
user: george
addresses_controller.rb
class AddressesController < ApplicationController
before_action :login_needed
def index
#addresses = Address.where(user_id: #current_user.id)
end
private
def login_needed
if !user_signed_in?
redirect_to new_user_session_path, alert: 'Please log in.'
end
end
end
addresses_controller_test.rb
require 'test_helper'
class AddressesControllerTest < ActionController::TestCase
include Devise::TestHelpers
setup do
sign_in users(:george)
#address = addresses(:georges_home)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:addresses)
end
end
I found a piece of code that was dealing with fixtures of a User model with devise and the confirmable option. So my users' fixture should look like this:
users.yml
george:
name: George
email: george#example.com
encrypted_password: <%= Devise::Encryptor.digest User, '123456' %>
confirmed_at: <%= Date.today %>

RSpec Controller Test Failing Method Not Called

I'm trying to write a simple RSpec test for "UsersController" that tests the index method.
The code for the controller index method looks as follows:
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
I am trying to test that the "all" method is called and that the index view is rendered. Here is my Rspec code for that:
require 'spec_helper'
describe UsersController do
describe 'get index', :type => :controller do
before :each do
#fake_users = [double('user1'), double('user2')]
end
it 'should call the model method that retrieves all Users' do
User.should_receive(:all).once.and_return(#fake_users)
get :index
end
describe 'after valid search' do
before :each do
User.stub(:all).and_return(#fake_users)
get :index
end
it 'should select the index template for rendering' do
response.should render_template('index')
end
it 'should make the users results available to that template' do
assigns(:users).should == #fake_users
end
end
end
end
However, this fails the "get index" test with the following message:
Failure/Error: User.should_receive(:all).once.and_return(#fake_users)
(<User(id: integer, firstname: string, lastname: string, username: string, email: string, password_digest: string, created_at: datetime, updated_at: datetime) (class)>).all(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
# ./spec/controllers/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Can anyone shed any light on what I'm doing wrong?
The problem was caused by the UsersController requiring a log in first. So the controller looked like:
class UsersController < AuthenticatedController
So the path wasn't accessible to RSpec.

devise with rspec test fails due to prevoius tests

i have used devise in rspec testing. this is my test
describe BooksController do
before(:all) do
#user = FactoryGirl.create(:user)
end
describe "GET index" do
it "shows list of current user books" do
sign_in #user
book = #user.books.create!(:title => "user")
get :index, {}
assigns(:books).should eq(#user.books)
end
end
describe "GET show" do
it "assigns the requested book as #book" do
sign_in #user
book = #user.books.create!(:title => "user")
visit_count = book.visits.to_i
get :show, {:id => book.to_param}
assigns(:book).should eq(book)
book = Book.find(book.id)
visit_count.should_not eq(book.visits)
end
end
describe "GET new" do
it "assigns a new book as #book" do
sign_in #user
get :new, {}
assigns(:book).should be_a_new(Book)
end
end
end
factory
FactoryGirl.define do
factory :user do
sequence(:email) { |n| "foo#{n}#example.com" }
password '12345678'
password_confirmation '12345678'
confirmed_at Time.now
end
end
book controller
class BooksController < ApplicationController
before_action :authenticate_user!, only: [:index, :edit, :update, :destroy, :new, :my_books, :add_wish_list]
# GET /books
# GET /books.json
def index
#books = current_user.books
end
# GET /books/1
# GET /books/1.json
def show
#book = Book.find(params[:id])
#book.book_visit_count
if(session["warden.user.user.key"].present?)
#book.book_visit_user(session["warden.user.user.key"][0][0])
end
end
# GET /books/new
def new
#book = Book.new
end
end
error
Failure/Error: assigns(:book).should be_a_new(Book)
expected nil to be a new Book(id: integer, title: string, author: string, isbn_10: string, isbn_13: string, edition: integer, print: integer, publication_year: integer, publication_month: string, condition: string, value: integer, status: boolean, stage: integer, description: text, visits: integer, user_id: integer, prefered_place: string, prefered_time: string, created_at: datetime, updated_at: datetime, rating: integer, image: string, publisher: string, goodreads_id: string)
# ./spec/controllers/books_controller_spec.rb:66:in `block (3 levels) in <top (required)>'
the problem is the third test "get new" fails when i run the test as a whole but passes when i run it individually. and also if i remove the before_authenticate! in controller then all test passes.
Again if i commented out the "assigns" in first two describe blocks then all tests pass again.
i am using rails 4.0.2 and rspec 2.14.7 , devise 3.2.2
The only thing I can figure is that your authenticate_user method is failing for users that have previously been authenticated. It's not affecting show because you don't have :show listed in your before_action. You could test this theory by requiring authentication for show as well and seeing if your second example starts failing for before(:all) as well.

One rspec roles test fails, but almost identical tests succeeds

I just added the Rolify gem, and am running some rspec tests.
2 tests are as follows:
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role? :admin
should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role? :moderator
should be_true
end
end
The test result is:
1) User roles should not approve incorrect roles
Failure/Error: should be_false
expected: false value
got: #<User id: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, name: nil, position: nil, location: nil, admin: false, archived: false, public_email: false, created_at: nil, updated_at: nil>
# ./spec/models/user_spec.rb:70:in `block (3 levels) in <top (required)>'
Finished in 1.37 seconds
7 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:67 # User roles should not approve incorrect roles
Randomized with seed 13074
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) {|n| "Example User #{n}"}
sequence(:email) {|n| "email#{n}#program.com" }
position "Regular"
location "Anywhere, USA"
public_email false
password "foobar"
password_confirmation "foobar"
confirmed_at Time.now
end
end
How is the first test is failing with a nil object, but the second is passing?
EDIT
Upon further inspection, any test for should be_true passes, and any test for should be_false fails, regardless of whether the added role matches the checked role.
When your tests do should be_true what is happening is the should call is being delegated to the subject object (see RSpec docs for implicit receiver). In this case, your subject object is a User instance that has not yet been saved to the database. If your user_spec.rb file starts with describe User do, RSpec is automatically providing this default subject of User.new (see RSpec docs for implicit subject).
What this means is that your tests are essentially doing User.new.should be_true and User.new.should be_false. Since a User object will always evaluate to true, the should be_true test will always pass (although probably not for the reason you wanted it to) and the should be_false will always fail.
Based on the way your tests are written, maybe you meant something more like this:
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role?(:admin).should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role?(:moderator).should be_true
end
end
I'm assuming that the example group is actually nested in a group declared with describe User do, yes?
The problem is that the last line of each example reads should xxx, but should has no receiver, so RSpec is substituting an instance of User for you.
What you want is:
describe User do
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role?(:admin).should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role?(:moderator).should be_true
end
end
end
HTH,
David

How to post to create with spec helper method in controller spec?

I'm relatively new to programming, Rails, Ruby, Rspec, and the like, so thanks for your help!
My specs were very repetitive, so I wrote some spec helper methods. I can't figure out how to properly use them in my specs. Specifically, I have a users controller with create:
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_path(#user)
else
render :action => :new
end
end
A bit in the spec helper that creates a valid user:
def valid_user_eilif
#test_image = Rails.root + "spec/fixtures/images/seagull.jpg"
#file = Rack::Test::UploadedFile.new(#test_image, "image/jpeg")
user = User.create!(:username => "eilif", :email => "eilif#email.org",
:image => #file, :bio => "Lots of text that I don't want to write",
:signature_quote => "Yet more text.")
user.save!
user
end
And then in my user controller spec:
before (:each) do
post :create, :user => valid_user_eilif
end
it 'should assign user to #user' do
assigns(:user).should eq(User.last)
end
When I run the spec I get the error:
Failure/Error: assigns(:user).should eq(User.last)
expected #<User id: 1, username: "eilif", email: "eilif#email.org", bio: "Lots of text that I don't want to write", signature_quote: "I feel empty.", image_file_name: "seagull.jpg", image_content_type: "image/jpeg", image_file_size: 10475, image_updated_at: "2011-05-10 23:35:55", created_at: "2011-05-10 23:35:56", updated_at: "2011-05-10 23:35:56">
got #<User id: nil, username: nil, email: nil, bio: nil, signature_quote: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, created_at: nil, updated_at: nil>
So, I assume I'm incorrectly posting to create, since nothing is created? What's the proper way to do this?
Ideally controller specs shouldn't depend on the model being able to create a row in the database. With such a simple action you can mock out the dependencies:
describe UsersController do
context "on success" do
before(:each) do
#user = mock_model(User,:save=>true)
User.stub(:new) {#user}
post :create, :user => {}
end
it "redirects" do
response.should redirect_to(user_path(#user))
end
it "assigns" do
assigns[:user].should == #user
end
end
context "on failure" do
it "renders 'new'" do
#user = mock_model(User,:save=>false)
User.stub(:new) {#user}
post :create, :user => {}
response.should render_template "users/new"
end
end
end
Notice that the specs don't pass anything in params[:user]. This helps enforce the MVC separation of concerns, whereby the model is responsible for handling the attributes, ie. validating, setting up associations, etc. You can't always keep controllers this 'skinny', but it's a good idea to try.
It looks like the problem is that #user doesn't get refreshed after the save. Try assigns(:user).reload.should eql(User.last).
But there's another slight problem, and that's probably still going to fail. You shouldn't be calling post with :user => valid_user_eilif; you want the attributes from your user record, not the actual user object itself. And you're essentially creating a new user in valid_user_eilif and then making your controller create that object again -- if you have any kind of unique constraints, you're going to get a conflict.
This is a good place to use something like factory_girl and mocks. For an example, take a look at how one of my projects handles controller specs. This example uses factory_girl, Mocha and shoulda. I'll annotate it with comments below:
describe MembersController, "POST create" do
before do
# Factory Girl - builds a record but doesn't save it
#resource = Factory.build(:member)
# Mocha expectation - overrides the default "new" behavior and makes it
# return our resource from above
Member.expects(:new).with({}).returns(#resource)
# Note how we expect it to be called with an empty hash; that's from the
# `:member` parameter to `post` below.
end
context "success" do
before do
post :create, :member => {}
end
# shoulda matchers - check for a flash message and a redirect
it { should set_the_flash.to(/successfully created/) }
it { should redirect_to(member_path(#resource)) }
end
context "failure" do
before do
# Mocha - To test a failing example in the controller, we override the
# default `save` behavior and make it return false, otherwise it would
# be true
#resource.expects(:save).returns(false)
post :create, :member => {}
end
# shoulda matchers - check for no flash message and re-render the form
it { should_not set_the_flash }
it { should render_template(:new) }
end
end

Resources