Class: ActionPolicy::RSpec::BeAuthorizedTo

Inherits:
RSpec::Matchers::BuiltIn::BaseMatcher
  • Object
show all
Defined in:
lib/action_policy/rspec/be_authorized_to.rb

Overview

Authorization matcher ‘be_authorized_to`.

Verifies that a block of code has been authorized using specific policy.

Example:

# in controller/request specs
subject { patch :update, id: product.id }

it "is authorized" do
  expect { subject }
    .to be_authorized_to(:manage?, product)
    .with(ProductPolicy)
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rule, target) ⇒ BeAuthorizedTo

Returns a new instance of BeAuthorizedTo.



25
26
27
28
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 25

def initialize(rule, target)
  @rule = rule
  @target = target
end

Instance Attribute Details

#actual_callsObject (readonly)

Returns the value of attribute actual_calls.



23
24
25
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 23

def actual_calls
  @actual_calls
end

#policyObject (readonly)

Returns the value of attribute policy.



23
24
25
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 23

def policy
  @policy
end

#ruleObject (readonly)

Returns the value of attribute rule.



23
24
25
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 23

def rule
  @rule
end

#targetObject (readonly)

Returns the value of attribute target.



23
24
25
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 23

def target
  @target
end

Instance Method Details

#actual_calls_messageObject



65
66
67
68
69
70
71
72
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 65

def actual_calls_message
  if actual_calls.empty?
    "no authorization calls have been made"
  else
    "the following calls were encountered:\n" \
    "#{formatted_calls}"
  end
end

#does_not_match?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 51

def does_not_match?(*)
  raise "This matcher doesn't support negation"
end

#failure_messageObject



59
60
61
62
63
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 59

def failure_message
  "expected #{formatted_record} " \
  "to be authorized with #{policy}##{rule}, " \
  "but #{actual_calls_message}"
end

#formatted_callsObject



74
75
76
77
78
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 74

def formatted_calls
  actual_calls.map do |acall|
    " - #{acall.inspect}"
  end.join("\n")
end

#formatted_record(record = target) ⇒ Object



80
81
82
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 80

def formatted_record(record = target)
  ::RSpec::Support::ObjectFormatter.format(record)
end

#match(_expected, actual) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 35

def match(_expected, actual)
  raise "This matcher only supports block expectations" unless actual.is_a?(Proc)

  @policy ||= ::ActionPolicy.lookup(target)

  begin
    ActionPolicy::Testing::AuthorizeTracker.tracking { actual.call }
  rescue ActionPolicy::Unauthorized # rubocop: disable Lint/HandleExceptions
    # we don't want to care about authorization result
  end

  @actual_calls = ActionPolicy::Testing::AuthorizeTracker.calls

  actual_calls.any? { |call| call.matches?(policy, rule, target) }
end

#supports_block_expectations?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 55

def supports_block_expectations?
  true
end

#with(policy) ⇒ Object



30
31
32
33
# File 'lib/action_policy/rspec/be_authorized_to.rb', line 30

def with(policy)
  @policy = policy
  self
end