Skip to content

Instantly share code, notes, and snippets.

@c-vetter
Created April 1, 2011 09:13
Show Gist options
  • Save c-vetter/897922 to your computer and use it in GitHub Desktop.
Save c-vetter/897922 to your computer and use it in GitHub Desktop.
for use with rspec-rails controller specs; avoids duplicate actions that basically differ only in the controller action. note the required spec_helper update
# streamlines request launching to remove duplication
#
# enables this setup:
# describe SomeController do
# describe :index do
# it 'works' do
# should do_something
# launch_request
# response.code.should eq('200')
# end
# end
# end
#
# accepts parameters, session data, flash data like so:
# launch_request :params => {}, :session => {}, :flash => {}
#
# uses POST, PUT, and DELETE for create, update, and destroy requests, respectively, GET otherwise
# set @method in a before(:all) block to override this, like so:
# before(:all){@method = :post}
#
# doesn't care where in the hierarchy the action verb is, thus enabling nested shared example groups
#
# verifies previously set expectations, thus state verification takes place _after_ behaviour verification
# BEWARE: this means calling launch_request twice leads to exceptions
#
# the variant launch_request_without_super makes the action call ignore super
# that is useful in case the application's actions inherit from a gem's actions
# specifying or stubbing what the gem does can be too much hassle
#
#
# put this in spec_helper:
# RSpec.configure do |config|
# config.include RequestLaunching, :type => :controller
# end
#
module RequestLaunching
def launch_request(options={})
method, action = method_and_action
kick_off method, action, options
end
def launch_request_without_super(options={}, &block)
method, action = method_and_action
described_class.ancestors[1].send(:alias_method, :stubbed_out_super, action)
described_class.ancestors[1].send(:define_method, action, block||lambda{})
kick_off method, action, options
described_class.ancestors[1].send(:alias_method, action, :stubbed_out_super)
end
# shortcuts
alias launch launch_request
alias launch_request_with_stubbed_super launch_request_without_super
alias launch_without_super launch_request_without_super
alias launch_with_stubbed_super launch_request_without_super
private
def kick_off(method, action, options)
# prepare data for the launch
parameters = (@params ||{}).merge(options[:params] ||{}) unless options[:params].nil? and @params.nil?
session = (@session ||{}).merge(options[:session] ||{}) unless options[:session].nil? and @session.nil?
flash = (@flash ||{}).merge(options[:flash] ||{}) unless options[:flash].nil? and @flash.nil?
# launch the request with the given options, merged into the related instance variables
if options[:xhr] || @xhr
xml_http_request method,
action,
parameters,
session,
flash
else
__send__ method,
action,
parameters,
session,
flash
end
# verify behaviour expectations
RSpec::Mocks.verify
end
def method_and_action
focus = self.class.instance_variable_get('@metadata')
# find the nearest action verb
while focus = focus[:example_group] do
action = focus[:description] and break if described_class.action_methods.include?(focus[:description])
end
raise "you need to specify an action of #{described_class}" unless action
# find the method corresponding to the action
method = @method || {
'create' => :post,
'update' => :put,
'destroy' => :delete
}[action] || :get
return method, action
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment