问题
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