How can I specify before_filters?

I want to specify my before_filter controllers with rspec. I thought to use ActionController :: Testing :: ClassMethods # before_filters for this.

I got these results in my rails c:

2.0.0p353 :006 > ActionController::Base.singleton_class.send :include, ActionController::Testing::ClassMethods
2.0.0p353 :003 > EquipmentController.before_filters

=> [: process_action ,: process_action]

But actually this is a filter of my action:

class EquipmentController < ApplicationController
  before_filter :authenticate_user!

Any ideas?

+2
source share
5 answers

This is what I did in my project:

# spec/support/matchers/have_filters.rb
RSpec::Matchers.define :have_filters do |kind, *names|
  match do |controller|
    filters = controller._process_action_callbacks.select{ |f| f.kind == kind }.map(&:filter)
    names.all?{ |name| filters.include?(name) }
  end
end

# spec/support/controller_macros.rb
module ControllerMacros
  def has_before_filters *names
    expect(controller).to have_filters(:before, *names)
  end
end

# spec/spec_helper.rb
RSpec.configure do |config|
  config.include ControllerMacros, type: :controller
end

and then you can just use it in controller specifications, for example:

# spec/controllers/application_controller_spec.rb
require 'spec_helper'
describe ApplicationController do
  describe 'class' do
    it { has_before_filters(:authenticate_user) }
  end
end
+7
source

I figured out a method based on the source code of ActionController :: Testing :: ClassMethods # before_filter

This will be my specification:

describe EquipmentController do
  context 'authentication' do
    specify{ expect(EquipmentController).to filter(:before, with: :authenticate_user!, only: :index)}
  end
...

spec/support/matchers/filter.rb

RSpec::Matchers.define :filter do |kind, filter|
  match do |controller|
    extra = -> (x) {true}
    if filter[:except].present?
      extra = -> (x) { x.options[:unless].include?( "action_name == '#{filter[:except]}'") }
    elsif filter[:only].present?
      extra = -> (x) { x.options[:if].include?( "action_name == '#{filter[:only]}'") }
    end
    controller._process_action_callbacks.find{|x|x.kind == kind && x.filter == filter[:with] && extra.call(x)}
  end
end
+7

, , . ,

before_filter :authenticate_user!

, , :authenticate_user! , . -

  • , #authenticate_user! .
  • , , , before_filter, , .

before_filter , :

describe ApplicationController do
    describe 'GET /my_account' do # a method to which the before_filter applies
        subject { get :my_account }

        context 'with a logged-out session' do
            it 'redirects to the homepage' do
                response.should redirect_to root_url
            end
        end

        context 'with a logged-in session' do
            # if you use FactoryGirl and have a spec helper method log_in() to set up the session
            before { log_in(FactoryGirl.create :user) }
            it { should render_template('my_account') } # etc...
        end
    end

    describe 'private #authenticate_user!' do
        subject { ApplicationController.send(:authenticate_user!) }

        it 'calls the authentication logic' do
            Authentication.expects(:attempt_login) # or whatever to verify the internals
            subject
        end
    end
end

, :authenticate_user! . , Rails!

, - . StackOverflow, !

+1

:

  • authenticate_user! , , , , Rails Devise? , . , . .

  • If you want to verify that the method authenticate_user!is being called in the controller, you can do controller.should_receive(:authenticate_user!)in your spec to verify that it is being called.

  • You can also check if EquipmentController is calling before_filter by writing this specification:

EquipmentController.should_receive(:before_filter).with(:authenticate_user!)

0
source

shoulda-matchers gem provides you use_after_action, use_around_actionand use_before_action, which are simple callback checks. No need to write your custom matches.

0
source

All Articles