# frozen_string_literal: true require "abstract_unit" require "controller/fake_models" require "test_renderable" require "active_model/validations" class TestController < ActionController::Base end module RenderTestCases def setup_view(paths) @assigns = { secret: "in the sauce" } @view = Class.new(ActionView::Base.with_empty_template_cache) do def view_cache_dependencies; []; end def combined_fragment_cache_key(key) [ :views, key ] end end.with_view_paths(paths, @assigns) controller = TestController.new controller.perform_caching = true controller.cache_store = :memory_store @view.controller = controller @controller_view = controller.view_context_class.with_empty_template_cache.new( controller.lookup_context, controller.view_assigns, controller) # Reload and register danish language for testing I18n.backend.store_translations "da", {} I18n.backend.store_translations "pt-BR", {} # Ensure original are still the same since we are reindexing view paths assert_equal ORIGINAL_LOCALES, I18n.available_locales.map(&:to_s).sort end def teardown I18n.reload! ActionController::Base.view_paths.map(&:clear_cache) end def test_implicit_format_comes_from_parent_template rendered_templates = JSON.parse(@controller_view.render(template: "test/mixing_formats")) assert_equal({ "format" => "HTML", "children" => ["XML", "HTML"] }, rendered_templates) end def test_implicit_format_comes_from_parent_template_cascading rendered_templates = JSON.parse(@controller_view.render(template: "test/mixing_formats_deep")) assert_equal({ "format" => "HTML", "children" => [ { "format" => "XML", "children" => ["XML"] }, { "format" => "HTML", "children" => ["HTML"] }, ] }, rendered_templates) end def test_explicit_js_format_adds_html_fallback rendered_templates = @controller_view.render(template: "test/js_html_fallback", formats: :js) assert_equal(%Q(document.write("Hello from a HTML partial!<\\/b>")\n), rendered_templates) end def test_render_without_options e = assert_raises(ArgumentError) { @view.render() } assert_match(/You invoked render but did not give any of (.+) option\./, e.message) end def test_render_template assert_equal "Hello world!", @view.render(template: "test/hello_world") end def test_render_file template_path = File.expand_path("../fixtures/test/hello_world.erb", __dir__) assert_equal "Hello world!", @view.render(file: template_path) end def test_render_file_with_full_path_no_extension template_path = File.expand_path("../fixtures/test/hello_world", __dir__) assert_raise(ArgumentError) { @view.render(file: template_path) } end # Test if :formats, :locale etc. options are passed correctly to the resolvers. def test_render_template_with_format assert_match "

No Comment

", @view.render(template: "comments/empty", formats: [:html]) assert_match "No Comment", @view.render(template: "comments/empty", formats: [:xml]) assert_match "No Comment", @view.render(template: "comments/empty", formats: :xml) end def test_render_partial_implicitly_use_format_of_the_rendered_template @view.lookup_context.formats = [:json] assert_equal "Hello world", @view.render(template: "test/one", formats: [:html]) end def test_render_partial_implicitly_use_format_of_the_rendered_partial @view.lookup_context.formats = [:html] assert_equal "Third level", @view.render(template: "test/html_template") end def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names @view.lookup_context.formats = [:html] assert_equal "\nHTML Template, but HTML partial", @view.render(template: "test/change_priority") end def test_render_template_with_a_missing_partial_of_another_format @view.lookup_context.formats = [:html] e = assert_raise ActionView::Template::Error do @view.render(template: "with_format", formats: [:json]) end assert_includes(e.message, "Missing partial /_missing with {:locale=>[:en], :formats=>[:json], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby]}.") end def test_render_template_with_locale assert_equal "

Kein Kommentar

", @view.render(template: "comments/empty", locale: [:de]) assert_equal "

Kein Kommentar

", @view.render(template: "comments/empty", locale: :de) end def test_render_template_with_variants assert_equal "

No Comment

\n", @view.render(template: "comments/empty", variants: :grid) end def test_render_template_with_handlers assert_equal "

No Comment

\n", @view.render(template: "comments/empty", handlers: [:builder]) assert_equal "

No Comment

