Updated Rails to 2.1.0
[gitorious:georgyos-clone.git] / vendor / plugins / rspec_on_rails / lib / spec / rails / example / view_example_group.rb
1 module Spec
2   module Rails
3     module Example
4       # View Examples live in $RAILS_ROOT/spec/views/.
5       #
6       # View Specs use Spec::Rails::Example::ViewExampleGroup,
7       # which provides access to views without invoking any of your controllers.
8       # See Spec::Rails::Expectations::Matchers for information about specific
9       # expectations that you can set on views.
10       #
11       # == Example
12       #
13       #   describe "login/login" do
14       #     before do
15       #       render 'login/login'
16       #     end
17       # 
18       #     it "should display login form" do
19       #       response.should have_tag("form[action=/login]") do
20       #         with_tag("input[type=text][name=email]")
21       #         with_tag("input[type=password][name=password]")
22       #         with_tag("input[type=submit][value=Login]")
23       #       end
24       #     end
25       #   end
26       class ViewExampleGroup < FunctionalExampleGroup
27         before(:each) do
28           ensure_that_flash_and_session_work_properly
29         end
30
31         after(:each) do
32           ensure_that_base_view_path_is_not_set_across_example_groups
33         end
34
35         def initialize(defined_description, &implementation) #:nodoc:
36           super
37           @controller_class_name = "Spec::Rails::Example::ViewExampleGroupController"
38         end
39
40         def ensure_that_flash_and_session_work_properly #:nodoc:
41           @controller.send :initialize_template_class, @response
42           @controller.send :assign_shortcuts, @request, @response
43           @session = @controller.session
44           @controller.class.send :public, :flash
45         end
46
47         def ensure_that_base_view_path_is_not_set_across_example_groups #:nodoc:
48           ActionView::Base.base_view_path = nil
49         end
50
51         def set_base_view_path(options) #:nodoc:
52           ActionView::Base.base_view_path = base_view_path(options)
53         end
54
55         def base_view_path(options) #:nodoc:
56           "/#{derived_controller_name(options)}/"
57         end
58
59         def derived_controller_name(options) #:nodoc:
60           parts = subject_of_render(options).split('/').reject { |part| part.empty? }
61           "#{parts[0..-2].join('/')}"
62         end
63
64         def derived_action_name(options) #:nodoc:
65           parts = subject_of_render(options).split('/').reject { |part| part.empty? }
66           "#{parts.last}"
67         end
68
69         def subject_of_render(options) #:nodoc:
70           [:template, :partial, :file].each do |render_type|
71             if options.has_key?(render_type)
72               return options[render_type]
73             end
74           end
75           return ""
76         end
77
78         def add_helpers(options) #:nodoc:
79           @controller.add_helper("application")
80           @controller.add_helper(derived_controller_name(options))
81           @controller.add_helper(options[:helper]) if options[:helper]
82           options[:helpers].each { |helper| @controller.add_helper(helper) } if options[:helpers]
83         end
84
85         # Renders a template for a View Spec, which then provides access to the result
86         # through the +response+. Also supports render with :inline, which you can
87         # use to spec custom form builders, helpers, etc, in the context of a view.
88         #
89         # == Examples
90         #
91         #   render('/people/list')
92         #   render('/people/list', :helper => MyHelper)
93         #   render('/people/list', :helpers => [MyHelper, MyOtherHelper])
94         #   render(:partial => '/people/_address')
95         #   render(:inline => "<% custom_helper 'argument', 'another argument' %>")
96         #
97         # See Spec::Rails::Example::ViewExampleGroup for more information.
98         def render(*args)
99           options = Hash === args.last ? args.pop : {}
100           options[:template] = args.first.to_s unless args.empty?
101
102           set_base_view_path(options)
103           add_helpers(options)
104
105           assigns[:action_name] = @action_name
106
107           @request.path_parameters = {
108           :controller => derived_controller_name(options),
109           :action => derived_action_name(options)
110           }
111
112           defaults = { :layout => false }
113           options = defaults.merge options
114
115           @controller.instance_variable_set :@params, @request.parameters
116
117           @controller.send :initialize_current_url
118
119           @controller.class.instance_eval %{
120             def controller_path
121               "#{derived_controller_name(options)}"
122             end
123
124             def controller_name
125               "#{derived_controller_name(options).split('/').last}"
126             end
127           }
128
129           @controller.send :forget_variables_added_to_assigns
130           @controller.send :render, options
131           @controller.send :process_cleanup
132         end
133
134         # This provides the template. Use this to set mock
135         # expectations for dealing with partials
136         #
137         # == Example
138         #
139         #   describe "/person/new" do
140         #     it "should use the form partial" do
141         #       template.should_receive(:render).with(:partial => 'form')
142         #       render "/person/new"
143         #     end
144         #   end
145         def template
146           @controller.template
147         end
148
149         Spec::Example::ExampleGroupFactory.register(:view, self)
150
151         protected
152         def _assigns_hash_proxy
153           @_assigns_hash_proxy ||= AssignsHashProxy.new @controller
154         end
155       end
156
157       class ViewExampleGroupController < ApplicationController #:nodoc:
158         include Spec::Rails::Example::RenderObserver
159         attr_reader :template
160
161         def add_helper_for(template_path)
162           add_helper(template_path.split('/')[0])
163         end
164
165         def add_helper(name)
166           begin
167             helper_module = "#{name}_helper".camelize.constantize
168           rescue
169             return
170           end
171           (class << template; self; end).class_eval do
172             include helper_module
173           end
174         end
175       end
176     end
177   end
178 end