Подтвердить что ты не робот

Тестирование просмотров, которые используют CanCan и Devise с RSpec

Я пытался проверить простой индексный просмотр, который имеет следующий код внутри:

- if can? :destroy, MyModel
  %th Options

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

При запуске спецификаций он выходит из строя на линии - if can? :destroy, MyModel

Failure/Error: render
   ActionView::Template::Error:
      undefined method `authenticate' for nil:NilClass

Нет следа, ничего не основано на...

Я думал, что, возможно, я не авторизовался и не подписал при тестировании представлений, но Devise::TestHelpers должен быть включен только в тесты контроллера (и то, что у меня есть).

Я пытался переопределить метод? как в Ability, так и в контроллере, но это не дало эффекта.

4b9b3361

Ответ 1

Это описано в CanCan docs для тестирования контроллера, а также может быть изменено для применения к спецификациям вида. Вот один из способов сделать это:

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

Ответ 2

Код "до: каждый", отправленный zetetic, не работает для меня. Мои взгляды на "может"? потому что 'current_ability' в представлении возвращает nil. Я исправил его, используя вместо этого код "before: each":

@ability = Ability.new(user)
assign(:current_ability, @ability)
controller.stub(:current_user, user)
view.stub(:current_user, user)

Вышеупомянутый код моделирует логин.

Ответ 3

В вашем spec_helper:

config.include Devise::TestHelpers, :type => :view

В вашем представлении spec:

controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])

Ответ 4

Для нового синтаксиса 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

Ответ 5

Проблема с решением из вики CanCan заключается в том, что в каждом примере требуется @ability. can ..., который не чувствует себя очень СУХОЙ.

Кроме того, он фактически не заглушает сами способности, а метод, который возвращает способность контроллера. Способность не является заглушкой, и, следовательно, возможности проверяются.

Если вы используете Rspec и хотите протестировать только контроллер (а не его способности), вот как его заглушить:

before(:each) do
  ability = mock(:ability).as_null_object
  controller.stub(:current_ability).and_return(ability)
end

Это работает, потому что as_null_object возвращает правдивые значения для всех методов, поэтому методы проверки способности проходят.