# frozen_string_literal: truemoduleViewComponentmoduleTestHelpersbeginrequire"capybara/minitest"includeCapybara::Minitest::Assertionsdefpage@page||=Capybara::Node::Simple.new(rendered_content)enddefrefute_component_renderedassert_no_selector("body")enddefassert_component_renderedassert_selector("body")endrescueLoadError# We don't have a test case for running an application without capybara installed.# It's probably fine to leave this without coverage.# :nocov:ifENV["DEBUG"]warn("WARNING in `ViewComponent::TestHelpers`: Add `capybara` "\"to Gemfile to use Capybara assertions.")end# :nocov:end# Returns the result of a render_inline call.## @return [ActionView::OutputBuffer]attr_reader:rendered_content# Render a component inline. Internally sets `page` to be a `Capybara::Node::Simple`,# allowing for Capybara assertions to be used:## ```ruby# render_inline(MyComponent.new)# assert_text("Hello, World!")# ```## @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.# @return [Nokogiri::HTML]defrender_inline(component,**args,&block)@page=nil@rendered_content=ifRails.version.to_f>=6.1vc_test_controller.view_context.render(component,args,&block)# :nocov:elsevc_test_controller.view_context.render_component(component,&block)end# :nocov:Nokogiri::HTML.fragment(@rendered_content)end# `JSON.parse`-d component output.## ```ruby# render_inline(MyJsonComponent.new)# assert_equal(rendered_json["hello"], "world")# ```defrendered_jsonJSON.parse(rendered_content)end# Render a preview inline. Internally sets `page` to be a `Capybara::Node::Simple`,# allowing for Capybara assertions to be used:## ```ruby# render_preview(:default)# assert_text("Hello, World!")# ```## Note: `#rendered_preview` expects a preview to be defined with the same class# name as the calling test, but with `Test` replaced with `Preview`:## MyComponentTest -> MyComponentPreview etc.## In RSpec, `Preview` is appended to `described_class`.## @param name [String] The name of the preview to be rendered.# @param from [ViewComponent::Preview] The class of the preview to be rendered.# @param params [Hash] Parameters to be passed to the preview.# @return [Nokogiri::HTML]defrender_preview(name,from: __vc_test_helpers_preview_class,params: {})previews_controller=__vc_test_helpers_build_controller(Rails.application.config.view_component.preview_controller.constantize)# From what I can tell, it's not possible to overwrite all request parameters# at once, so we set them individually here.params.eachdo|k,v|previews_controller.request.params[k]=vendpreviews_controller.request.params[:path]="#{from.preview_name}/#{name}"previews_controller.set_response!(ActionDispatch::Response.new)result=previews_controller.previews@rendered_content=resultNokogiri::HTML.fragment(@rendered_content)end# Execute the given block in the view context (using `instance_exec`).# Internally sets `page` to be a `Capybara::Node::Simple`, allowing for# Capybara assertions to be used. All arguments are forwarded to the block.## ```ruby# render_in_view_context(arg1, arg2: nil) do |arg1, arg2:|# render(MyComponent.new(arg1, arg2))# end## assert_text("Hello, World!")# ```defrender_in_view_context(*args,&block)@page=nil@rendered_content=vc_test_controller.view_context.instance_exec(*args,&block)Nokogiri::HTML.fragment(@rendered_content)endruby2_keywords(:render_in_view_context)ifrespond_to?(:ruby2_keywords,true)# Set the Action Pack request variant for the given block:## ```ruby# with_variant(:phone) do# render_inline(MyComponent.new)# end# ```## @param variant [Symbol] The variant to be set for the provided block.defwith_variant(variant)old_variants=vc_test_controller.view_context.lookup_context.variantsvc_test_controller.view_context.lookup_context.variants=variantyieldensurevc_test_controller.view_context.lookup_context.variants=old_variantsend# Set the controller to be used while executing the given block,# allowing access to controller-specific methods:## ```ruby# with_controller_class(UsersController) do# render_inline(MyComponent.new)# end# ```## @param klass [Class<ActionController::Base>] The controller to be used.defwith_controller_class(klass)old_controller=defined?(@vc_test_controller)&&@vc_test_controller@vc_test_controller=__vc_test_helpers_build_controller(klass)yieldensure@vc_test_controller=old_controllerend# Set format of the current request## ```ruby# with_format(:json) do# render_inline(MyComponent.new)# end# ```## @param format [Symbol] The format to be set for the provided block.defwith_format(format)with_request_url("/",format: format){yield}end# Set the URL of the current request (such as when using request-dependent path helpers):## ```ruby# with_request_url("/users/42") do# render_inline(MyComponent.new)# end# ```## To use a specific host, pass the host param:## ```ruby# with_request_url("/users/42", host: "app.example.com") do# render_inline(MyComponent.new)# end# ```## To specify a request method, pass the method param:## ```ruby# with_request_url("/users/42", method: "POST") do# render_inline(MyComponent.new)# end# ```## @param full_path [String] The path to set for the current request.# @param host [String] The host to set for the current request.# @param method [String] The request method to set for the current request.defwith_request_url(full_path,host: nil,method: nil,format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT)old_request_host=vc_test_request.hostold_request_method=vc_test_request.request_methodold_request_path_info=vc_test_request.path_infoold_request_path_parameters=vc_test_request.path_parametersold_request_query_parameters=vc_test_request.query_parametersold_request_query_string=vc_test_request.query_stringold_request_format=vc_test_request.format.symbolold_controller=defined?(@vc_test_controller)&&@vc_test_controllerpath,query=full_path.split("?",2)vc_test_request.instance_variable_set(:@fullpath,full_path)vc_test_request.instance_variable_set(:@original_fullpath,full_path)vc_test_request.host=hostifhostvc_test_request.request_method=methodifmethodvc_test_request.path_info=pathvc_test_request.path_parameters=Rails.application.routes.recognize_path_with_request(vc_test_request,path,{})vc_test_request.set_header("action_dispatch.request.query_parameters",Rack::Utils.parse_nested_query(query).with_indifferent_access)vc_test_request.set_header(Rack::QUERY_STRING,query)vc_test_request.format=formatyieldensurevc_test_request.host=old_request_hostvc_test_request.request_method=old_request_methodvc_test_request.path_info=old_request_path_infovc_test_request.path_parameters=old_request_path_parametersvc_test_request.set_header("action_dispatch.request.query_parameters",old_request_query_parameters)vc_test_request.set_header(Rack::QUERY_STRING,old_request_query_string)vc_test_request.format=old_request_format@vc_test_controller=old_controllerend# Access the controller used by `render_inline`:## ```ruby# test "logged out user sees login link" do# vc_test_controller.expects(:logged_in?).at_least_once.returns(false)# render_inline(LoginComponent.new)# assert_selector("[aria-label='You must be signed in']")# end# ```## @return [ActionController::Base]defvc_test_controller@vc_test_controller||=__vc_test_helpers_build_controller(Base.test_controller.constantize)end# Access the request used by `render_inline`:## ```ruby# test "component does not render in Firefox" do# request.env["HTTP_USER_AGENT"] = "Mozilla/5.0"# render_inline(NoFirefoxComponent.new)# refute_component_rendered# end# ```## @return [ActionDispatch::TestRequest]defvc_test_requestrequire"action_controller/test_case"@vc_test_request||=beginout=ActionDispatch::TestRequest.createout.session=ActionController::TestSession.newoutendend# Note: We prefix private methods here to prevent collisions in consumer's tests.privatedef__vc_test_helpers_build_controller(klass)klass.new.tap{|c|c.request=vc_test_request}.extend(Rails.application.routes.url_helpers)enddef__vc_test_helpers_preview_classresult=ifrespond_to?(:described_class)# :nocov:raise"`render_preview` expected a described_class, but it is nil."ifdescribed_class.nil?"#{described_class}Preview"# :nocov:elseself.class.name.gsub("Test","Preview")endresult=result.constantizerescueNameErrorraiseNameError,"`render_preview` expected to find #{result}, but it does not exist."end# :nocov:endend