How to use draper and cancancan? - ruby-on-rails

Trying to use can? method and stub current ability.
class UserDecorator < Draper::Decorator
delegate_all
def some_helper
can? :read, object
end
end
RSpec.describe UserDecorator, type: :decorator do
before { allow(subject).to receive(:current_ability) { Ability.new } }
subject { User.new.decorate }
it { subject.some_helper }
end
But I get error: user does not implement: current_ability.

Related

RSpec for stubbed method inside call

I'm trying test class which is responsible for creating Jira tickets. I want to stub create_issue method which is inside of method call
module JiraTickets
class Creator
def initialize(webhook)
#webhook = webhook
end
def call
create_issue(support_ticket_class, webhook)
end
private
def client
#client ||= JIRA::Client.new
end
def support_ticket_class
#support_ticket_class ||= "SupportBoard::Issues::#{webhook.action_type_class}".constantize
end
def create_issue(support_ticket_class, webhook)
issue = client.Issue.build
issue.save(support_ticket_class.new(webhook).call)
end
def fields
{
'fields' => {
'summary' => 'example.rb',
'project' => { 'id' => '11' },
'issuetype' => { 'id' => '3' }
}
}
end
end
end
The create_issue method should return true. So I've made a specs:
RSpec.describe JiraTickets::Creator do
describe '#call' do
subject { described_class.new(webhook).call }
let(:webhook) { GithubApi::Webhook.new(webhook_hash, 'repository') }
let(:webhook_hash) { { repository: { name: 'Test-repo' }, action: 'publicized' } }
let(:creator_instance) { instance_double(JiraTickets::Creator) }
before do
allow(described_class).to receive(:new).with(webhook).and_return(creator_instance)
allow(creator_instance).to receive(:call).and_return(true)
end
context 'when webhook class is supported' do
it 'expect to create Jira ticket' do
expect(subject).to receive(:call)
end
end
end
end
But I'm getting an error:
Failure/Error: expect(subject).to receive(:call)
true does not implement: call
You just need to check that the method was called on the stub creator_instance
RSpec.describe JiraTickets::Creator do
describe '#call' do
subject { described_class.new(webhook) }
let(:webhook) { GithubApi::Webhook.new(webhook_hash, 'repository') }
let(:webhook_hash) { { repository: { name: 'Test-repo' }, action: 'publicized' } }
before do
allow_any_instance_of(described_class).to receive(:create_issue).with(any_args).and_return(true)
end
context 'when webhook class is supported' do
it 'expects to create Jira ticket' do
expect(subject.call).to eq(true)
end
end
end
end

Undefined method index? pundit testing in Rails

I am using Pundit for authorization in my application with rspec for testing.
require 'rails_helper'
describe SubjectPolicy do
subject { described_class.new(user, subject) }
let(:subject) { Subject.create }
context 'is an administrator' do
let(:role) { Role.create(role_name: 'admin') }
let(:user) { User.create(role_id: role.id) }
it { is_expected.to permit_actions([:index]) }
end
context 'is a teacher' do
let(:role) { Role.create(role_name: 'teacher') }
let(:user) { User.create(role_id: role.id) }
it { is_expected.to forbid_actions([:index]) }
end
end
When running the test for this spec test I receive the following error.
Failure/Error: it { is_expected.to permit_actions([:index]) }
NoMethodError: undefined method 'index?' for #<Subject:0x007fdcc1f70fd0>
There is a route for this index action and it is in my subjects_controller.
The code in the subject policy is very simple.
class SubjectPolicy < ApplicationPolicy
def index?
#user.is_admin?
end
end
Here is the index action in my subjects_controller
def index
#subjects = Subject.all
authorize #subjects
end
I am able to create subjects as an admin, and it does in fact block non-admins from accessing the index. But I am confused as to why this test would fail. I have this policy spec set up just like others and they are passing just fine. Any idea?

Rspec: How to test a controller's around_action filter?

My controller has an around_action filter on its update action, to trigger specific behavior if a particular attribute is updated. Something like below:
class EventsController < ApplicationController
around_action :contact_added_users
def contact_added_users
#event = Event.find(params[:id])
existing_users = #event.users
yield
added_users = #event.users.reject{|u| existing_users.include? u }
added_users.each { |u| u.contact }
end
end
I've verified that it works manually, but how can I test my around_action filter in Rspec? I've tried something like:
describe EventsController do
describe "PUT update" do
let(:event) { FactoryGirl.create(:event) }
let(:old_u) { FactoryGirl.create(:user) }
let(:new_u) { FactoryGirl.create(:user) }
before(:each) { event.users = [ old_u ]
event.save }
context "when adding a user" do
it "contacts newly added user" do
expect(new_u).to receive(:contact)
expect(old_u).not_to receive(:contact)
event_params = { users: [ old_u, new_u ] }
put :update, id: event.id, event: event_params
end
end
...but it fails. Also tried adding
around(:each) do |example|
EventsController.contact_added_users(&example)
end
but still no dice. How can I test this correctly?
I'd suggest stubbing the call to Event and returning a double that can respond to :users with the results you need for the spec to pass. The trick is that :users must be called twice with different results. RSpec allows you to pass a list of values that will be returned for successive calls:
let(:existing_users) { [user_1, user_2] }
let(:added_users) { [user_3] }
let(:event) { double('event') {
before(:each) do
Event.stub(:find).with(params[:id]) { event }
event.should_receive(:users).exactly(2).times.and_return(existing_users, added_users)
end

Draper - NoMethodError with RSpec testing for decorator

I'm receiving the following error when trying to test with Draper:
NoMethodError: undefined method 'with_unit' for nil:NilClass
Here's my test code:
# spec/decorators/food_decorator_spec.rb
require 'spec_helper'
describe FoodDecorator do
before { ApplicationController.new.set_current_view_context }
FactoryGirl.create(:food)
#food = FoodDecorator.first
specify { #food.with_unit('water').should == "85.56 g" }
end
And here's my decorator code:
class FoodDecorator < ApplicationDecorator
decorates :food
def with_unit(nutrient)
model.send(nutrient.to_sym).to_s + " g"
end
end
My research suggests that the line ApplicationController.new.set_current_view_context should fix this, but it hasn't. Any thoughts?
replace with:
require 'spec_helper'
describe FoodDecorator do
before do
ApplicationController.new.set_current_view_context
FactoryGirl.create(:food)
#food = FoodDecorator.first
end
specify { #food.with_unit('water').should == "85.56 g" }
end
You could even do:
require 'spec_helper'
describe FoodDecorator do
let(:food) { Factory(:food) }
subject { FoodDecorator.first }
before do
food
ApplicationController.new.set_current_view_context
end
specify { subject.with_unit('water').should == "85.56 g" }
end

How can I dry helper methods declarations

I have a lot of helpers defined which all basically do the same.
def subtitle(page_subtitle)
content_for(:subtitle) { page_subtitle }
end
def header(page_header)
content_for(:header) { page_header }
end
def auto_header(page_auto_header)
content_for(:auto_header) { page_auto_header }
end
def header_image(page_header_image)
content_for(:header_image) { page_header_image }
end
def bodyclass(page_bodyclass)
content_for(:bodyclass) { page_bodyclass }
end
And there are many more...
My question is how can I DRY this code?
I tried something this but I didn't work
content_for_helpers = ["title","subtitle","logocolor"]
content_for_helpers.each do |helper|
def helper(helper)
content_for(helper.parameterize.underscore.to_sym) { helper }
end
end
def helper what
content_for(what) { send "page_#{what}" }
end

Resources