diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c2c997177..896660b4e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 6 ## main +* Restore request-dependent URL generation when using `render_preview` inside `with_request_url`. + + *Joel Hawksley* + * Speed up cold cache digests by skipping the `# Template Dependency:` scan for sources that declare none, and by not translating class names in synthetic templates, which only declare paths. *Erik Axel Nielsen* diff --git a/docs/guide/testing.md b/docs/guide/testing.md index 8463495bd..394509011 100644 --- a/docs/guide/testing.md +++ b/docs/guide/testing.md @@ -231,6 +231,15 @@ class ExampleComponentTest < ViewComponent::TestCase end ``` +`with_request_url` also applies to request-dependent URL generation inside `render_preview`: + +```ruby +with_request_url "/products/42" do + render_preview(:default, from: ExampleComponentPreview) + assert_link "French", href: "/products/42?locale=fr" +end +``` + ## Setting `request.host` Since 3.3.0 diff --git a/lib/view_component/test_helpers.rb b/lib/view_component/test_helpers.rb index b267a3e7e..30766dd19 100644 --- a/lib/view_component/test_helpers.rb +++ b/lib/view_component/test_helpers.rb @@ -89,14 +89,16 @@ def render_preview(name, from: __vc_test_helpers_preview_class, params: {}) controller_class = Rails.application.config.view_component.previews.controller.constantize request = ActionDispatch::TestRequest.new(vc_test_request.env.dup) query_parameters = vc_test_request.query_parameters.deep_dup.merge(params.stringify_keys) - request.path_parameters = vc_test_request.path_parameters.except(*params.keys.map(&:to_sym)).merge( - controller: controller_class.controller_path, - action: "previews", - path: "#{from.preview_name}/#{name}" - ) + request.path_parameters = vc_test_request.path_parameters.deep_dup request.set_header("action_dispatch.request.query_parameters", query_parameters) request.set_header(Rack::QUERY_STRING, query_parameters.to_query) previews_controller = __vc_test_helpers_build_controller(controller_class, request: request) + # Dispatch the preview without replacing the request's URL generation context. + previews_controller.params = request.parameters.merge(params.stringify_keys).merge( + "controller" => controller_class.controller_path, + "action" => "previews", + "path" => "#{from.preview_name}/#{name}" + ) previews_controller.set_response!(ActionDispatch::Response.new) previews_controller.process(:previews) @rendered_content = previews_controller.response.body diff --git a/test/sandbox/app/components/request_url_component.rb b/test/sandbox/app/components/request_url_component.rb index e96b4e996..e8ea2abf1 100644 --- a/test/sandbox/app/components/request_url_component.rb +++ b/test/sandbox/app/components/request_url_component.rb @@ -2,6 +2,10 @@ class RequestUrlComponent < ViewComponent::Base def call - content_tag(:span, request.path, class: "path") + content_tag(:span, request.fullpath, class: "fullpath") + content_tag(:span, request.path, class: "path") + + content_tag(:span, request.fullpath, class: "fullpath") + + content_tag(:span, content, class: "content") + + link_to("Request-dependent link", url_for(bar: "baz")) + + link_to("Absolute request-dependent link", url_for(bar: "baz", only_path: false)) end end diff --git a/test/sandbox/config/routes.rb b/test/sandbox/config/routes.rb index d0d7c5073..2c6ed95bc 100644 --- a/test/sandbox/config/routes.rb +++ b/test/sandbox/config/routes.rb @@ -8,6 +8,7 @@ get :content, to: "integration_examples#content" get :variants, to: "integration_examples#variants" get :products, to: "integration_examples#products" + get "products/:id", to: "integration_examples#products" get :inline_products, to: "integration_examples#inline_products" get :cached, to: "integration_examples#cached" get :render_check, to: "integration_examples#render_check" diff --git a/test/sandbox/test/components/previews/request_url_component_preview.rb b/test/sandbox/test/components/previews/request_url_component_preview.rb new file mode 100644 index 000000000..1faadbb5d --- /dev/null +++ b/test/sandbox/test/components/previews/request_url_component_preview.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class RequestUrlComponentPreview < ViewComponent::Preview + def default + render(RequestUrlComponent.new) + end + + def with_id(id:) + render(RequestUrlComponent.new) { id } + end +end diff --git a/test/sandbox/test/components/render_preview_test.rb b/test/sandbox/test/components/render_preview_test.rb index 80b4a84a4..183dd92d3 100644 --- a/test/sandbox/test/components/render_preview_test.rb +++ b/test/sandbox/test/components/render_preview_test.rb @@ -63,6 +63,45 @@ def test_render_preview_preserves_the_original_request_parameters end end + def test_render_preview_uses_the_request_url_for_request_dependent_links + with_request_url("/products") do + fragment = render_preview(:default, from: RequestUrlComponentPreview) + + assert_equal "/products", vc_test_request.path + assert_selector(".path", text: "/products") + assert_equal "/products?bar=baz", fragment.at_css("a")["href"] + end + end + + def test_render_preview_preserves_route_parameters_when_preview_parameters_overlap + with_request_url("/products/42?id=query-id") do + render_preview(:with_id, from: RequestUrlComponentPreview, params: {id: "preview-id"}) + + assert_selector(".content", exact_text: "preview-id") + assert_link "Request-dependent link", href: "/products/42?bar=baz", exact: true + assert_equal "42", vc_test_request.path_parameters[:id] + assert_equal "query-id", vc_test_request.query_parameters["id"] + end + end + + def test_render_preview_parameters_override_request_query_parameters + with_request_url("/products?title=Query+title") do + render_preview(:with_params, from: PreviewComponentPreview, params: {title: "Preview title"}) + + assert_text "Preview title" + assert_no_text "Query title" + assert_equal "Query title", vc_test_request.query_parameters["title"] + end + end + + def test_render_preview_preserves_the_request_host_and_protocol_for_links + with_request_url("/products/42", host: "app.example.com:8443", protocol: :https) do + render_preview(:default, from: RequestUrlComponentPreview) + + assert_link "Absolute request-dependent link", href: "https://app.example.com:8443/products/42?bar=baz" + end + end + def test_render_preview_runs_locale_callbacks_and_restores_the_locale render_args = PreviewComponentPreview.method(:render_args) locales = [] diff --git a/test/sandbox/test/integration_test.rb b/test/sandbox/test/integration_test.rb index 628dc92d7..82d06ef66 100644 --- a/test/sandbox/test/integration_test.rb +++ b/test/sandbox/test/integration_test.rb @@ -134,8 +134,8 @@ def test_inherited_component_with_call_method_does_not_recompile_superclass assert_select "div", "hello world" assert_response :success ensure - UncompilableComponent.singleton_class.silence_redefinition_of_method(:__vc_compile) - UncompilableComponent.define_singleton_method(:__vc_compile, original_method) + original_method.receiver.singleton_class.silence_redefinition_of_method(:__vc_compile) + original_method.receiver.define_singleton_method(:__vc_compile, original_method) end end