Search code examples
ruby-on-railsrspecrspec-rails

RSpec create method for build message


I'm still learning how to test controllers with rspec. I've got a simple message app where one user can create message to another user (only logged users can write messages). I didn't used devise to log in or sign up users, this app is as simple as possible just for rspec learning.

I've got create method in Messages controllers which I want to test:

class MessagesController < ApplicationController
  before_action :require_user

  def create
    message = current_user.messages.build(message_params)
    if message.save
      redirect_to root_path
    end
  end

  private

  def message_params
    params.require(:message).permit(:body)
  end
end

Here is my spec

RSpec.describe MessagesController, type: :controller do
  describe 'signed user' do
    before do
      user = User.create!(username: 'John', password: 'test123')
    end

    describe 'GET #create' do
      it 'create message' do
        expect do
          post :create, params: { message: { body: 'Please work!' } }
        end.to change(Message, :count).by(1)
        expect(response).to have_http_status(:redirect)
      end
    end
  end
end

With an error

expected Message.count to have changed by 1, but was changed by 0

I think I have to log in user but how to do so without using factory bot?

EDIT As suggested in comment, this should be useful

class ApplicationController < ActionController::Base
  helper_method :current_user, :logged_in?

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

  def logged_in?
    !!current_user
  end

  def require_user
    if !logged_in?
      flash[:error] = 'You must be logged in to perform that action'
      redirect_to login_path
    end
  end
end

Solution

  • You need to set @current_user for your spec to pass ie:

     before do
        user = User.create!(username: 'John', password: 'test123')
        assign(:current_user, user)
     end
    

    See assign docs for reference

    If assign @current_user doesn't work, try stub current_user instead ie

         before do
            user = User.create!(username: 'John', password: 'test123')
            allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
         end