Pundit: Minitest?

Created on 3 Sep 2014  路  6Comments  路  Source: varvet/pundit

Do you have an example of how you would test it with minitest? Or minitest spec?

Most helpful comment

This is how I'm testing my policies using MiniTest. I've created a few helper functions:

# test_helper.rb
def assert_permit(user, record, action)
  msg = "User #{user.inspect} should be permitted to #{action} #{record}, but isn't permitted"
  assert permit(user, record, action), msg
end

def refute_permit(user, record, action)
  msg = "User #{user.inspect} should NOT be permitted to #{action} #{record}, but is permitted"
  refute permit(user, record, action), msg
end

def permit(user, record, action)
  cls = self.class.superclass.to_s.gsub(/Test/, '')
  cls.constantize.new(user, record).public_send("#{action.to_s}?")
end

And then for each policy file:

# post_policy_test.rb
require 'test_helper'

class PostPolicyTest < ActiveSupport::TestCase
  before do
    @account = build_stubbed(:account)
    @administrator = build_stubbed(:administrator, account: @account)
    @employee = build_stubbed(:employee, account: @account)
    @post = build_stubbed(:post, account: @account)
  end

  describe "for an administrator" do
    it { assert_permit @administrator, :post, :index }
    it { assert_permit @administrator, @post, :show }
    it { assert_permit @administrator, @post, :new }
    it { assert_permit @administrator, @post, :create }
    it { assert_permit @administrator, @post, :edit }
    it { assert_permit @administrator, @post, :update }
    it { assert_permit @administrator, @post, :destroy }
  end

  describe "for an employee" do
    it { refute_permit @employee, :post, :index }
    it { refute_permit @employee, @post, :show }
    it { refute_permit @employee, @post, :new }
    it { refute_permit @employee, @post, :create }
    it { refute_permit @employee, @post, :edit }
    it { refute_permit @employee, @post, :update }
    it { refute_permit @employee, @post, :destroy }
  end

  describe "for a guest" do
    it { refute_permit nil, :post, :index }
    it { refute_permit nil, @post, :show }
    it { refute_permit nil, @post, :new }
    it { refute_permit nil, @post, :create }
    it { refute_permit nil, @post, :edit }
    it { refute_permit nil, @post, :update }
    it { refute_permit nil, @post, :destroy }
  end
end

Hope this helps. If anybody has improvements, please share.

All 6 comments

This is how I'm testing my policies using MiniTest. I've created a few helper functions:

# test_helper.rb
def assert_permit(user, record, action)
  msg = "User #{user.inspect} should be permitted to #{action} #{record}, but isn't permitted"
  assert permit(user, record, action), msg
end

def refute_permit(user, record, action)
  msg = "User #{user.inspect} should NOT be permitted to #{action} #{record}, but is permitted"
  refute permit(user, record, action), msg
end

def permit(user, record, action)
  cls = self.class.superclass.to_s.gsub(/Test/, '')
  cls.constantize.new(user, record).public_send("#{action.to_s}?")
end

And then for each policy file:

# post_policy_test.rb
require 'test_helper'

class PostPolicyTest < ActiveSupport::TestCase
  before do
    @account = build_stubbed(:account)
    @administrator = build_stubbed(:administrator, account: @account)
    @employee = build_stubbed(:employee, account: @account)
    @post = build_stubbed(:post, account: @account)
  end

  describe "for an administrator" do
    it { assert_permit @administrator, :post, :index }
    it { assert_permit @administrator, @post, :show }
    it { assert_permit @administrator, @post, :new }
    it { assert_permit @administrator, @post, :create }
    it { assert_permit @administrator, @post, :edit }
    it { assert_permit @administrator, @post, :update }
    it { assert_permit @administrator, @post, :destroy }
  end

  describe "for an employee" do
    it { refute_permit @employee, :post, :index }
    it { refute_permit @employee, @post, :show }
    it { refute_permit @employee, @post, :new }
    it { refute_permit @employee, @post, :create }
    it { refute_permit @employee, @post, :edit }
    it { refute_permit @employee, @post, :update }
    it { refute_permit @employee, @post, :destroy }
  end

  describe "for a guest" do
    it { refute_permit nil, :post, :index }
    it { refute_permit nil, @post, :show }
    it { refute_permit nil, @post, :new }
    it { refute_permit nil, @post, :create }
    it { refute_permit nil, @post, :edit }
    it { refute_permit nil, @post, :update }
    it { refute_permit nil, @post, :destroy }
  end
end

Hope this helps. If anybody has improvements, please share.

ah cool! Looks really nice. Will give it a try

:+1: @pbougie Thanks for sharing!

It comes close to the Gist I found here: https://gist.github.com/promisedlandt/9800713

However I actually prefer your approach. Thank you.

For anybody who has nested describe issues in the future, based on the issue described here and the solution I came up with, if you're having nested describe problems, then try changing your permit method to

def permit(user, record, action)
  test_name = self.class.ancestors.select { |a| a.to_s.match(/PolicyTest/) }.first
  klass = test_name.to_s.gsub(/Test/, '')
  klass.constantize.new(user, record).public_send("#{action.to_s}?")
end

Hope that helps!

Unfortunately this didn't work as expected. My test classes also use a describe block at the top-level (unlike the above example), i.e.

describe PostPolicy do
  ...
end

Therefore my permit() method is as follows:

def permit(user, record, action)
  index = self.class.name.index('Policy')
  klass = self.class.name[0, index+6]
  klass.constantize.new(user, record).public_send("#{action.to_s}?")
end

This solution seems to work for namespaced policies and nested describe blocks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AngelVillanueva picture AngelVillanueva  路  3Comments

murdoch picture murdoch  路  6Comments

lnikkila picture lnikkila  路  5Comments

mattruzicka picture mattruzicka  路  5Comments

jarosluv picture jarosluv  路  6Comments