Last active
August 29, 2015 14:15
-
-
Save creeonix/ab76a10bfe1b26933c97 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is updated version for RSpec 3, orgiginaly taken from here: | |
# https://gist.github.com/fotinakis/3a532a0929f64b4b5352 | |
# | |
# Custom rspec matcher for testing CanCan abilities. | |
# Originally inspired by https://github.com/ryanb/cancan/wiki/Testing-Abilities | |
# | |
# Usage: | |
# expect.to have_abilities(:create).on(Post.new) | |
# expect.to have_abilities([:read, :update]).on(post) | |
# expect.to have_abilities({manage: false, destroy: true}).on(post) | |
# expect.to have_abilities({create: false}).on(Post.new) | |
# expect.to not_have_abilities(:update).on(post) | |
# expect.to not_have_abilities([:update, :destroy]).on(post) | |
# | |
# WARNING: never use "should_not have_abilities" or you may get false positives due to | |
# whitelisting/blacklisting issues. Use "should not_have_abilities" instead. | |
RSpec::Matchers.define :have_abilities do |actions| | |
include HaveAbilitiesMixin | |
chain :on do |obj| | |
@object = obj | |
end | |
match do |ability| | |
verify_ability_type(ability) | |
@expected_hash = build_expected_hash(actions, default_expectation: true) | |
@actual_hash = {} | |
@expected_hash.each do |action, _| | |
@actual_hash[action] = ability.can?(action, @obj) | |
end | |
@actual_hash == @expected_hash | |
end | |
description do | |
obj_name = @obj.class.name | |
obj_name = @obj.to_s.capitalize if [Class, Module, Symbol].include?(@obj.class) | |
"have abilities #{@expected_hash.keys.join(', ')} on #{obj_name}" | |
end | |
failure_message do |ability| | |
obj_name = @obj.class.name | |
obj_name = @obj.to_s.capitalize if [Class, Module, Symbol].include?(@obj.class) | |
message = ( | |
"expected user to have abilities: #{@expected_hash} for " + | |
"#{obj_name}, but got #{@actual_hash}" | |
) | |
end | |
end | |
RSpec::Matchers.define :not_have_abilities do |actions| | |
include HaveAbilitiesMixin | |
chain :on do |obj| | |
@object = obj | |
end | |
match do |ability| | |
verify_ability_type(ability) | |
if actions.is_a?(Hash) | |
raise ArgumentError.new( | |
'You cannot pass a hash to not_have_abilities. Use have_abilities instead.') | |
end | |
@expected_hash = build_expected_hash(actions, default_expectation: false) | |
@actual_hash = {} | |
@expected_hash.each do |action, _| | |
@actual_hash[action] = ability.can?(action, @obj) | |
end | |
@actual_hash == @expected_hash | |
end | |
description do | |
obj_name = @obj.class.name | |
obj_name = @obj.to_s.capitalize if [Class, Module, Symbol].include?(@obj.class) | |
"not have abilities #{@expected_hash.keys.join(', ')} on #{obj_name}" if @expected_hash.present? | |
end | |
failure_message do |ability| | |
obj_name = @obj.class.name | |
obj_name = @obj.to_s.capitalize if [Class, Module, Symbol].include?(@obj.class) | |
message = ( | |
"expected user NOT to have abilities #{@expected_hash.keys.join(', ')} for " + | |
"#{obj_name}, but got #{@actual_hash}" | |
) | |
end | |
end | |
module HaveAbilitiesMixin | |
def build_expected_hash(actions, default_expectation:) | |
return actions if actions.is_a?(Hash) | |
expected_hash = {} | |
if actions.is_a?(Array) | |
# If given an array like [:create, read] build a hash like: | |
# {create: default_expectation, read: default_expectation} | |
actions.each { |action| expected_hash[action] = default_expectation } | |
elsif actions.is_a?(Symbol) | |
# Build a hash if it's just a symbol. | |
expected_hash = {actions => default_expectation} | |
end | |
expected_hash | |
end | |
def verify_ability_type(ability) | |
if !ability.class.ancestors.include?(CanCan::Ability) | |
raise TypeError.new("subject must mixin CanCan::Ability, got a #{ability.class.name} class.") | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
taken here and updated for RSpec 3