[英]Testing views that use CanCan and Devise with RSpec
I was trying to test a simple index view, which has following code inside: 我试图测试一个简单的索引视图,其中包含以下代码:
- if can? :destroy, MyModel
%th Options
MyModelsController
has following options (Inherited Resources + CanCan + Devise): MyModelsController
有以下选项(Inherited Resources + CanCan + Devise):
class MyModelsController < ApplicationController
inherit_resources
nested_belongs_to :mymodel
before_filter :authenticate_user!
load_and_authorize_resource :project
load_and_authorize_resource :mymodel, :through => :project
When running specs, it crashes at the line - if can? :destroy, MyModel
在运行规格时,它会崩溃
- if can? :destroy, MyModel
- if can? :destroy, MyModel
Failure/Error: render
ActionView::Template::Error:
undefined method `authenticate' for nil:NilClass
There's no traceback, nothing to base on... 没有追溯,没有任何依据......
I thought that maybe I'm not authorized and signed when testing views, but Devise::TestHelpers
should only be included in controller tests (and that's how I have it). 我想也许在测试视图时我没有被授权和签名,但是
Devise::TestHelpers
应该只包含在控制器测试中(这就是我的方法)。
I was trying to override method can? 我试图覆盖方法可以吗? in both
Ability
and the controller, but that gave no effect. 在
Ability
和控制器中,但没有产生任何影响。
This is described in the CanCan docs for controller testing , and can also be modified to apply to view specs. 这在控制器测试的CanCan文档中有所描述,也可以修改为适用于查看规范。 Here's one way to do it:
这是一种方法:
require 'spec_helper'
describe "mymodel/index.html.erb" do
before(:each) do
assign(:my_model,mock_model(MyModel))
@ability = Object.new
@ability.extend(CanCan::Ability)
controller.stub(:current_ability) { @ability }
end
context "authorized user" do
it "can see the table header" do
@ability.can :destroy, MyModel
render
rendered.should have_selector('th:contains("Options")')
end
end
context "unauthorized user" do
it "cannot see the table header" do
render
rendered.should_not have_selector('th:contains("Options")')
end
end
end
In your spec_helper: 在您的spec_helper中:
config.include Devise::TestHelpers, :type => :view
In your view spec: 在您的视图规范中:
controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])
The 'before :each' code posted by zetetic doesn't work for me. zetetic发布的'before:each'代码对我不起作用。 My views bork on the 'can?'
我对'can?'的看法很开心 method because 'current_ability' in the view returns nil.
方法因为视图中的'current_ability'返回nil。 I fixed it by using this 'before :each' code instead:
我使用这个'before:each'代码修改了它:
@ability = Ability.new(user)
assign(:current_ability, @ability)
controller.stub(:current_user, user)
view.stub(:current_user, user)
The above code simulates a login. 上面的代码模拟了登录。
For new RSpec 3.0 syntax 对于新的RSpec 3.0语法
before(:each) do
assign(:my_model,mock_model(MyModel))
@ability = Object.new.extend(CanCan::Ability)
allow(controller).to receive(:current_ability).and_return(@ability)
end
The problem with the solution from the CanCan wiki is that it requires a @ability. can ...
CanCan wiki解决方案的问题在于它需要
@ability. can ...
@ability. can ...
in each example, which doesn't feel very DRY. @ability. can ...
在每个例子中,感觉不是很干。
Moreover, it doesn't actually stub out the abilities themselves, but the method that returns the controller's ability. 而且,它实际上并没有隐藏能力本身,而是返回控制器能力的方法。 The ability is not a stub and consequently the abilities are checked.
能力不是存根,因此检查能力。
If you're using Rspec and want to test just the controller (and not it's abilities), here's how to stub it out: 如果您正在使用Rspec并且想要仅测试控制器(而不是它的能力),那么这里是如何将其存根:
before(:each) do
ability = mock(:ability).as_null_object
controller.stub(:current_ability).and_return(ability)
end
This works because as_null_object
returns truthy values for all methods, so the ability checking methods pass. 这是因为
as_null_object
为所有方法返回truthy值,因此能力检查方法通过。
Based on John Kloian's example I defined this useful helper: 根据John Kloian的例子,我定义了这个有用的帮手:
# spec/support/sign_in.rb
module ViewSpecSignInHelper
def login_as(user)
allow(view).to receive(:signed_in?).and_return true
allow(controller).to receive(:current_user).and_return user
end
end
RSpec.configure do |config|
config.include ViewSpecSignInHelper, type: :view
end
My full spec/support/sign_in.rb
looks like this: 我的完整
spec/support/sign_in.rb
如下所示:
module ControllerSpecSignInHelper
def login_as(user)
sign_in(user)
end
end
module FeatureSpecSignInHelper
# See https://github.com/plataformatec/devise/wiki/How-To%3a-Test-with-Capybara
include Warden::Test::Helpers
Warden.test_mode!
# A login_as(user) method is provided already!
end
module ViewSpecSignInHelper
def login_as(user)
allow(view).to receive(:signed_in?).and_return true
allow(controller).to receive(:current_user).and_return user
end
end
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include ControllerSpecSignInHelper, type: :controller
config.include FeatureSpecSignInHelper, type: :feature
config.include ViewSpecSignInHelper, type: :view
end
I can now login a user the same way in feature, controller, and view specs: 我现在可以在功能,控制器和视图规范中以相同的方式登录用户:
user = create :user # Using FactoryBot
login_as user
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.