module Spec module Rails module Example # View Examples live in $RAILS_ROOT/spec/views/. # # View Specs use Spec::Rails::Example::ViewExampleGroup, # which provides access to views without invoking any of your controllers. # See Spec::Rails::Expectations::Matchers for information about specific # expectations that you can set on views. # # == Example # # describe "login/login" do # before do # render 'login/login' # end # # it "should display login form" do # response.should have_tag("form[action=/login]") do # with_tag("input[type=text][name=email]") # with_tag("input[type=password][name=password]") # with_tag("input[type=submit][value=Login]") # end # end # end class ViewExampleGroup < FunctionalExampleGroup before(:each) do ensure_that_flash_and_session_work_properly end after(:each) do ensure_that_base_view_path_is_not_set_across_example_groups end def initialize(defined_description, options={}, &implementation) #:nodoc: super @controller_class_name = "Spec::Rails::Example::ViewExampleGroupController" end def ensure_that_flash_and_session_work_properly #:nodoc: @controller.send :initialize_template_class, @response @controller.send :assign_shortcuts, @request, @response @session = @controller.session @controller.class.send :public, :flash end def ensure_that_base_view_path_is_not_set_across_example_groups #:nodoc: ActionView::Base.base_view_path = nil end def set_base_view_path(options) #:nodoc: ActionView::Base.base_view_path = base_view_path(options) end def base_view_path(options) #:nodoc: "/#{derived_controller_name(options)}/" end def derived_controller_name(options) #:nodoc: parts = subject_of_render(options).split('/').reject { |part| part.empty? } "#{parts[0..-2].join('/')}" end def derived_action_name(options) #:nodoc: parts = subject_of_render(options).split('/').reject { |part| part.empty? } "#{parts.last}".split('.').first end def subject_of_render(options) #:nodoc: [:template, :partial, :file].each do |render_type| if options.has_key?(render_type) return options[render_type] end end return "" end def add_helpers(options) #:nodoc: @controller.add_helper("application") @controller.add_helper(derived_controller_name(options)) @controller.add_helper(options[:helper]) if options[:helper] options[:helpers].each { |helper| @controller.add_helper(helper) } if options[:helpers] end # Renders a template for a View Spec, which then provides access to the result # through the +response+. Also supports render with :inline, which you can # use to spec custom form builders, helpers, etc, in the context of a view. # # == Examples # # render('/people/list') # render('/people/list', :helper => MyHelper) # render('/people/list', :helpers => [MyHelper, MyOtherHelper]) # render(:partial => '/people/_address') # render(:inline => "<% custom_helper 'argument', 'another argument' %>") # # See Spec::Rails::Example::ViewExampleGroup for more information. def render(*args) options = Hash === args.last ? args.pop : {} options[:template] = args.first.to_s unless args.empty? set_base_view_path(options) add_helpers(options) assigns[:action_name] = @action_name @request.path_parameters = @request.path_parameters.merge( :controller => derived_controller_name(options), :action => derived_action_name(options) ).merge(options[:path_parameters] || {}) defaults = { :layout => false } options = defaults.merge options @controller.send(:params).reverse_merge! @request.parameters @controller.send :initialize_current_url @controller.class.instance_eval %{ def controller_path "#{derived_controller_name(options)}" end def controller_name "#{derived_controller_name(options).split('/').last}" end } @controller.send :forget_variables_added_to_assigns @controller.send :render, options @controller.send :process_cleanup end # This provides the template. Use this to set mock # expectations for dealing with partials # # == Example # # describe "/person/new" do # it "should use the form partial" do # template.should_receive(:render).with(:partial => 'form') # render "/person/new" # end # end def template @controller.template end Spec::Example::ExampleGroupFactory.register(:view, self) protected def _assigns_hash_proxy @_assigns_hash_proxy ||= AssignsHashProxy.new self do @response.template end end end class ViewExampleGroupController < ApplicationController #:nodoc: include Spec::Rails::Example::RenderObserver attr_reader :template def add_helper_for(template_path) add_helper(template_path.split('/')[0]) end def add_helper(name) begin helper_module = "#{name}_helper".camelize.constantize rescue return end (class << template; self; end).class_eval do include helper_module end end def forget_variables_added_to_assigns end end end end end