module Goma # Goma::ControllerTestHelpers provides a facility to test controllers in isolation # Most of the code was extracted from Devise's Devise::TestHelpers. module ControllerTestHelpers def self.included(base) base.class_eval do setup :setup_controller_for_warden, :warden if respond_to?(:setup) end end # Override process to consider warden. def process(*) # Make sure we always return @response, a la ActionController::TestCase::Behavior#process, even if warden interrupts _catch_warden {super} || @response end # We need to setup the environment variables and the response in the controller def setup_controller_for_warden @request.env['action_controller.instance'] = @controller end # Quick access to Warden::Proxy. def warden @warden ||= begin manager = Warden::Manager.new(nil, &Rails.application.config.middleware.detect{|m| m.name == 'Warden::Manager'}.block) @request.env['warden'] = Warden::Proxy.new(@request.env, manager) end end protected # Catch warden continuations and handle like the middleware would. # Returns nil when interrupted, otherwise the normal result of the block. def _catch_warden(&block) result = catch(:warden, &block) if result.is_a?(Hash) && !warden.custom_failure? && !@controller.send(:performed?) result[:action] ||= :unauthenticated env = @controller.request.env env['PATH_INFO'] = "/#{result[:action]}" env['warden.options'] = result Warden::Manager._run_callbacks(:before_failure, env, result) status, headers, body = warden.config[:failure_app].call(env).to_a @controller.send :render, :status => status, :text => body, :content_type => headers['Content-Type'], :location => headers['Location'] nil else result end end def method_missing(m, *args) name = m.to_s if name =~ /^(?:(#{Goma.config.scopes.join('|')})_)?(?:login!?|logout|logged_in\?)$/ || name == 'force_login' || name =~ /^current_(#{Goma.config.scopes.join('|')})$/ @controller.send(m, *args) else super end end end end