Question: Rspec test error in devise session #create

Question

Rspec test error in devise session #create

Answers 2
Added at 2016-12-26 11:12
Tags
Question

I implemented point system. User.point increases by 2 when he does login. My devise session controller is below.

     class Users::SessionsController < Devise::SessionsController
            after_action :add_point, only: [:create]
             # POST /resource/sign_in
             def create
               super
             end
            private

          def add_point
              resource.rewards.create(point: 2)
         end

      end

and My spec/controllers/users_controller_spec.rb is below.

RSpec.describe UsersController, type: :controller do
 describe 'adds 2 point with login' do
  before do
      @user=create(:user)
  end
  it 'adds 2 point in one day if two times login' do
    expect{login_user(@user)}.to change {@user.points}.by(0)
  end
  it 'adds 4 point in two day ' do
    expect{login_user(@user)}.to change {@user.points}.by(2)
  end
 end 
end

and my model/user.rb is below.

      class User < ActiveRecord::Base
             def points
              self.rewards.sum(:point)
             end
      end

When I did rspec command , I had this error.

    Failure/Error: expect{login_user(@user)}.to change {@user.points}.by(2)
   expected result to have changed by 2, but was changed by 0

I confirmed that @user.points increased by 2 in rails/console. Why do I have this error? Please tell me.

By looking at answers , I change it to below.

      require 'rails_helper'

      RSpec.describe Users::SessionsController, type: :controller do
       describe 'adds 2 point with login' do
         before do
          @user=create(:user)
          @request.env["devise.mapping"] = Devise.mappings[:user]
        end
        it 'adds 2 point in one day if two times login' do
         expect{post :create, params: {email: @user.email ,password: @user.password} }.to change {@user.points(true)}.by(0)
  end
        it 'adds 4 point in two day ' do
          expect{post :create, params: {email: @user.email ,password: @user.password} }.to change {@user.points(true)}.by(2)
       end
     end
    end
Answers
nr: #1 dodano: 2016-12-26 12:12

In most cases that will work:

expect{ login_user(@user) }.to change { @user.reload.points }.by(0)

Looks like @user instance is desynchronized with DB.

nr: #2 dodano: 2016-12-30 16:12

First, have you configured the routing since you use a custom controller (albeit that inherits from Devise Session controller)?

something like this, but in your case, it's sessions instead of registrations:

devise_for :users, :controllers => { :registrations => "registrations" }

Source: https://howilearnedrails.wordpress.com/2013/12/27/how-to-override-and-customize-the-devise-controller-in-rails/comment-page-1/

Second, since you basically use a custom controller, try hitting the controller the normal way rather than using the Devise test helper. Assuming you got the login_user method from the Devise documentation like below here:

module ControllerMacros   
  def login_user
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      user = FactoryGirl.create(:user)
      user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
      sign_in user
    end
  end
end

you have to understand that the login_user method DOES NOT make a request to the Users::SessionsController you created. This is why your callback after_action :add_point, only: [:create] is not triggered, hence no points were added to the logged_in user.

What I meant by hitting the rspec with proper request is calling like this:

post :create, params: { session_params }
Source Show
◀ Wstecz