Module: ActionPolicy::TestHelper

Defined in:
lib/action_policy/test_helper.rb

Overview

Provides assertions for policies usage

Defined Under Namespace

Classes: WithScopeTarget

Instance Method Summary collapse

Instance Method Details

#assert_authorized_to(rule, target, with: nil, context: {}) ⇒ Object

Asserts that the given policy was used to authorize the given target.

def test_authorize
  assert_authorized_to(:show?, user, with: UserPolicy) do
    get :show, id: user.id
  end
end

You can omit the policy (then it would be inferred from the target):

assert_authorized_to(:show?, user) do
  get :show, id: user.id
end

Raises:

  • (ArgumentError)


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/action_policy/test_helper.rb', line 39

def assert_authorized_to(rule, target, with: nil, context: {})
  raise ArgumentError, "Block is required" unless block_given?

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

  begin
    ActionPolicy::Testing::AuthorizeTracker.tracking { yield }
  rescue ActionPolicy::Unauthorized
    # we don't want to care about authorization result
  end

  actual_calls = ActionPolicy::Testing::AuthorizeTracker.calls

  assert(
    actual_calls.any? { |call| call.matches?(policy, rule, target, context) },
    "Expected #{target.inspect} to be authorized with #{policy}##{rule}, " \
    "#{context ? "and context #{context}, " : ""}" \
    "but no such authorization has been made.\n" \
    "Registered authorizations: " \
    "#{actual_calls.empty? ? "none" : actual_calls.map(&:inspect).join(",")}"
  )
end

#assert_have_authorized_scope(type:, with:, as: :default, scope_options: nil) ⇒ Object

Asserts that the given policy was used for scoping.

def test_authorize
  assert_have_authorized_scope(type: :active_record_relation, with: UserPolicy) do
    get :index
  end
end

You can also specify ‘as` option.

NOTE: ‘type` and `with` must be specified.

You can run additional assertions for the matching target (the object passed to the ‘authorized_scope` method) by calling `with_target`:

def test_authorize
  assert_have_authorized_scope(type: :active_record_relation, with: UserPolicy) do
    get :index
  end.with_target do |target|
    assert_equal User.all, target
  end
end

Raises:

  • (ArgumentError)


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/action_policy/test_helper.rb', line 85

def assert_have_authorized_scope(type:, with:, as: :default, scope_options: nil)
  raise ArgumentError, "Block is required" unless block_given?

  policy = with

  ActionPolicy::Testing::AuthorizeTracker.tracking { yield }

  actual_scopes = ActionPolicy::Testing::AuthorizeTracker.scopings

  scope_options_message = if scope_options
    "with scope options #{scope_options}"
  else
    "without scope options"
  end

  assert(
    actual_scopes.any? { |scope| scope.matches?(policy, type, as, scope_options) },
    "Expected a scoping named :#{as} for :#{type} type " \
    "#{scope_options_message} " \
    "from #{policy} to have been applied, " \
    "but no such scoping has been made.\n" \
    "Registered scopings: " \
    "#{actual_scopes.empty? ? "none" : actual_scopes.map(&:inspect).join(",")}"
  )

  WithScopeTarget.new(actual_scopes)
end