x6iae
x6iae

Reputation: 4164

Testing cancancan abilities with rspec

I am trying to test my cancancan abilities using rspec

but as opposed to testing for what a particular user can do, I am trying to test for what a user should not be able to do.

Now, I have a block of context like so:

context "for a manager" do
  before do
    @manager = FactoryGirl.build(:user, :manager)
    @ability = Ability.new(@manager)
  end

  it "should not be able to create Questions" do
    expect(@ability).not_to be_able_to(:create, Question.new)
  end

  it "should not be able to read Questions" do
    expect(@ability).not_to be_able_to(:read, Question.new)
  end

  it "should not be able to update Questions" do
    expect(@ability).not_to be_able_to(:update, Question.new)
  end

  it "should not be able to delete Questions" do
    expect(@ability).not_to be_able_to(:destroy, Question.new)
  end
end

This clearly shows that a user of type manager should not have any form of access to the Question model.

Is there a direct way to write this whole block in a single it block, with only one expect?

I have thought about writing it as follow:

context "for a manager" do
  before do
    @manager = FactoryGirl.build(:user, :manager)
    @ability = Ability.new(@manager)
  end

  it "should not be able to manage Questions" do
    expect(@ability).not_to be_able_to(:manage, Question.new)
  end
end

But I'm thinking that this may not necessarily do what I'm intending it to do, as this test will pass is as much as one of the ability for that resource is not granted.

So, in short, is there a direct way to test such scenarios? Thanks to all.

Upvotes: 1

Views: 3740

Answers (1)

Nuno Costa
Nuno Costa

Reputation: 1250

First of all, I advise you to use an explicit subject for @ability so you can use the one-liner syntax like in the example below.

describe Role do
  subject(:ability){ Ability.new(user) }
  let(:user){ FactoryGirl.build(:user, roles: [role]) }

  context "when is a manager" do
    let(:role){ FactoryGirl.build(:manager_role) }

    it{ is_expected.not_to be_able_to(:create, Question.new) }
    it{ is_expected.not_to be_able_to(:read, Question.new) }
    it{ is_expected.not_to be_able_to(:update, Question.new) }
    it{ is_expected.not_to be_able_to(:destroy, Question.new) }
  end
end

Updated after your comment

But you can also summarize all this 4 expectations to simply

%i[create read update destroy].each do |role|
  it{ is_expected.not_to be_able_to(role, Question.new) }
end

Upvotes: 7

Related Questions