Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I spec before_filters?

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

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 in reality this is the filter on my action:

class EquipmentController < ApplicationController
  before_filter :authenticate_user!

Any ideas?

like image 374
Boti Avatar asked Dec 01 '22 19:12

Boti


2 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 specs like:

# spec/controllers/application_controller_spec.rb
require 'spec_helper'
describe ApplicationController do
  describe 'class' do
    it { has_before_filters(:authenticate_user) }
  end
end
like image 86
Bart Avatar answered Dec 06 '22 17:12

Bart


I figured out a way based on the source code from the ActionController::Testing::ClassMethods#before_filter

This will be my spec:

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

This is my matcher in 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
like image 34
Boti Avatar answered Dec 06 '22 18:12

Boti