3

I have tests setup for Pundit no problem using:

https://github.com/ksimmons/policy-assertions

In my case I have my Pundit / Devise system supplemented with an enrollment type system to add roles etc.

When I test my controllers I want to skip the entire Devise / Pundit system entirely and focus on just the controller logic and not look at authorization which I will handle in my policy tests.

I am looking something like this (http://www.colorfultyping.com/disabling-devise-for-rails-integration-testing/#comment-4718) but I can't get it to work.

Dan Tappin
  • 2,692
  • 3
  • 37
  • 77
  • I think the key is the fact that 'authorize' is getting called in the controllers. I tried even disabling Pundit by commenting out ':verify_authorized' in my application controller. I want to have Pundit always authorize when I test except when I am testing the actual policies. – Dan Tappin Mar 12 '17 at 05:26
  • My workaround my be to just use the user fixture that has superuser permissions - this way Pundit always authorizes. – Dan Tappin Mar 12 '17 at 05:29

1 Answers1

1

In order to skip the Pundit authorization within controllers you need to stub out the Policy class' new method to return a placeholder / mock object that responds with true for the action policy in the action that is being tested; e.g. for FooController my FooPolicy returns a new instance of itself that returns true when its action policy index? is called within the index controller action.

For Minitest it looks something like this

# - Minitest -
foo_policy = MiniTest::Mock.new
foo_policy.expect :index?, true

FooPolicy.stub :new, foo_policy do
  # your controller action test
end

You will create a mock object that will fulfil the role of Policy's new instance object within the Controller action, and return that mock object if the Policy's new method is called within the scope of its block during a test.

If you using Mocha, I believe the following will work also to achieve the same as above, but without the need to specific the test assetion within its block.

# - Mocha -
foo_policy = mock("foo_policy")
foo_policy.expects(:index?).returns(true)

FooPolicy.any_instance.stubs(:new).returns(foo_policy)

Also, you can achieve a similar mock object with mock = Object.new and stub method by defining a method for the mock inline like def mock.index?. This also applies to existing classes, since Ruby allows you to redeclare a method for a Class inline like so def FooPolicy.new and only persists within the scope of the test. Knowing this we can have def FooPolicy.new and have return our mock like in the following

# - Without a Test-framework -
foo_policy = Object.new # create a mock / double
def foo_policy.index?; true; end # stub a method

def FooPolicy.new # stub Policyclass to return double with stubbed method
  foo_policy = Object.new
  def foo_policy.index?; true; end
  foo_policy
end

For completeness, I use RSpec and use the folllowing to stub out my Pundit Polices within my controller actions

# - Rspec -
foo_policy = instance_double("policy", index?: true)
allow(FooPolicy).to receive(:new).and_return(foo_policy)

As for Devise I use the following support test helpers and only include them for Controller and Requests tests that require an User to sign_in before a test:

module DeviseRequestSpecHelpers
  include Warden::Test::Helpers

  def sign_in(resource_or_scope, resource = nil)
    resource ||= resource_or_scope
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    login_as(resource, scope: scope)
  end

  def sign_out(resource_or_scope)
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    logout(scope)
  end
end

See Module: Warden::Test::Helpers — Documentation for hassox/warden (master) for more information on Warden::Test::Helpers module

This is because Warden is used within Devise that its Test Helpers are used. This Warden::Test::Helpers module when included switches Warden into its test_mode! and its login_as method will set your user object as the current_user for the purposes of testing with Devise being used in your application.

References:

sonna
  • 600
  • 4
  • 10