Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/actionpack/test/controller/new_render_test.rb

Revision 9177, 27.0 kB (checked in by bitsweat, 8 months ago)

Support render :partial => collection of heterogeneous elements. Closes #11491.

Line 
1 require 'abstract_unit'
2 require 'controller/fake_models'
3
4 class CustomersController < ActionController::Base
5 end
6
7 module Fun
8   class GamesController < ActionController::Base
9     def hello_world
10     end
11   end
12 end
13
14 module NewRenderTestHelper
15   def rjs_helper_method_from_module
16     page.visual_effect :highlight
17   end
18 end
19
20 class LabellingFormBuilder < ActionView::Helpers::FormBuilder
21 end
22
23 class NewRenderTestController < ActionController::Base
24   layout :determine_layout
25
26   def self.controller_name; "test"; end
27   def self.controller_path; "test"; end
28
29   def hello_world
30   end
31
32   def render_hello_world
33     render :template => "test/hello_world"
34   end
35
36   def render_hello_world_from_variable
37     @person = "david"
38     render :text => "hello #{@person}"
39   end
40
41   def render_action_hello_world
42     render :action => "hello_world"
43   end
44
45   def render_action_hello_world_as_symbol
46     render :action => :hello_world
47   end
48  
49   def render_text_hello_world
50     render :text => "hello world"
51   end
52  
53   def render_text_hello_world_with_layout
54     @variable_for_layout = ", I'm here!"
55     render :text => "hello world", :layout => true
56   end
57
58   def hello_world_with_layout_false
59     render :layout => false
60   end
61
62   def render_custom_code
63     render :text => "hello world", :status => "404 Moved"
64   end
65
66   def render_file_with_instance_variables
67     @secret = 'in the sauce'
68     path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
69     render :file => path
70   end
71
72   def render_file_with_locals
73     path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
74     render :file => path, :locals => {:secret => 'in the sauce'}
75   end
76
77   def render_file_not_using_full_path
78     @secret = 'in the sauce'
79     render :file => 'test/render_file_with_ivar', :use_full_path => true
80   end
81  
82   def render_file_not_using_full_path_with_dot_in_path
83     @secret = 'in the sauce'
84     render :file => 'test/dot.directory/render_file_with_ivar', :use_full_path => true
85   end
86
87   def render_xml_hello
88     @name = "David"
89     render :template => "test/hello"
90   end
91
92   def greeting
93     # let's just rely on the template
94   end
95
96   def layout_test
97     render :action => "hello_world"
98   end
99
100   def layout_test_with_different_layout
101     render :action => "hello_world", :layout => "standard"
102   end
103  
104   def rendering_without_layout
105     render :action => "hello_world", :layout => false
106   end
107
108   def layout_overriding_layout
109     render :action => "hello_world", :layout => "standard"
110   end
111  
112   def rendering_nothing_on_layout
113     render :nothing => true
114   end
115  
116   def builder_layout_test
117     render :action => "hello"
118   end
119
120   def partials_list
121     @test_unchanged = 'hello'
122     @customers = [ Customer.new("david"), Customer.new("mary") ]
123     render :action => "list"
124   end
125
126   def partial_only
127     render :partial => true
128   end
129
130   def partial_only_with_layout
131     render :partial => "partial_only", :layout => true
132   end
133  
134   def partial_with_locals
135     render :partial => "customer", :locals => { :customer => Customer.new("david") }
136   end
137
138   def partial_with_form_builder
139     render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, @template, {}, Proc.new {})
140   end
141
142   def partial_with_form_builder_subclass
143     render :partial => LabellingFormBuilder.new(:post, nil, @template, {}, Proc.new {})
144   end
145
146   def partial_collection
147     render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ]
148   end
149  
150   def partial_collection_with_spacer
151     render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ]
152   end
153  
154   def partial_collection_with_counter
155     render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ]
156   end
157
158   def partial_collection_with_locals
159     render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" }
160   end
161
162   def partial_collection_shorthand_with_locals
163     render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" }
164   end
165
166   def partial_collection_shorthand_with_different_types_of_records
167     render :partial => [
168         BadCustomer.new("mark"),
169         GoodCustomer.new("craig"),
170         BadCustomer.new("john"),
171         GoodCustomer.new("zach"),
172         GoodCustomer.new("brandon"),
173         BadCustomer.new("dan") ],
174       :locals => { :greeting => "Bonjour" }
175   end
176
177   def partial_collection_shorthand_with_different_types_of_records_with_counter
178     partial_collection_shorthand_with_different_types_of_records
179   end
180
181   def empty_partial_collection
182     render :partial => "customer", :collection => []
183   end
184  
185   def partial_with_hash_object
186     render :partial => "hash_object", :object => {:first_name => "Sam"}
187   end
188  
189   def partial_hash_collection
190     render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ]
191   end
192  
193   def partial_hash_collection_with_locals
194     render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" }
195   end
196  
197   def partial_with_implicit_local_assignment
198     @customer = Customer.new("Marcel")
199     render :partial => "customer"
200   end
201  
202   def missing_partial
203     render :partial => 'thisFileIsntHere'
204   end
205  
206   def hello_in_a_string
207     @customers = [ Customer.new("david"), Customer.new("mary") ]
208     render :text =>  "How's there? " << render_to_string(:template => "test/list")
209   end
210  
211   def render_to_string_with_assigns
212     @before = "i'm before the render"
213     render_to_string :text => "foo"
214     @after = "i'm after the render"
215     render :action => "test/hello_world"
216   end
217
218  def render_to_string_with_partial
219     @partial_only = render_to_string :partial => "partial_only"
220     @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }     
221     render :action => "test/hello_world" 
222   end 
223  
224   def render_to_string_with_exception
225     render_to_string :file => "exception that will not be caught - this will certainly not work", :use_full_path => true
226   end
227  
228   def render_to_string_with_caught_exception
229     @before = "i'm before the render"
230     begin
231       render_to_string :file => "exception that will be caught- hope my future instance vars still work!", :use_full_path => true
232     rescue
233     end
234     @after = "i'm after the render"
235     render :action => "test/hello_world"
236   end
237
238   def accessing_params_in_template
239     render :inline =>  "Hello: <%= params[:name] %>"
240   end
241
242   def accessing_params_in_template_with_layout
243     render :layout => nil, :inline =>  "Hello: <%= params[:name] %>"
244   end
245
246   def render_with_explicit_template
247     render :template => "test/hello_world"
248   end
249
250   def double_render
251     render :text => "hello"
252     render :text => "world"
253   end
254
255   def double_redirect
256     redirect_to :action => "double_render"
257     redirect_to :action => "double_render"
258   end
259
260   def render_and_redirect
261     render :text => "hello"
262     redirect_to :action => "double_render"
263   end
264  
265   def render_to_string_and_render
266     @stuff = render_to_string :text => "here is some cached stuff"
267     render :text => "Hi web users! #{@stuff}"
268   end
269
270   def rendering_with_conflicting_local_vars
271     @name = "David"
272     def @template.name() nil end
273     render :action => "potential_conflicts"
274   end
275
276   def hello_world_from_rxml_using_action
277     render :action => "hello_world_from_rxml.builder"
278   end
279
280   def hello_world_from_rxml_using_template
281     render :template => "test/hello_world_from_rxml.builder"
282   end
283
284   def head_with_location_header
285     head :location => "/foo"
286   end
287
288   def head_with_symbolic_status
289     head :status => params[:status].intern
290   end
291
292   def head_with_integer_status
293     head :status => params[:status].to_i
294   end
295
296   def head_with_string_status
297     head :status => params[:status]
298   end
299
300   def head_with_custom_header
301     head :x_custom_header => "something"
302   end
303
304   def head_with_status_code_first
305     head :forbidden, :x_custom_header => "something"
306   end
307
308   def render_with_location
309     render :xml => "<hello/>", :location => "http://example.com", :status => 201
310   end
311  
312   def render_with_object_location
313     customer = Customer.new("Some guy", 1)
314     render :xml => "<customer/>", :location => customer_url(customer), :status => :created
315   end
316
317   def render_with_to_xml
318     to_xmlable = Class.new do
319       def to_xml
320         "<i-am-xml/>"
321       end
322     end.new
323    
324     render :xml => to_xmlable
325   end
326
327   helper NewRenderTestHelper
328   helper do
329     def rjs_helper_method(value)
330       page.visual_effect :highlight, value
331     end
332   end
333
334   def enum_rjs_test
335     render :update do |page|
336       page.select('.product').each do |value|
337         page.rjs_helper_method_from_module
338         page.rjs_helper_method(value)
339         page.sortable(value, :url => { :action => "order" })
340         page.draggable(value)
341       end
342     end
343   end
344
345   def delete_with_js
346     @project_id = 4
347   end
348
349   def render_js_with_explicit_template
350     @project_id = 4
351     render :template => 'test/delete_with_js'
352   end
353
354   def render_js_with_explicit_action_template
355     @project_id = 4
356     render :action => 'delete_with_js'
357   end
358
359   def update_page
360     render :update do |page|
361       page.replace_html 'balance', '$37,000,000.00'
362       page.visual_effect :highlight, 'balance'
363     end
364   end
365  
366   def update_page_with_instance_variables
367     @money = '$37,000,000.00'
368     @div_id = 'balance'
369     render :update do |page|
370       page.replace_html @div_id, @money
371       page.visual_effect :highlight, @div_id
372     end
373   end
374
375   def action_talk_to_layout
376     # Action template sets variable that's picked up by layout
377   end
378
379   def render_text_with_assigns
380     @hello = "world"
381     render :text => "foo"
382   end
383
384   def yield_content_for
385     render :action => "content_for", :layout => "yield"
386   end
387
388   def render_content_type_from_body
389     response.content_type = Mime::RSS
390     render :text => "hello world!"
391   end
392
393   def render_call_to_partial_with_layout
394     render :action => "calling_partial_with_layout"
395   end
396
397   def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout
398     render :action => "calling_partial_with_layout"
399   end
400
401   def render_using_layout_around_block
402     render :action => "using_layout_around_block"
403   end
404
405   def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
406     render :action => "using_layout_around_block"
407   end
408  
409   def rescue_action(e) raise end
410    
411   private
412     def determine_layout
413       case action_name
414         when "hello_world", "layout_test", "rendering_without_layout",
415              "rendering_nothing_on_layout", "render_text_hello_world",
416              "render_text_hello_world_with_layout",
417              "hello_world_with_layout_false",
418              "partial_only", "partial_only_with_layout",
419              "accessing_params_in_template",
420              "accessing_params_in_template_with_layout",
421              "render_with_explicit_template",
422              "render_js_with_explicit_template",
423              "render_js_with_explicit_action_template",
424              "delete_with_js", "update_page", "update_page_with_instance_variables"
425    
426           "layouts/standard"
427         when "builder_layout_test"
428           "layouts/builder"
429         when "action_talk_to_layout", "layout_overriding_layout"
430           "layouts/talk_from_action"
431         when "render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout"
432           "layouts/partial_with_layout"
433         when "render_using_layout_around_block_in_main_layout_and_within_content_for_layout"
434           "layouts/block_with_layout"
435       end
436     end
437 end
438
439 NewRenderTestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
440 Fun::GamesController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
441
442 class NewRenderTest < Test::Unit::TestCase
443   def setup
444     @controller = NewRenderTestController.new
445
446     # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
447     # a more accurate simulation of what happens in "real life".
448     @controller.logger = Logger.new(nil)
449
450     @request    = ActionController::TestRequest.new
451     @response   = ActionController::TestResponse.new
452
453     @request.host = "www.nextangle.com"
454   end
455
456   def test_simple_show
457     get :hello_world
458     assert_response :success
459     assert_template "test/hello_world"
460     assert_equal "<html>Hello world!</html>", @response.body
461   end
462
463   def test_do_with_render
464     get :render_hello_world
465     assert_template "test/hello_world"
466   end
467
468   def test_do_with_render_from_variable
469     get :render_hello_world_from_variable
470     assert_equal "hello david", @response.body
471   end
472
473   def test_do_with_render_action
474     get :render_action_hello_world
475     assert_template "test/hello_world"
476   end
477
478   def test_do_with_render_action_as_symbol
479     get :render_action_hello_world_as_symbol
480     assert_template "test/hello_world"
481   end
482
483   def test_do_with_render_text
484     get :render_text_hello_world
485     assert_equal "hello world", @response.body
486   end
487
488   def test_do_with_render_text_and_layout
489     get :render_text_hello_world_with_layout
490     assert_equal "<html>hello world, I'm here!</html>", @response.body
491   end
492
493   def test_do_with_render_action_and_layout_false
494     get :hello_world_with_layout_false
495     assert_equal 'Hello world!', @response.body
496   end
497
498   def test_do_with_render_custom_code
499     get :render_custom_code
500     assert_response :missing
501   end
502
503   def test_render_file_with_instance_variables
504     get :render_file_with_instance_variables
505     assert_equal "The secret is in the sauce\n", @response.body
506   end
507
508   def test_render_file_not_using_full_path
509     get :render_file_not_using_full_path
510     assert_equal "The secret is in the sauce\n", @response.body
511   end
512
513   def test_render_file_not_using_full_path_with_dot_in_path
514     get :render_file_not_using_full_path_with_dot_in_path
515     assert_equal "The secret is in the sauce\n", @response.body
516   end
517
518   def test_render_file_with_locals
519     get :render_file_with_locals
520     assert_equal "The secret is in the sauce\n", @response.body
521   end
522
523   def test_attempt_to_access_object_method
524     assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
525   end
526
527   def test_private_methods
528     assert_raises(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout }
529   end
530
531   def test_access_to_request_in_view
532     view_internals_old_value = ActionController::Base.view_controller_internals
533
534     ActionController::Base.view_controller_internals = false
535     ActionController::Base.protected_variables_cache = nil
536
537     get :hello_world
538     assert !assigns.include?('_request'), '_request should not be in assigns'
539     assert !assigns.include?('request'), 'request should not be in assigns'
540
541     ActionController::Base.view_controller_internals = true
542     ActionController::Base.protected_variables_cache = nil
543
544     get :hello_world
545     assert !assigns.include?('request'), 'request should not be in assigns'
546     assert_kind_of ActionController::AbstractRequest, assigns['_request']
547     assert_kind_of ActionController::AbstractRequest, @response.template.request
548
549   ensure
550     ActionController::Base.view_controller_internals = view_internals_old_value
551     ActionController::Base.protected_variables_cache = nil
552   end
553
554   def test_render_xml
555     get :render_xml_hello
556     assert_equal "<html>\n  <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
557   end
558
559   def test_enum_rjs_test
560     get :enum_rjs_test
561     assert_equal <<-EOS.strip, @response.body
562 $$(".product").each(function(value, index) {
563 new Effect.Highlight(element,{});
564 new Effect.Highlight(value,{});
565 Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value)})}});
566 new Draggable(value, {});
567 });
568 EOS
569   end
570
571   def test_render_xml_with_default
572     get :greeting
573     assert_equal "<p>This is grand!</p>\n", @response.body
574   end
575
576   def test_render_with_default_from_accept_header
577     @request.env["HTTP_ACCEPT"] = "text/javascript"
578     get :greeting
579     assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
580   end
581
582   def test_render_rjs_with_default
583     get :delete_with_js
584     assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
585   end
586
587   def test_render_rjs_template_explicitly
588     get :render_js_with_explicit_template
589     assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
590   end
591
592   def test_rendering_rjs_action_explicitly
593     get :render_js_with_explicit_action_template
594     assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
595   end
596
597   def test_layout_rendering
598     get :layout_test
599     assert_equal "<html>Hello world!</html>", @response.body
600   end
601
602   def test_layout_test_with_different_layout
603     get :layout_test_with_different_layout
604     assert_equal "<html>Hello world!</html>", @response.body
605   end
606
607   def test_rendering_without_layout
608     get :rendering_without_layout
609     assert_equal "Hello world!", @response.body
610   end
611
612   def test_layout_overriding_layout
613     get :layout_overriding_layout
614     assert_no_match %r{<title>}, @response.body
615   end
616
617   def test_rendering_nothing_on_layout
618     get :rendering_nothing_on_layout
619     assert_equal " ", @response.body
620   end
621
622   def test_render_xml_with_layouts
623     get :builder_layout_test
624     assert_equal "<wrapper>\n<html>\n  <p>Hello </p>\n<p>This is grand!</p>\n</html>\n</wrapper>\n", @response.body
625   end
626
627   def test_partial_only
628     get :partial_only
629