Skip to content

Instantly share code, notes, and snippets.

@zorab47
Created March 7, 2014 16:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zorab47/9414504 to your computer and use it in GitHub Desktop.
Save zorab47/9414504 to your computer and use it in GitHub Desktop.
# RSpec CanCan matcher.
#
# When testing your user must have an id otherwise a nil foreign key will
# match on new records.
#
# Examples
#
# describe User do
# subject { User.create! }
#
# it { should have_ability(:read).for(Post.new) }
# it { should_not have_ability(:edit, :update, :destroy).for(Post.new) }
# end
#
RSpec::Matchers.define :have_ability do |*actions|
match_for_should do |user|
check_subject!
actual_abilities(actions, user) == expected_abilities(actions, user, true)
end
match_for_should_not do |user|
check_subject!
actual_abilities(actions, user) == expected_abilities(actions, user, false)
end
chain :for do |target|
@target = target
end
failure_message_for_should do |user|
"expected: #{expected_abilities(actions, user, true)} for #{user} on #{@target.inspect}\n got: #{actual_abilities(actions, user)}"
end
failure_message_for_should_not do |user|
"expected: #{expected_abilities(actions, user, false)} for #{user} on #{@target.inspect}\n got: #{actual_abilities(actions, user)}"
end
def actual_abilities(actions, user)
@actual_abilities ||= begin
ability = Ability.new(user)
actions.reduce({}) do |results, action|
results.merge({ action => ability.can?(action, @target) })
end
end
end
def expected_abilities(actions, user, expectation)
actions.reduce({}) do |abilities, action|
abilities.merge({ action => expectation })
end
end
def check_subject!
raise "Ability subject is nil! Subject should be defined: `have_ability(...).for(subject)`" if @target.nil?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment