Module: ViewComponent::TestHelpers

Included in:
SystemTestHelpers, TestCase
Defined in:
lib/view_component/test_helpers.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#rendered_contentActionView::OutputBuffer (readonly)

Returns the result of a render_inline call.



27
28
29
# File 'lib/view_component/test_helpers.rb', line 27

def rendered_content
  @rendered_content
end

Instance Method Details

#render_in_view_contextObject

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!”) “‘



116
117
118
119
120
# File 'lib/view_component/test_helpers.rb', line 116

def render_in_view_context(...)
  @page = nil
  @rendered_content = vc_test_view_context.instance_exec(...)
  Nokogiri::HTML5.fragment(@rendered_content)
end

#render_inline(component, **args, &block) ⇒ Nokogiri::HTML5

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!”) “`

Parameters:

Returns:

  • (Nokogiri::HTML5)


40
41
42
43
44
45
46
47
# File 'lib/view_component/test_helpers.rb', line 40

def render_inline(component, **args, &block)
  @page = nil
  @rendered_content = vc_test_view_context.render(component, args, &block)

  fragment = Nokogiri::HTML5.fragment(@rendered_content, context: "template")
  @vc_test_view_context = nil
  fragment
end

#render_preview(name, from: __vc_test_helpers_preview_class, params: {}) ⇒ Nokogiri::HTML5

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`.

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!”) “`

Parameters:

  • name (String)

    The name of the preview to be rendered.

  • from (ViewComponent::Preview) (defaults to: __vc_test_helpers_preview_class)

    The class of the preview to be rendered.

  • params (Hash) (defaults to: {})

    Parameters to be passed to the preview.

Returns:

  • (Nokogiri::HTML5)


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/view_component/test_helpers.rb', line 87

def render_preview(name, from: __vc_test_helpers_preview_class, params: {})
  previews_controller = __vc_test_helpers_build_controller(Rails.application.config.view_component.previews.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.each do |k, v|
    previews_controller.request.params[k] = v
  end

  previews_controller.request.params[:path] = "#{from.preview_name}/#{name}"
  previews_controller.set_response!(ActionDispatch::Response.new)
  result = previews_controller.previews

  @rendered_content = result

  Nokogiri::HTML5.fragment(@rendered_content)
end

#rendered_jsonObject

‘JSON.parse`-d component output.

“‘ruby render_inline(MyJsonComponent.new) assert_equal(rendered_json, “world”) “`



63
64
65
# File 'lib/view_component/test_helpers.rb', line 63

def rendered_json
  JSON.parse(rendered_content)
end

#vc_test_controllerActionController::Base

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 “‘

Returns:

  • (ActionController::Base)


259
260
261
# File 'lib/view_component/test_helpers.rb', line 259

def vc_test_controller
  @vc_test_controller ||= __vc_test_helpers_build_controller(vc_test_controller_class)
end

#vc_test_controller_classObject

Set the controller used by ‘render_inline`:

“‘ruby def vc_test_controller_class

MyTestController

end “‘



270
271
272
273
274
# File 'lib/view_component/test_helpers.rb', line 270

def vc_test_controller_class
  return @__vc_test_controller_class if defined?(@__vc_test_controller_class)

  defined?(ApplicationController) ? ApplicationController : ActionController::Base
end

#vc_test_requestActionDispatch::TestRequest

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 “‘

Returns:

  • (ActionDispatch::TestRequest)


287
288
289
290
291
292
293
294
295
296
# File 'lib/view_component/test_helpers.rb', line 287

def vc_test_request
  require "action_controller/test_case"

  @vc_test_request ||=
    begin
      out = ActionDispatch::TestRequest.create
      out.session = ActionController::TestSession.new
      out
    end
end

#vc_test_view_contextActionView::Base

Returns the view context used to render components in tests. Note that the view context is reset after each call to ‘render_inline`.

Returns:

  • (ActionView::Base)


53
54
55
# File 'lib/view_component/test_helpers.rb', line 53

def vc_test_view_context
  @vc_test_view_context ||= vc_test_controller.view_context
end

#with_controller_class(klass) ⇒ Object

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 “‘

Parameters:

  • klass (Class<ActionController::Base>)

    The controller to be used.



150
151
152
153
154
155
156
157
# File 'lib/view_component/test_helpers.rb', line 150

def with_controller_class(klass)
  old_controller = defined?(@vc_test_controller) && @vc_test_controller

  @vc_test_controller = __vc_test_helpers_build_controller(klass)
  yield
ensure
  @vc_test_controller = old_controller
end

#with_format(*formats) ⇒ Object

Set format of the current request

“‘ruby with_format(:json) do

render_inline(MyComponent.new)

end “‘

Parameters:

  • formats (Array<Symbol>)

    The format(s) to be set for the provided block.



168
169
170
171
172
173
174
175
# File 'lib/view_component/test_helpers.rb', line 168

def with_format(*formats)
  old_formats = vc_test_controller.view_context.lookup_context.formats

  vc_test_controller.view_context.lookup_context.formats = formats
  yield
ensure
  vc_test_controller.view_context.lookup_context.formats = old_formats
end

#with_request_url(full_path, host: nil, method: nil, protocol: nil) ⇒ Object

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 “‘

To specify a protocol, pass the protocol param:

“‘ruby with_request_url(“/users/42”, protocol: :https) do

render_inline(MyComponent.new)

end “‘

Parameters:

  • full_path (String)

    The path to set for the current request.

  • host (String) (defaults to: nil)

    The host to set for the current request.

  • method (String) (defaults to: nil)

    The request method to set for the current request.

  • protocol (Symbol) (defaults to: nil)

    The protocol to set for the current request (e.g., ‘:http` or `:https`).



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/view_component/test_helpers.rb', line 213

def with_request_url(full_path, host: nil, method: nil, protocol: nil)
  old_request_host = vc_test_request.host
  old_request_method = vc_test_request.request_method
  old_request_path_info = vc_test_request.path_info
  old_request_path_parameters = vc_test_request.path_parameters
  old_request_query_parameters = vc_test_request.query_parameters
  old_request_query_string = vc_test_request.query_string
  old_request_format = vc_test_request.format.symbol
  old_request_scheme = vc_test_request.scheme
  old_controller = defined?(@vc_test_controller) && @vc_test_controller

  path, 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 = host if host
  vc_test_request.request_method = method if method
  vc_test_request.set_header(Rack::RACK_URL_SCHEME, protocol.to_s) if protocol
  vc_test_request.path_info = path
  vc_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)
  yield
ensure
  vc_test_request.host = old_request_host
  vc_test_request.request_method = old_request_method
  vc_test_request.set_header(Rack::RACK_URL_SCHEME, old_request_scheme)
  vc_test_request.path_info = old_request_path_info
  vc_test_request.path_parameters = old_request_path_parameters
  vc_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_controller
end

#with_variant(*variants) ⇒ Object

Set the Action Pack request variant for the given block:

“‘ruby with_variant(:phone) do

render_inline(MyComponent.new)

end “‘

Parameters:

  • variants (Array<Symbol>)

    The variants to be set for the provided block.



131
132
133
134
135
136
137
138
# File 'lib/view_component/test_helpers.rb', line 131

def with_variant(*variants)
  old_variants = vc_test_controller.view_context.lookup_context.variants

  vc_test_controller.view_context.lookup_context.variants += variants
  yield
ensure
  vc_test_controller.view_context.lookup_context.variants = old_variants
end