Add CallbackMatcher for ActionController

Matcher for checking if a filter / action callback is in place within a
controller.

Example:

```ruby
describe UserController do
  it { should use_before_filter(:authenticate_user!) }
end
```
This commit is contained in:
Damian Galarza and Harry Schwartz 2014-01-31 17:06:49 -05:00 committed by Damian Galarza
parent fb77a6c310
commit b5083467bc
4 changed files with 221 additions and 1 deletions

View File

@ -909,7 +909,7 @@ end
### ActionController Matchers
*Jump to: [filter_param](#filter_param), [redirect_to](#redirect_to), [render_template](#render_template), [render_with_layout](#render_with_layout), [rescue_from](#rescue_from), [respond_with](#respond_with), [route](#route), [set_session](#set_session), [set_the_flash](#set_the_flash)*
*Jump to: [filter_param](#filter_param), [redirect_to](#redirect_to), [render_template](#render_template), [render_with_layout](#render_with_layout), [rescue_from](#rescue_from), [respond_with](#respond_with), [route](#route), [set_session](#set_session), [set_the_flash](#set_the_flash), [use_after_filter](#use_after_filter), [use_before_filter](#use_before_filter)*
#### filter_param
@ -1251,6 +1251,46 @@ class PostsControllerTest < ActionController::TestCase
end
```
#### use_after_filter
The `use_after_filter` ensures a given `after_filter` is used.
```ruby
class UserController < ActionController::Base
after_filter :log_activity
end
# RSpec
describe UserController do
it { should use_after_filter(:log_activity) }
end
# Test::Unit
class UserControllerTest < ActionController::TestCase
should use_after_filter(:log_activity)
end
```
#### use_before_filter
The `use_before_filter` ensures a given `before_filter` is used.
```ruby
class UserController < ActionController::Base
before_filter :authenticate_user!
end
# RSpec
describe UserController do
it { should use_before_filter(:authenticate_user!) }
end
# Test::Unit
class UserControllerTest < ActionController::TestCase
should use_before_filter(:authenticate_user!)
end
```
## Versioning
shoulda-matchers follows Semantic Versioning 2.0 as defined at

View File

@ -8,6 +8,7 @@ require 'shoulda/matchers/action_controller/route_matcher'
require 'shoulda/matchers/action_controller/redirect_to_matcher'
require 'shoulda/matchers/action_controller/render_template_matcher'
require 'shoulda/matchers/action_controller/rescue_from_matcher'
require 'shoulda/matchers/action_controller/callback_matcher'
module Shoulda
module Matchers

View File

@ -0,0 +1,100 @@
module Shoulda # :nodoc:
module Matchers
module ActionController # :nodoc:
# Ensure a controller uses a given before_filter
#
# Example:
#
# it { should use_before_filter(:authenticate_user!) }
# it { should_not use_before_filter(:prevent_ssl) }
def use_before_filter(callback)
CallbackMatcher.new(callback, :before, :filter)
end
# Ensure a controller uses a given before_filter
#
# Example:
#
# it { should use_after_filter(:log_activity) }
# it { should_not use_after_filter(:destroy_user) }
def use_after_filter(callback)
CallbackMatcher.new(callback, :after, :filter)
end
# Ensure a controller uses a given before_action
#
# Example:
#
# it { should use_before_action(:authenticate_user!) }
# it { should_not use_before_action(:prevent_ssl) }
def use_before_action(callback)
CallbackMatcher.new(callback, :before, :action)
end
# Ensure a controller uses a given after_action
#
# Example:
#
# it { should use_after_action(:log_activity) }
# it { should_not use_after_action(:destroy_user) }
def use_after_action(callback)
CallbackMatcher.new(callback, :after, :action)
end
# Ensure a controller uses a given around_filter
#
# Example:
#
# it { should use_around_filter(:log_activity) }
# it { should_not use_around_filter(:destroy_user) }
def use_around_filter(callback)
CallbackMatcher.new(callback, :around, :filter)
end
# Ensure a controller uses a given around_action
#
# Example:
#
# it { should use_around_action(:log_activity) }
# it { should_not use_around_action(:destroy_user) }
def use_around_action(callback)
CallbackMatcher.new(callback, :around, :action)
end
class CallbackMatcher # :nodoc:
def initialize(method_name, kind, callback_type)
@method_name = method_name
@kind = kind
@callback_type = callback_type
end
def matches?(subject)
@subject = subject
callbacks.map(&:filter).include?(method_name)
end
def failure_message
"Expected that #{subject.name} would have :#{method_name} as a #{kind}_#{callback_type}"
end
alias failure_message_for_should failure_message
def failure_message_when_negated
"Expected that #{subject.name} would not have :#{method_name} as a #{kind}_#{callback_type}"
end
alias failure_message_for_should_not failure_message_when_negated
def description
"have :#{method_name} as a #{kind}_#{callback_type}"
end
private
def callbacks
subject._process_action_callbacks.select { |callback| callback.kind == kind }
end
attr_reader :method_name, :subject, :kind, :callback_type
end
end
end
end

View File

@ -0,0 +1,79 @@
require 'spec_helper'
describe Shoulda::Matchers::ActionController::CallbackMatcher do
shared_examples 'CallbackMatcher' do |kind, callback_type|
let(:matcher) { described_class.new(:authenticate_user!, kind, callback_type) }
let(:controller) { define_controller('HookController') }
describe '#matches?' do
it "matches when a #{kind} hook is in place" do
add_callback(kind, callback_type, :authenticate_user!)
expect(matcher.matches?(controller)).to be_true
end
it "does not match when a #{kind} hook is missing" do
expect(matcher.matches?(controller)).to be_false
end
end
describe 'description' do
it 'includes the filter kind and name' do
expect(matcher.description).to eq "have :authenticate_user! as a #{kind}_#{callback_type}"
end
end
describe 'failure message' do
it 'includes the filter kind and name that was expected' do
message = "Expected that HookController would have :authenticate_user! as a #{kind}_#{callback_type}"
expect {
expect(controller).to send("use_#{kind}_#{callback_type}", :authenticate_user!)
}.to fail_with_message(message)
end
end
describe 'failure message when negated' do
it 'includes the filter kind and name that was expected' do
add_callback(kind, callback_type, :authenticate_user!)
message = "Expected that HookController would not have :authenticate_user! as a #{kind}_#{callback_type}"
expect {
expect(controller).not_to send("use_#{kind}_#{callback_type}", :authenticate_user!)
}.to fail_with_message(message)
end
end
private
def add_callback(kind, callback_type, callback)
controller.send("#{kind}_#{callback_type}", callback)
end
end
describe '#use_before_filter' do
it_behaves_like 'CallbackMatcher', :before, :filter
end
describe '#use_after_filter' do
it_behaves_like 'CallbackMatcher', :after, :filter
end
describe '#use_around_filter' do
it_behaves_like 'CallbackMatcher', :around, :filter
end
if rails_4_x?
describe '#use_before_action' do
it_behaves_like 'CallbackMatcher', :before, :action
end
describe '#use_after_action' do
it_behaves_like 'CallbackMatcher', :after, :action
end
describe '#use_around_action' do
it_behaves_like 'CallbackMatcher', :around, :action
end
end
end