Pundit: Test policy scope

Created on 12 Mar 2014  路  7Comments  路  Source: varvet/pundit

Hello,

How can i test policy scope with rspect? Can anyone have a tutorial or documentation?

Thanks

Most helpful comment

Since policies are designed to check which records the user has permission to access, I find a readable solution is to test for individual records included in the output. Here's an example of how I might test that the user can only see posts belonging to them:

let(:current_user) { FactoryGirl.create(:user) }
let(:another_user) { FactoryGirl.create(:user) }
let(:current_users_post) { FactoryGirl.create(:post, user: current_user) }
let(:another_users_post) { FactoryGirl.create(:post, user: another_user) }

it "returns posts in scope that belong to the current user" do
  expect(PostPolicy::Scope.new(current_user, Post.all).resolve).to include(current_users_post)
end

it "does not return posts in scope that do not belong to the current user" do
  expect(PostPolicy::Scope.new(current_user, Post.all).resolve).not_to include(another_users_post)
end

All 7 comments

You can try something like that, but a Matcher will be better...

require 'spec_helper'

describe ConsultationPolicy, focused: true do
  let(:consultation) { create :consultation }

  context 'scope' do
    context 'admin' do
      let(:admin) { create :admin }
      specify do
        expect(
          ConsultationPolicy::Scope.new(admin, Consultation).resolve.to_sql
        ).to eq("SELECT \"consultations\".* FROM \"consultations\" ")
      end
    end
    context 'patient' do
      let(:patient) { create :patient }
      specify do
        expect(
          ConsultationPolicy::Scope.new(patient, Consultation).resolve.to_sql
        ).to eq("SELECT \"consultations\".* FROM \"consultations\"  WHERE \"consultations\".\"patient_id\" = #{patient.id}")
      end
    end
  end
end

@joel I wouldn't do that. Testing the generated SQL is super brittle. Just run the query against the DB and see what you get.

Ok, i will try in this way, testing the output.
Thanks joel an jnicklas :).

@jnicklas Yes i'm pretty agree with that and it's strongly coupled to your type of backend, Yes another way is to load one set of data and check what you get.

Here is an example of how I test policy scope:

describe UserPolicy do
  describe ".scope" do
    before { create_list(:user, 2)  } # factory_girl is used here to create test data
    it "contains all" do
      expect(Pundit.policy_scope(current_user, User.all)).to match_array User.all 
    end
  end
end

Just use change User.all to whatever you need.

Since policies are designed to check which records the user has permission to access, I find a readable solution is to test for individual records included in the output. Here's an example of how I might test that the user can only see posts belonging to them:

let(:current_user) { FactoryGirl.create(:user) }
let(:another_user) { FactoryGirl.create(:user) }
let(:current_users_post) { FactoryGirl.create(:post, user: current_user) }
let(:another_users_post) { FactoryGirl.create(:post, user: another_user) }

it "returns posts in scope that belong to the current user" do
  expect(PostPolicy::Scope.new(current_user, Post.all).resolve).to include(current_users_post)
end

it "does not return posts in scope that do not belong to the current user" do
  expect(PostPolicy::Scope.new(current_user, Post.all).resolve).not_to include(another_users_post)
end

It may be worth linking to the popular snippet above ( https://github.com/elabs/pundit/issues/123#issuecomment-51412664 ) from #333 -- I would do it but it's locked, so needs to be someone with permissions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jdwolk picture jdwolk  路  3Comments

linhmtran168 picture linhmtran168  路  3Comments

richjdsmith picture richjdsmith  路  4Comments

mattruzicka picture mattruzicka  路  5Comments

guzart picture guzart  路  4Comments