\n", @view.render(template: "comments/empty", handlers: :builder) end def test_render_raw_template_with_handlers assert_equal "<%= hello_world %>\n", @view.render(template: "plain_text") end def test_render_raw_template_with_quotes assert_equal %q;Here are some characters: !@#$%^&*()-="'}{`; + "\n", @view.render(template: "plain_text_with_characters") end def test_render_raw_is_html_safe_and_does_not_escape_output buffer = ActiveSupport::SafeBuffer.new buffer << @view.render(template: "plain_text") assert_equal true, buffer.html_safe? assert_equal buffer, "<%= hello_world %>\n" end def test_render_ruby_template_with_handlers assert_equal "Hello from Ruby code", @view.render(template: "ruby_template") end def test_render_ruby_template_inline assert_equal "4", @view.render(inline: "(2**2).to_s", type: :ruby) end def test_render_template_via_symbol_lookup assert_equal "Hello from Ruby code", @view.render(template: :ruby_template) end def test_render_template_with_localization_on_context_level old_locale, @view.locale = @view.locale, :da assert_equal "Hey verden", @view.render(template: "test/hello_world") ensure @view.locale = old_locale end def test_render_template_with_dashed_locale old_locale, @view.locale = @view.locale, :"pt-BR" assert_equal "Ola mundo", @view.render(template: "test/hello_world") ensure @view.locale = old_locale end def test_render_template_at_top_level assert_equal "Elastica", @view.render(template: "/shared") end def test_render_template_with_instance_variable assert_equal "The secret is in the sauce\n", @view.render(template: "test/render_template_with_ivar") end def test_render_template_with_locals locals = { secret: "in the sauce" } assert_equal "The secret is in the sauce\n", @view.render(template: "test/render_template_with_locals", locals: locals) end def test_render_template_with_dot_in_path assert_equal "The secret is in the sauce\n", @view.render(template: "test/dot.directory/render_template_with_ivar") end def test_render_partial_from_default assert_equal "only partial", @view.render("test/partial_only") end def test_render_outside_path assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__)) assert_raises ActionView::MissingTemplate do assert_deprecated do @view.render(template: "../\\../test/abstract_unit.rb") end end end def test_render_partial assert_equal "only partial", @view.render(partial: "test/partial_only") end def test_render_partial_with_format assert_equal "partial html", @view.render(partial: "test/partial") end def test_render_partial_with_variants assert_equal "

Partial with variants

\n", @view.render(partial: "test/partial_with_variants", variants: :grid) end def test_render_partial_with_selected_format assert_equal "partial html", @view.render(partial: "test/partial", formats: :html) assert_equal "partial js", @view.render(partial: "test/partial", formats: [:js]) end def test_render_partial_at_top_level # file fixtures/_top_level_partial_only (not fixtures/test) assert_equal "top level partial", @view.render(partial: "/top_level_partial_only") end def test_render_partial_with_format_at_top_level # file fixtures/_top_level_partial.html (not fixtures/test, with format extension) assert_equal "top level partial html", @view.render(partial: "/top_level_partial") end def test_render_partial_with_locals assert_equal "5", @view.render(partial: "test/counter", locals: { counter_counter: 5 }) end def test_render_partial_with_locals_from_default assert_equal "only partial", @view.render("test/partial_only", counter_counter: 5) end def test_render_partial_with_number assert_nothing_raised { @view.render(partial: "test/200") } end def test_render_partial_with_missing_filename assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/") } end def test_render_partial_with_incompatible_object e = assert_raises(ArgumentError) { @view.render(partial: nil) } assert_equal "'#{nil.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.", e.message end def test_render_partial_starting_with_a_capital assert_nothing_raised { @view.render(partial: "test/FooBar") } end def test_render_partial_with_hyphen assert_nothing_raised { @view.render(partial: "test/a-in") } end def test_render_partial_with_unicode_text assert_nothing_raised { @view.render(partial: "test/🍣") } end def test_render_partial_with_invalid_option_as e = assert_raises(ArgumentError) { @view.render(partial: "test/partial_only", as: "a-in", object: nil) } assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " \ "make sure it starts with lowercase letter, " \ "and is followed by any combination of letters, numbers and underscores.", e.message end def test_render_partial_with_hyphen_and_invalid_option_as e = assert_raises(ArgumentError) { @view.render(partial: "test/a-in", as: "a-in", object: nil) } assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " \ "make sure it starts with lowercase letter, " \ "and is followed by any combination of letters, numbers and underscores.", e.message end def test_render_template_with_syntax_error e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/syntax_error") } assert_match %r!syntax!, e.message assert_equal "1: <%= foo(", e.annotated_source_code[0].strip end def test_render_partial_with_errors e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise") } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number assert_equal "1: <%= doesnt_exist %>", e.annotated_source_code[0].strip assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end def test_render_error_indentation e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise_indentation") } error_lines = e.annotated_source_code assert_match %r!error\shere!, e.message assert_equal "11", e.line_number assert_equal " 9:

