class TestingAbility include CanCan::Ability def initialize(user) can :read, User can :comment, User cannot :destroy, User end end describe 'CanCan custom RSpec::Matchers' do subject(:ability) { TestingAbility.new(user) } let(:user) { create(:user) } let(:other_user) { create(:user) } it { should have_abilities(:read, other_user) } it { should have_abilities(:comment, other_user) } it { should have_abilities({destroy: false}, other_user) } it { should have_abilities([:read], other_user) } it { should have_abilities([:read, :comment], other_user) } it { should have_abilities({read: true}, other_user) } it { should have_abilities({read: true, comment: true}, other_user) } it { should have_abilities({read: true, destroy: false}, other_user) } it { should have_abilities({read: true, comment: true, destroy: false}, other_user) } it { should not_have_abilities(:destroy, other_user) } it { should not_have_abilities([:destroy], other_user) } # These should all expect failure intentionally, to catch false positives. let(:expected_error) { RSpec::Expectations::ExpectationNotMetError } it { expect { should have_abilities(:destroy, other_user) }.to raise_error(expected_error) } it { expect { should have_abilities([:destroy], other_user) }.to raise_error(expected_error) } it { expect { should have_abilities([:read, :destroy], other_user) }.to raise_error(expected_error) } it { expect { should have_abilities({read: true, destroy: true}, other_user) }.to raise_error(expected_error) } it { expect { should have_abilities({read: false, destroy: false}, other_user) }.to raise_error(expected_error) } it { expect { should have_abilities({read: false, destroy: true}, other_user) }.to raise_error(expected_error) } it { expect { should not_have_abilities([:read, :destroy], other_user) }.to raise_error(expected_error) } it { expect { should not_have_abilities({destroy: false}, other_user) }.to raise_error(ArgumentError) } # Never use should_not with have_abilities. end