RSpec: how to stub inherited method current_user (w/o Devise)?

廉价感情. 提交于 2019-12-21 03:13:34

问题


I have a controller based on MHartl's RoR4 Tutorial

And just like MHartl, I'm not using Devise, I rolled my own authentication system

Having trouble with the RSpec for UsersController#Edit since the view has a call to current_user.admin? and the controller calls @path_switch = path_switch

I keep getting RSpec errors along the lines of:

1) User Pages Edit 
 Failure/Error: visit edit_user_path(user)
 NoMethodError:
   undefined method `admin?' for nil:NilClass
 # ./app/controllers/users_controller.rb:106:in `path_switch'
 # ./app/controllers/users_controller.rb:53:in `edit'
 # ./spec/requests/user_pages_spec.rb:54:in `block (3 levels) in <top (required)>'

UsersController:

class UsersController < ApplicationController
  ...
  def edit
    @user = User.find(params[:id])
    @path_switch ||= path_switch                        #error
  end
  ...
  def path_switch
    if current_user.admin?                               #error
      users_path
    else
      root_path
    end
  end
end

I found this really helpful article that gives me hope that I'm on the right track, but I can't get it to work.

Here's as far as I've gotten (updated):

user_pages_spec.rb:

require 'spec_helper'
require 'support/utilities'

describe "User Pages" do
  #include SessionsHelper

  let(:user) { FactoryGirl.create(:user) }
  let(:current_user) {user}

  subject { page }

  describe "Edit" do
    before do
      sign_in(user)
      visit edit_user_path(user) 
    end

    it '(check links and content)' do
      should have_button('Submit')
      should have_link('Cancel')
      should have_content(user.fname+"\'s profile")
    end
   ...
  end
...
end

But current_user is still coming back nil

Any help/guidance is appreciated. Thanks!


Adding include SessionsHelper to the top describe block of my user_pages_edit.rb seems to try and use the sign_in(path) from that helper. Creating an issue between RSpec and cookies.permanent. So that's a bust.

unfortunately, this brings me right back to my .admin? error.

There are two calls to current_user.admin?

One is in the controller:

  def path_switch
    if current_user.admin?    #error current_user == nil
      users_path
    else
      root_path
    end
  end

One is in the view as ERB:

<% if current_user.admin? %>
  <div class="row  col-xs-6 col-sm-6 col-md-3">
    <div class="input-group input-selector">
    ...

All I need to do is figure out how to set current_user.admin = true and pass it to the controller (and then hopefully the view) so that the page can load. To do that, all I need to do is set current_user = user because user.admin == true.


回答1:


Also works

user = create(:user) #FactoryBot

allow(controller).to receive(:current_user).and_return(user)



回答2:


If you are doing unit testing of your controller you can simply stub your current_user in a before block, like this:

let(:user) { ... }

# RSpec version <= 2 syntax:
before { controller.stub(:current_user) { user } }

# RSpec version >= 3 syntax:
before { allow(controller).to receive(:current_user) { user } }

If you are doing feature or request testing, I advise you to perform a real log-in by creating a user in your database, then passing through your log-in page with this user credentials


Here you seem to be doing a feature test, you should write a helper that perform the creation of the user record and go through the log-in.

Additionally in feature testing to gain a lot of time while running your test, do not hesitate to group your assertions in the same block. Clearly, instead of:

it { should have_button('Submit')}
it { should have_link('Cancel')}
it { should have_content(user.fname+"\'s profile")}

You can write

it 'check links and content' do
  should have_button('Submit')
  should have_link('Cancel')
  should have_content(user.fname+"\'s profile")
end

That will avoid to generate several session of your feature environment, and also to log-in several times




回答3:


For me, worked with:

before { controller.stub!(:current_user).and_return(user) }



回答4:


I run into the same problem with a legacy Rails 4 app and based my solution on this test case of Rspec Views.

First define a helper that will define the missing helper method in the controller instance

# /spec/support/concerns/view_helper.rb
module ViewHelper
  def include_current_user_helper(&block)
    controller.singleton_class.class_eval do
      define_method :current_user, &block
      helper_method :current_user
    end
  end
end

Then configure Rspec to include it in all the view helpers

# spec/rails_helper.rb
# ...
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

RSpec.configure do |config|
  # ...
  config.include ViewHelper, type: :view
end

And in the view specs it is called like this

RSpec.describe 'something' do
  let!(:user) { FactoryGirl.create(:user) } # Note the "!" there
  before { include_current_user_helper { user } }

  # do stuff
end

Note: the call to let with bang is important as content inside the block will be executed lazily, outside of the test scope, and user will be nill if not



来源:https://stackoverflow.com/questions/24522294/rspec-how-to-stub-inherited-method-current-user-w-o-devise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!