Ninth paragraph

", error_lines.second assert_equal " 10:

Tenth paragraph

", error_lines.third end def test_render_template_with_errors e = assert_raises(ActionView::Template::Error) { assert_deprecated { @view.render(template: "test/_raise") } } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number assert_equal "1: <%= doesnt_exist %>", e.annotated_source_code[0].strip assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end def test_render_sub_template_with_errors e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/sub_template_raise") } assert_match %r!method.*doesnt_exist!, e.message assert_match %r{Trace of template inclusion: .*test/sub_template_raise\.html\.erb}, e.sub_template_message assert_equal "1", e.line_number assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end def test_undefined_method_error_references_named_class e = assert_raises(ActionView::Template::Error) { @view.render(inline: "<%= undefined %>") } assert_match(/`undefined' for #/, e.message) end def test_render_renderable_object assert_equal "Hello: david", @view.render(partial: "test/customer", object: Customer.new("david")) assert_equal "FalseClass", @view.render(partial: "test/klass", object: false) assert_equal "NilClass", @view.render(partial: "test/klass", object: nil) end def test_render_object_different_name assert_equal "Hello: t.lo", @view.render(partial: "test/template_not_named_customer", object: Customer.new("t.lo"), as: "customer").chomp end def test_render_object_with_array assert_equal "[1, 2, 3]", @view.render(partial: "test/object_inspector", object: [1, 2, 3]) end def test_render_partial_collection assert_equal "Hello: davidHello: mary", @view.render(partial: "test/customer", collection: [ Customer.new("david"), Customer.new("mary") ]) end def test_render_partial_collection_as_by_string assert_equal "david david davidmary mary mary", @view.render(partial: "test/customer_with_var", collection: [ Customer.new("david"), Customer.new("mary") ], as: "customer") end def test_render_partial_collection_as_by_symbol assert_equal "david david davidmary mary mary", @view.render(partial: "test/customer_with_var", collection: [ Customer.new("david"), Customer.new("mary") ], as: :customer) end def test_render_partial_collection_without_as assert_equal "local_inspector,local_inspector_counter,local_inspector_iteration", @view.render(partial: "test/local_inspector", collection: [ Customer.new("mary") ]) end def test_render_partial_collection_with_different_partials_still_provides_partial_iteration a = {} b = {} def a.to_partial_path; "test/partial_iteration_1"; end def b.to_partial_path; "test/partial_iteration_2"; end assert_equal "local-variable\nlocal-variable", @controller_view.render([a, b]) end def test_render_partial_with_empty_collection_should_return_nil assert_nil @view.render(partial: "test/customer", collection: []) end def test_render_partial_with_nil_collection_should_return_nil assert_nil @view.render(partial: "test/customer", collection: nil) end def test_render_partial_collection_for_non_array customers = Enumerator.new do |y| y.yield(Customer.new("david")) y.yield(Customer.new("mary")) end assert_equal "Hello: davidHello: mary", @view.render(partial: "test/customer", collection: customers) end def test_without_compiled_method_container_is_deprecated view = ActionView::Base.with_view_paths(ActionController::Base.view_paths) assert_raises(NotImplementedError) do assert_equal "Hello world!", view.render(template: "test/hello_world") end end def test_render_partial_without_object_does_not_put_partial_name_to_local_assigns assert_equal "false", @view.render(partial: "test/partial_name_in_local_assigns") end def test_render_partial_with_nil_object_puts_partial_name_to_local_assigns assert_equal "true", @view.render(partial: "test/partial_name_in_local_assigns", object: nil) end def test_render_partial_with_nil_values_in_collection assert_equal "Hello: davidHello: Anonymous", @view.render(partial: "test/customer", collection: [ Customer.new("david"), nil ]) end def test_render_partial_with_layout_using_collection_and_template assert_equal "Hello: AmazonHello: Yahoo", @view.render(partial: "test/customer", layout: "test/b_layout_for_partial", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_layout assert_equal 'Hello: AmazonHello: Yahoo', @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_collection_and_template_makes_current_item_counter_available_in_layout assert_equal 'Hello: AmazonHello: Yahoo', @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object_counter", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_layout assert_equal 'Hello: Amazon', @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object", object: Customer.new("Amazon")) end def test_render_partial_with_empty_array_should_return_nil assert_nil @view.render(partial: []) end def test_render_partial_using_string assert_equal "Hello: Anonymous", @controller_view.render("customer") end def test_render_partial_with_locals_using_string assert_equal "Hola: david", @controller_view.render("customer_greeting", greeting: "Hola", customer_greeting: Customer.new("david")) end def test_render_partial_with_object_uses_render_partial_path assert_equal "Hello: lifo", @controller_view.render(partial: Customer.new("lifo"), locals: { greeting: "Hello" }) end def test_render_partial_with_object_and_format_uses_render_partial_path assert_equal "Hellolifo", @controller_view.render(partial: Customer.new("lifo"), formats: :xml, locals: { greeting: "Hello" }) end def test_render_partial_using_object assert_equal "Hello: lifo", @controller_view.render(Customer.new("lifo"), greeting: "Hello") end def test_render_partial_using_collection customers = [ Customer.new("Amazon"), Customer.new("Yahoo") ] assert_equal "Hello: AmazonHello: Yahoo", @controller_view.render(customers, greeting: "Hello") end def test_render_partial_using_collection_without_path assert_equal "hi good customer: david0", @controller_view.render([ GoodCustomer.new("david") ], greeting: "hi") end def test_render_partial_without_object_or_collection_does_not_generate_partial_name_local_variable exception = assert_raises ActionView::Template::Error do @controller_view.render("partial_name_local_variable") end assert_instance_of NameError, exception.cause assert_equal :partial_name_local_variable, exception.cause.name end def test_render_partial_with_no_block_given_to_yield assert_equal "Before (Josh)\n\nAfter", @view.render(partial: "test/layout_for_partial", locals: { name: "Josh" }) end def test_render_partial_with_non_existent_format_and_raise_missing_template @view.formats = [:xml] assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/layout_for_partial") } ensure @view.formats = nil end def test_render_layout_with_block_and_other_partial_inside render = @view.render(layout: "test/layout_with_partial_and_yield") { "Yield!" } assert_equal "Before\npartial html\nYield!\nAfter\n", render end def test_render_inline assert_equal "Hello, World!", @view.render(inline: "Hello, World!") end def test_render_inline_with_locals assert_equal "Hello, Josh!", @view.render(inline: "Hello, <%= name %>!", locals: { name: "Josh" }) end def test_render_fallbacks_to_erb_for_unknown_types assert_equal "Hello, World!", @view.render(inline: "Hello, World!", type: :bar) end CustomHandler = lambda do |template, source| "@output_buffer = ''.dup\n" \ "@output_buffer << 'source: #{source.inspect}'\n" end def test_render_inline_with_render_from_to_proc ActionView::Template.register_template_handler :ruby_handler, lambda { |_, source| source } assert_equal "3", @view.render(inline: "(1 + 2).to_s", type: :ruby_handler) ensure ActionView::Template.unregister_template_handler :ruby_handler end def test_optional_second_arg_works_without_deprecation assert_not_deprecated do ActionView::Template.register_template_handler :ruby_handler, ->(view, source = nil) { source } end assert_equal "3", @view.render(inline: "(1 + 2).to_s", type: :ruby_handler) ensure ActionView::Template.unregister_template_handler :ruby_handler end def test_render_inline_with_compilable_custom_type ActionView::Template.register_template_handler :foo, CustomHandler assert_equal 'source: "Hello, World!"', @view.render(inline: "Hello, World!", type: :foo) ensure ActionView::Template.unregister_template_handler :foo end def test_render_inline_with_locals_and_compilable_custom_type ActionView::Template.register_template_handler :foo, CustomHandler assert_equal 'source: "Hello, <%= name %>!"', @view.render(inline: "Hello, <%= name %>!", locals: { name: "Josh" }, type: :foo) ensure ActionView::Template.unregister_template_handler :foo end def test_render_body assert_equal "some body", @view.render(body: "some body") end def test_render_plain assert_equal "some plaintext", @view.render(plain: "some plaintext") end def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization ActionView::Template::Handlers.extensions ActionView::Template.register_template_handler :foo, CustomHandler assert_includes ActionView::Template::Handlers.extensions, :foo ensure ActionView::Template.unregister_template_handler :foo end def test_render_does_not_use_unregistered_extension_and_template_handler ActionView::Template.register_template_handler :foo, CustomHandler ActionView::Template.unregister_template_handler :foo assert_not ActionView::Template::Handlers.extensions.include?(:foo) assert_equal "Hello, World!", @view.render(inline: "Hello, World!", type: :foo) ensure ActionView::Template::Handlers.class_variable_get(:@@template_handlers).delete(:foo) end def test_render_ignores_templates_with_malformed_template_handlers %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| assert File.exist?(File.expand_path("#{FIXTURE_LOAD_PATH}/test/malformed/#{name}~")), "Malformed file (#{name}~) which should be ignored does not exists" assert_raises(ActionView::MissingTemplate) do ActiveSupport::Deprecation.silence do @view.render(template: "test/malformed/#{name}") end end end end def test_render_with_layout assert_equal %(\nHello world!\n), @view.render(template: "test/hello_world", layout: "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), @view.render(template: "test/hello_world", layout: "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), @view.render(template: "test/hello_world", layout: "layouts/yield_with_render_partial_inside") end def test_render_partial_with_html_only_extension assert_equal %(

partial html

\nHello world!\n), @view.render(template: "test/hello_world", layout: "layouts/render_partial_html") end def test_render_layout_with_block_and_yield assert_equal %(Content from block!\n), @view.render(layout: "layouts/yield_only") { "Content from block!" } end def test_render_layout_with_block_and_yield_with_params assert_equal %(Yield! Content from block!\n), @view.render(layout: "layouts/yield_with_params") { |param| "#{param} Content from block!" } end def test_render_layout_with_block_which_renders_another_partial_and_yields assert_equal %(partial html\nContent from block!\n), @view.render(layout: "layouts/partial_and_yield") { "Content from block!" } end def test_render_partial_and_layout_without_block_with_locals assert_equal %(Before (Foo!)\npartial html\nAfter), @view.render(partial: "test/partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_and_layout_without_block_with_locals_and_rendering_another_partial assert_equal %(Before (Foo!)\npartial html\npartial with partial\n\nAfter), @view.render(partial: "test/partial_with_partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_shortcut_with_block_content assert_equal %(Before (shortcut test)\nBefore\n\n Yielded: arg1/arg2\n\nAfter\nAfter), @view.render(partial: "test/partial_shortcut_with_block_content", layout: "test/layout_for_partial", locals: { name: "shortcut test" }) end def test_render_layout_with_a_nested_render_layout_call assert_equal %(Before (Foo!)\nBefore (Bar!)\npartial html\nAfter\npartial with layout\n\nAfter), @view.render(partial: "test/partial_with_layout", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_partial assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n partial html\n\nAfterpartial with layout\n\nAfter), @view.render(partial: "test/partial_with_layout_block_partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_content assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n Content from inside layout!\n\nAfterpartial with layout\n\nAfter), @view.render(partial: "test/partial_with_layout_block_content", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_with_layout_raises_descriptive_error e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partial", layout: true) } assert_match "Missing partial /_true with", e.message end if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error) def test_render_partial_provides_spellcheck e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partail") } assert_match %r{Did you mean\? test/partial\n *test/partialhtml}, e.message end def test_spellcheck_doesnt_list_directories e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/directory") } assert_match %r{Did you mean\?}, e.message assert_no_match %r{Did you mean\? test/directory\n}, e.message # test/hello is a directory end def test_spellcheck_only_lists_templates e = assert_raises(ActionView::MissingTemplate) { @view.render(template: "test/partial") } assert_match %r{Did you mean\?}, e.message assert_no_match %r{Did you mean\? test/partial\n}, e.message end def test_spellcheck_only_lists_partials e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/template") } assert_match %r{Did you mean\?}, e.message assert_no_match %r{Did you mean\? test/template\n}, e.message end end def test_render_partial_wrong_details_no_spellcheck e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partial_with_only_html_version", formats: [:xml]) } assert_no_match %r{Did you mean\?}, e.message end def test_render_with_nested_layout assert_equal %(title\n\n
column
\n
content
\n), @view.render(template: "test/nested_layout", layout: "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\ntitle\n\n), @view.render(template: "test/layout_render_file") end def test_render_layout_with_object assert_equal %(David), @view.render(template: "test/layout_render_object") end def test_render_with_passing_couple_extensions_to_one_register_template_handler_function_call ActionView::Template.register_template_handler :foo1, :foo2, CustomHandler assert_equal @view.render(inline: +"Hello, World!", type: :foo1), @view.render(inline: +"Hello, World!", type: :foo2) ensure ActionView::Template.unregister_template_handler :foo1, :foo2 end def test_render_throws_exception_when_no_extensions_passed_to_register_template_handler_function_call assert_raises(ArgumentError) { ActionView::Template.register_template_handler CustomHandler } end def test_render_object assert_equal( %(Hello, World!), @view.render(TestRenderable.new) ) end end class CachedViewRenderTest < ActiveSupport::TestCase include RenderTestCases # Ensure view path cache is primed def setup ActionView::LookupContext::DetailsKey.clear view_paths = ActionController::Base.view_paths assert_equal ActionView::FileSystemResolver, view_paths.first.class setup_view(view_paths) end def test_cache_fragments_inside_render_layout_call_with_block cat = @view.render(template: "test/cache_fragment_inside_render_layout_block_1") dog = @view.render(template: "test/cache_fragment_inside_render_layout_block_2") assert_not_equal cat, dog end end class LazyViewRenderTest < ActiveSupport::TestCase include RenderTestCases # Test the same thing as above, but make sure the view path # is not eager loaded def setup ActionView::LookupContext::DetailsKey.clear path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) view_paths = ActionView::PathSet.new([path]) assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first setup_view(view_paths) end def test_render_utf8_template_with_magic_comment with_external_encoding Encoding::ASCII_8BIT do result = @view.render(template: "test/utf8_magic", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "\nРусский \nтСкст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end def test_render_utf8_template_with_default_external_encoding with_external_encoding Encoding::UTF_8 do result = @view.render(template: "test/utf8", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "Русский тСкст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/utf8", formats: [:html], layouts: "layouts/yield") } assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/utf8_magic_with_bare_partial", formats: [:html], layouts: "layouts/yield") } assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end def with_external_encoding(encoding) old = Encoding.default_external silence_warnings { Encoding.default_external = encoding } yield ensure silence_warnings { Encoding.default_external = old } end end class CachedCollectionViewRenderTest < ActiveSupport::TestCase class CachedCustomer < Customer; end include RenderTestCases # Ensure view path cache is primed setup do ActionView::LookupContext::DetailsKey.clear view_paths = ActionController::Base.view_paths assert_equal ActionView::FileSystemResolver, view_paths.first.class ActionView::PartialRenderer.collection_cache = ActiveSupport::Cache::MemoryStore.new setup_view(view_paths) end test "template body written to cache" do customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") assert_nil ActionView::PartialRenderer.collection_cache.read(key) @view.render(partial: "test/customer", collection: [customer], cached: true) assert_equal "Hello: david", ActionView::PartialRenderer.collection_cache.read(key) end test "collection caching does not cache by default" do customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_not_equal "Cached", @view.render(partial: "test/customer", collection: [customer]) end test "collection caching does not cache if controller doesn't respond to perform_caching" do @view.controller = nil customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_not_equal "Cached", @view.render(partial: "test/customer", collection: [customer], cached: true) end test "collection caching does not cache if perform_caching is disabled" do @view.controller.perform_caching = false customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_not_equal "Cached", @view.render(partial: "test/customer", collection: [customer], cached: true) end test "collection caching with partial that doesn't use fragment caching" do customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_equal "Cached", @view.render(partial: "test/customer", collection: [customer], cached: true) end test "collection caching with cached true" do customer = CachedCustomer.new("david", 1) key = cache_key(customer, "test/_cached_customer") ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_equal "Cached", @view.render(partial: "test/cached_customer", collection: [customer], cached: true) end test "collection caching does not work on multi-partials" do a = Object.new b = Object.new def a.to_partial_path; "test/partial_iteration_1"; end def b.to_partial_path; "test/partial_iteration_2"; end assert_raises(NotImplementedError) do @controller_view.render(partial: [a, b], cached: true) end end test "collection caching with repeated collection" do sets = [ [1, 2, 3, 4, 5], [1, 2, 3, 4, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 4], [1, 2, 3, 4, 6] ] result = @view.render(partial: "test/cached_set", collection: sets, cached: true) splited_result = result.split("\n") assert_equal 5, splited_result.count assert_equal [ "1 | 2 | 3 | 4 | 5", "1 | 2 | 3 | 4 | 4", "1 | 2 | 3 | 4 | 5", "1 | 2 | 3 | 4 | 4", "1 | 2 | 3 | 4 | 6" ], splited_result end private def cache_key(*names, virtual_path) digest = ActionView::Digestor.digest name: virtual_path, format: :html, finder: @view.lookup_context, dependencies: [] @view.combined_fragment_cache_key([ "#{virtual_path}:#{digest}", *names ]) end end