diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 08b398d5b..7696aa584 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,7 @@ nav_order: 6 ## main +* Share the view context in tests to prevent out-of-order rendering issues for certain advanced use-cases, eg. testing instances of Rails' `FormBuilder`. * Fix double rendering issue for partials that yield. *Cameron Dutro* diff --git a/lib/view_component/test_helpers.rb b/lib/view_component/test_helpers.rb index 60a08e0d7..e3de34f1b 100644 --- a/lib/view_component/test_helpers.rb +++ b/lib/view_component/test_helpers.rb @@ -38,9 +38,19 @@ def assert_component_rendered # @return [Nokogiri::HTML5] def render_inline(component, **args, &block) @page = nil - @rendered_content = vc_test_controller.view_context.render(component, args, &block) + @rendered_content = vc_test_view_context.render(component, args, &block) - Nokogiri::HTML5.fragment(@rendered_content) + fragment = Nokogiri::HTML5.fragment(@rendered_content) + @vc_test_view_context = nil + fragment + end + + # Returns the view context used to render components in tests. Note that the view context + # is reset after each call to `render_inline`. + # + # @return [ActionView::Base] + def vc_test_view_context + @vc_test_view_context ||= vc_test_controller.view_context end # `JSON.parse`-d component output. @@ -103,7 +113,7 @@ def render_preview(name, from: __vc_test_helpers_preview_class, params: {}) # ``` def render_in_view_context(...) @page = nil - @rendered_content = vc_test_controller.view_context.instance_exec(...) + @rendered_content = vc_test_view_context.instance_exec(...) Nokogiri::HTML5.fragment(@rendered_content) end diff --git a/test/sandbox/app/components/custom_form_builder_component.html.erb b/test/sandbox/app/components/custom_form_builder_component.html.erb new file mode 100644 index 000000000..ea2dec845 --- /dev/null +++ b/test/sandbox/app/components/custom_form_builder_component.html.erb @@ -0,0 +1,3 @@ +<%= @builder.label :foo do %> + <%= content %> +<% end %> diff --git a/test/sandbox/app/components/custom_form_builder_component.rb b/test/sandbox/app/components/custom_form_builder_component.rb new file mode 100644 index 000000000..604cdbc72 --- /dev/null +++ b/test/sandbox/app/components/custom_form_builder_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class CustomFormBuilderComponent < ViewComponent::Base + def initialize(builder:) + @builder = builder + end +end diff --git a/test/sandbox/test/rendering_test.rb b/test/sandbox/test/rendering_test.rb index 144e55f63..b37bbffe4 100644 --- a/test/sandbox/test/rendering_test.rb +++ b/test/sandbox/test/rendering_test.rb @@ -34,7 +34,7 @@ def test_render_collection_inline_allocations ViewComponent::CompileCache.cache.delete(ProductComponent) ProductComponent.__vc_ensure_compiled - allocations = {"3.5" => 76, "3.4" => 82, "3.3" => 86, "3.2" => 89..90} + allocations = {"3.5" => 66, "3.4" => 82, "3.3" => 86, "3.2" => 89..90} products = [Product.new(name: "Radio clock"), Product.new(name: "Mints")] notice = "On sale" diff --git a/test/sandbox/test/test_helper_test.rb b/test/sandbox/test/test_helper_test.rb index c55dfc0eb..251f429fd 100644 --- a/test/sandbox/test/test_helper_test.rb +++ b/test/sandbox/test/test_helper_test.rb @@ -43,4 +43,10 @@ def test_with_request_url_under_constraint def test_vc_test_controller_exists assert vc_test_controller.is_a?(ActionController::Base) end + + def test_vc_test_view_context_is_shared_reference + builder = ActionView::Helpers::FormBuilder.new(nil, Object.new, vc_test_view_context, {}) + render_inline(CustomFormBuilderComponent.new(builder: builder)) { "Label content" } + assert_selector("label[for=foo]", text: "Label content") + end end