Here's my very simple ability class:
class Ability
include CanCan::Ability
def initialize(user)
if user.has_role? :admin
can :manage, :control_panel
end
end
end
How should I mock it in a controller spec?
Here's my control panel controller:
class Admin::ControlPanelController < ApplicationController
authorize_resource class: false
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, danger: "#{exception}"
end
def statistics
end
end
Here's my control_panel controller spec:
describe '#statistics:' do
let(:request){ get :statistics }
context 'When guest;' do
before do
# HOW SHOULD I MOCK HERE?
end
describe 'response' do
subject { response }
its(:status){ should eq 302 }
its(:content_type){ should eq 'text/html' }
it{ should redirect_to root_path }
end
describe 'flash' do
specify { expect( flash[:danger] ).to eq "You do not have sufficient priviledges to access the admin area. Try logging in with an account that has admin priviledges." }
end
end
How should I mock the ability? Before, I was doing this:
let(:user){ FactoryGirl.create :user }
expect(controller).to receive(:current_user).and_return user
expect(user).to receive(:has_role?).with(:admin).and_return false
but that was before I was using cancan and was manually checking that the user had a certain role. This behaviour was happening in the application controller and so was very easy to mock. I'm having difficulty mocking this ability class :(
I want to mock it in different contexts. I'm feeling a bit lost because even if I do this:
expect(Ability).to receive(:asdasdadskjadawd?).at_least(:once)
No error is raised, though one is raised if I do spell 'Ability' wrongly so it's mocking the class ok...
I don't think you should be mocking the Ability
class, especially not in a controller test. The Ability
class is more like configuration than code; it doesn't change during your application. It's also an implementation detail that the controller shouldn't care about.
Instead, you should be mocking your Users
. It looks like you're using FactoryGirl; you could use FactoryGirl's traits to mock the various kinds of user you have:
FactoryGirl.define do
factory :user do
name 'Bob'
email '[email protected]
role 'user'
trait :admin do
role 'admin'
end
trait :guest do
role 'guest'
end
end
end
You can then use FactoryGirl.create :user
if you need a regular user, and FactoryGirl.create :user, :admin
if your test requires an admin.