Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds tests to cover policy overrides and when authorize is called in other namespaces #772

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Pundit

### Added

- Adds tests to cover policy overrides and when authorize is called in other namespaces (#772)

## Unreleased

### Fixed
Expand Down
73 changes: 73 additions & 0 deletions spec/authorization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
let(:post) { Post.new(user) }
let(:customer_post) { Customer::Post.new(user) }
let(:comment) { Comment.new }
let(:admin_post) { Project::Admin::Post.new(user) }
let(:article) { Article.new }
let(:article_tag) { ArticleTag.new }
let(:wiki) { Wiki.new }
Expand Down Expand Up @@ -116,6 +117,39 @@
it "raises an error with a invalid policy constructor" do
expect { controller.authorize(wiki, :destroy?) }.to raise_error(Pundit::InvalidConstructorError)
end

context "when passed a record with the admin namespace" do
it "returns the record when the permission check passes" do
allow(controller).to receive(:authorize).with(admin_post, :update?).and_return(admin_post)
expect(controller.authorize(admin_post, :update?)).to eq(admin_post)
end
TheDevJoao marked this conversation as resolved.
Show resolved Hide resolved

it "raises an exception when the permission check fails" do
allow(controller).to receive(:authorize).with(admin_post, :update?).and_raise(Pundit::NotAuthorizedError)
expect { controller.authorize(admin_post, :update?) }.to raise_error(Pundit::NotAuthorizedError)
end
end

context "when called in a controller" do
let(:controller) { Controller.new(user, "update", {}) }

before do
allow(controller).to receive(:kind_of?).with(Controller).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
end

it "uses the Admin namespace for policy calls" do
expect(controller).to receive(:authorize).with(admin_post, :update?).and_return(admin_post)
expect(controller.authorize(admin_post, :update?)).to eq(admin_post)
end

it "allows overriding the policy class" do
allow(controller).to receive(:policy_class).and_return(Project::Admin::CommentPolicy)
expect(controller).to receive(:authorize).with(admin_post, :update?,
policy_class: Project::Admin::Post).and_return(admin_post)
expect(controller.authorize(admin_post, :update?, policy_class: Project::Admin::Post)).to eq(admin_post)
end
end
end

describe "#skip_authorization" do
Expand Down Expand Up @@ -159,6 +193,45 @@

expect(controller.policy(post)).to eq new_policy
end

context "when the policy is overriden" do
before do
allow(controller).to receive(:policy) do |record|
case record
when Post
PostPolicy.new(user, record)
when Blog
BlogPolicy.new(user, record)
else
raise Pundit::NotDefinedError, "Policy not defined for record: #{record.class}"
end
end
end

it "returns the correct overriden policy for a Post record" do
post = Post.new(user)

policy = controller.policy(post)
expect(policy).to be_instance_of(PostPolicy)
expect(policy.user).to eq(user)
expect(policy.post).to eq(post)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This context says "when the policy is overridden", but it doesn't look like anything is being overriden? What's the "policy" which is being overridden (do you mean the policy method, or the Policy class?), and where is it overridden?

I see there are some new things added in the spec_helper but none of those override policy_class, authorize, policy, Post or PostPolicy, so this spec looks like it just tests that ::PostPolicy works - nothing to do with any overriding?

What am I missing?

If I understand it correctly, the "overriding" which the original issue was talking about defining policy or authorize in a specific controller - eg. in an admin controller you might want to do something like this:

  def authorize(record, query = nil)
    super([:admin, record], query)
  end

  def policy(record)
    super([:admin, record])
  end 

...to make sure that calls to authorize(Post) and policy(Post) in that controller end using the Admin::PostPolicy instead of ::PostPolicy.

I'm actually using this exact override of authorize in my current project.

end

it "returns the correct overriden policy for a Blog record" do
blog = Blog.new

policy = controller.policy(blog)
expect(policy).to be_instance_of(BlogPolicy)
expect(policy.user).to eq(user)
expect(policy.blog).to eq(blog)
end

it "raises an error if the given policy can't be found" do
record = Article.new

expect { controller.policy(record) }.to raise_error(Pundit::NotDefinedError)
end
end
end

describe "#policy_scope" do
Expand Down
10 changes: 10 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ def destroy?
false
end
end

class Post < Post
def model_name
OpenStruct.new(param_key: "admin_post")
end

def self.policy_class
PostPolicy
end
end
end
end

Expand Down