Ensure consistent indentation with Rubocop (#997)

* Ensure consistent indentation with Rubocop

* add more rubocop spacing rules
This commit is contained in:
Joel Hawksley 2021-07-01 15:01:38 -06:00 коммит произвёл GitHub
Родитель 92195559fb
Коммит 0afe05da0c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
27 изменённых файлов: 321 добавлений и 256 удалений

Просмотреть файл

@ -11,3 +11,9 @@ AllCops:
Gemspec/OrderedDependencies:
Enabled: true
Layout:
Enabled: true
Layout/DotPosition:
EnforcedStyle: trailing

Просмотреть файл

@ -57,8 +57,8 @@ namespace :docs do
meths.
select do |method|
!method.tag(:private) &&
method.path.include?("ViewComponent::Base") &&
method.visibility == :public
method.path.include?("ViewComponent::Base") &&
method.visibility == :public
end.sort_by { |method| method[:name] }
instance_methods_to_document = meths.select { |method| method.scope != :class }
@ -83,9 +83,10 @@ namespace :docs do
" (Deprecated)"
end
types = if method.tag(:return)&.types
" → [#{method.tag(:return).types.join(',')}]"
end
types =
if method.tag(:return)&.types
" → [#{method.tag(:return).types.join(',')}]"
end
f.puts
f.puts("### #{method.sep}#{method.signature.gsub('def ', '')}#{types}#{suffix}")
@ -107,9 +108,10 @@ namespace :docs do
" (Deprecated)"
end
types = if method.tag(:return)&.types
" → [#{method.tag(:return).types.join(',')}]"
end
types =
if method.tag(:return)&.types
" → [#{method.tag(:return).types.join(',')}]"
end
f.puts
f.puts("### #{method.sep}#{method.signature.gsub('def ', '')}#{types}#{suffix}")
@ -131,7 +133,6 @@ namespace :docs do
select { |method| method[:mattr_accessor] }.
sort_by { |method| method[:name] }.
each do |method|
suffix =
if method.tag(:deprecated)
" (Deprecated)"

Просмотреть файл

@ -7,6 +7,10 @@ title: Changelog
## main
* Ensure consistent indentation with Rubocop.
*Joel Hawksley
* Bump `activesupport` upper bound from `< 7.0` to `< 8.0`.
*Richard Macklin*

Просмотреть файл

@ -1,4 +1,5 @@
# frozen_string_literal: true
require "action_view"
require "active_support/dependencies/autoload"

Просмотреть файл

@ -155,6 +155,7 @@ module ViewComponent
# @return [ActionController::Base]
def controller
raise ViewContextCalledBeforeRenderError, "`controller` can only be called at render time." if view_context.nil?
@__vc_controller ||= view_context.controller
end
@ -163,6 +164,7 @@ module ViewComponent
# @return [ActionView::Base]
def helpers
raise ViewContextCalledBeforeRenderError, "`helpers` can only be called at render time." if view_context.nil?
@__vc_helpers ||= controller.view_context
end
@ -214,11 +216,12 @@ module ViewComponent
@__vc_content_evaluated = true
return @__vc_content if defined?(@__vc_content)
@__vc_content = if @view_context && @__vc_render_in_block
view_context.capture(self, &@__vc_render_in_block)
elsif defined?(@__vc_content_set_by_with_content)
@__vc_content_set_by_with_content
end
@__vc_content =
if @view_context && @__vc_render_in_block
view_context.capture(self, &@__vc_render_in_block)
elsif defined?(@__vc_content_set_by_with_content)
@__vc_content_set_by_with_content
end
end
def content_evaluated?
@ -288,11 +291,12 @@ module ViewComponent
# end
#
# Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
nested_component_files = if name.include?("::") && component_name != filename
Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
else
[]
end
nested_component_files =
if name.include?("::") && component_name != filename
Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
else
[]
end
# view files in the same directory as the component
sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]

Просмотреть файл

@ -5,6 +5,7 @@ require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
module ViewComponent
class Collection
attr_reader :component
delegate :format, to: :component
def render_in(view_context, &block)

Просмотреть файл

@ -7,6 +7,7 @@ module ViewComponent
mattr_accessor :cache, instance_reader: false, instance_accessor: false do
Set.new
end
module_function
def register(klass)

Просмотреть файл

@ -21,6 +21,7 @@ module ViewComponent
if template_errors.present?
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
return false
end
@ -77,72 +78,75 @@ module ViewComponent
end
end
RUBY
end
def template_errors
@__vc_template_errors ||= begin
errors = []
@__vc_template_errors ||=
begin
errors = []
if (templates + inline_calls).empty?
errors << "Could not find a template file or inline render method for #{component_class}."
if (templates + inline_calls).empty?
errors << "Could not find a template file or inline render method for #{component_class}."
end
if templates.count { |template| template[:variant].nil? } > 1
errors << "More than one template found for #{component_class}. There can only be one default template file per component."
end
invalid_variants =
templates.
group_by { |template| template[:variant] }.
map { |variant, grouped| variant if grouped.length > 1 }.
compact.
sort
unless invalid_variants.empty?
errors << "More than one template found for #{'variant'.pluralize(invalid_variants.count)} #{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be one template file per variant."
end
if templates.find { |template| template[:variant].nil? } && inline_calls_defined_on_self.include?(:call)
errors << "Template file and inline render method found for #{component_class}. There can only be a template file or inline render method per component."
end
duplicate_template_file_and_inline_variant_calls =
templates.pluck(:variant) & variants_from_inline_calls(inline_calls_defined_on_self)
unless duplicate_template_file_and_inline_variant_calls.empty?
count = duplicate_template_file_and_inline_variant_calls.count
errors << "Template #{'file'.pluralize(count)} and inline render #{'method'.pluralize(count)} found for #{'variant'.pluralize(count)} #{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be a template file or inline render method per variant."
end
errors
end
if templates.count { |template| template[:variant].nil? } > 1
errors << "More than one template found for #{component_class}. There can only be one default template file per component."
end
invalid_variants = templates
.group_by { |template| template[:variant] }
.map { |variant, grouped| variant if grouped.length > 1 }
.compact
.sort
unless invalid_variants.empty?
errors << "More than one template found for #{'variant'.pluralize(invalid_variants.count)} #{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be one template file per variant."
end
if templates.find { |template| template[:variant].nil? } && inline_calls_defined_on_self.include?(:call)
errors << "Template file and inline render method found for #{component_class}. There can only be a template file or inline render method per component."
end
duplicate_template_file_and_inline_variant_calls =
templates.pluck(:variant) & variants_from_inline_calls(inline_calls_defined_on_self)
unless duplicate_template_file_and_inline_variant_calls.empty?
count = duplicate_template_file_and_inline_variant_calls.count
errors << "Template #{'file'.pluralize(count)} and inline render #{'method'.pluralize(count)} found for #{'variant'.pluralize(count)} #{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. There can only be a template file or inline render method per variant."
end
errors
end
end
def templates
@templates ||= begin
extensions = ActionView::Template.template_handler_extensions
@templates ||=
begin
extensions = ActionView::Template.template_handler_extensions
component_class._sidecar_files(extensions).each_with_object([]) do |path, memo|
pieces = File.basename(path).split(".")
memo << {
path: path,
variant: pieces.second.split("+").second&.to_sym,
handler: pieces.last
}
component_class._sidecar_files(extensions).each_with_object([]) do |path, memo|
pieces = File.basename(path).split(".")
memo << {
path: path,
variant: pieces.second.split("+").second&.to_sym,
handler: pieces.last
}
end
end
end
end
def inline_calls
@inline_calls ||= begin
# Fetch only ViewComponent ancestor classes to limit the scope of
# finding inline calls
view_component_ancestors =
component_class.ancestors.take_while { |ancestor| ancestor != ViewComponent::Base } - component_class.included_modules
@inline_calls ||=
begin
# Fetch only ViewComponent ancestor classes to limit the scope of
# finding inline calls
view_component_ancestors =
component_class.ancestors.take_while { |ancestor| ancestor != ViewComponent::Base } - component_class.included_modules
view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq
end
view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq
end
end
def inline_calls_defined_on_self

Просмотреть файл

@ -71,19 +71,20 @@ module ViewComponent # :nodoc:
# Returns the relative path (from preview_path) to the preview example template if the template exists
def preview_example_template_path(example)
preview_path = Array(preview_paths).detect do |preview_path|
Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
end
preview_path =
Array(preview_paths).detect do |preview_path|
Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
end
if preview_path.nil?
raise PreviewTemplateError, "preview template for example #{example} does not exist"
end
path = Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
Pathname.new(path)
.relative_path_from(Pathname.new(preview_path))
.to_s
.sub(/\..*$/, "")
Pathname.new(path).
relative_path_from(Pathname.new(preview_path)).
to_s.
sub(/\..*$/, "")
end
# Returns the method body for the example from the preview file.

Просмотреть файл

@ -32,30 +32,31 @@ module ViewComponent
raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if defined?(@__vc_content_block) && defined?(@__vc_content_set_by_with_content)
@content = if defined?(@__vc_component_instance)
if defined?(@__vc_content_set_by_with_content)
@__vc_component_instance.with_content(@__vc_content_set_by_with_content)
@content =
if defined?(@__vc_component_instance)
if defined?(@__vc_content_set_by_with_content)
@__vc_component_instance.with_content(@__vc_content_set_by_with_content)
view_context.capture do
@__vc_component_instance.render_in(view_context)
view_context.capture do
@__vc_component_instance.render_in(view_context)
end
elsif defined?(@__vc_content_block)
view_context.capture do
# render_in is faster than `parent.render`
@__vc_component_instance.render_in(view_context, &@__vc_content_block)
end
else
view_context.capture do
@__vc_component_instance.render_in(view_context)
end
end
elsif defined?(@__vc_content)
@__vc_content
elsif defined?(@__vc_content_block)
view_context.capture do
# render_in is faster than `parent.render`
@__vc_component_instance.render_in(view_context, &@__vc_content_block)
end
else
view_context.capture do
@__vc_component_instance.render_in(view_context)
end
end
elsif defined?(@__vc_content)
@__vc_content
elsif defined?(@__vc_content_block)
view_context.capture(&@__vc_content_block)
elsif defined?(@__vc_content_set_by_with_content)
@__vc_content_set_by_with_content
end
view_context.capture(&@__vc_content_block)
elsif defined?(@__vc_content_set_by_with_content)
@__vc_content_set_by_with_content
end
@content
end

Просмотреть файл

@ -136,7 +136,7 @@ module ViewComponent
# Append Slot instance to collection accessor Array
instance_variable_get(slot[:instance_variable_name]) << slot_instance
else
# Assign the Slot instance to the slot accessor
# Assign the Slot instance to the slot accessor
instance_variable_set(slot[:instance_variable_name], slot_instance)
end

Просмотреть файл

@ -230,13 +230,14 @@ module ViewComponent
# Use `bind(self)` to ensure lambda is executed in the context of the
# current component. This is necessary to allow the lambda to access helper
# methods like `content_tag` as well as parent component state.
renderable_value = if block_given?
slot_definition[:renderable_function].bind(self).call(*args, **kwargs) do |*args, **kwargs|
view_context.capture(*args, **kwargs, &block)
renderable_value =
if block_given?
slot_definition[:renderable_function].bind(self).call(*args, **kwargs) do |*args, **kwargs|
view_context.capture(*args, **kwargs, &block)
end
else
slot_definition[:renderable_function].bind(self).call(*args, **kwargs)
end
else
slot_definition[:renderable_function].bind(self).call(*args, **kwargs)
end
# Function calls can return components, so if it's a component handle it specially
if renderable_value.respond_to?(:render_in)

Просмотреть файл

@ -52,7 +52,7 @@ module ViewComponent
def scope_data(data)
@i18n_scope.reverse_each do |part|
data = { part => data}
data = { part => data }
end
data
end
@ -70,9 +70,10 @@ module ViewComponent
key = key&.to_s unless key.is_a?(String)
key = "#{i18n_scope}#{key}" if key.start_with?(".")
translated = catch(:exception) do
i18n_backend.translate(locale, key, options)
end
translated =
catch(:exception) do
i18n_backend.translate(locale, key, options)
end
# Fallback to the global translations
if translated.is_a? ::I18n::MissingTranslation

Просмотреть файл

@ -1,8 +1,8 @@
# frozen_string_literal: true
class SlotsV2Component < ViewComponent::Base
renders_one :header, -> (**kwargs) { HeaderComponent.new(**kwargs) }
renders_many :items, -> (**kwargs) { ItemComponent.new(**kwargs) }
renders_one :header, ->(**kwargs) { HeaderComponent.new(**kwargs) }
renders_many :items, ->(**kwargs) { ItemComponent.new(**kwargs) }
class HeaderComponent < ViewComponent::Base
attr_reader :classes

Просмотреть файл

@ -2,7 +2,7 @@
module NestedSharedState
class TableComponent < ViewComponent::Base
renders_one :header, -> (arg = nil, **system_arguments, &block) do
renders_one :header, ->(arg = nil, **system_arguments, &block) do
header_system_arguments = system_arguments
header_system_arguments[:selectable] = @selectable

Просмотреть файл

@ -3,12 +3,14 @@
# This code intentionally has a bug where there is an extra comma after the
# :notice reader. `Kernel.silence_warnings` is in place to avoid Ruby emitting
# warnings in test output.
# rubocop:disable all
Kernel.silence_warnings do
class ProductReaderOopsComponent < ViewComponent::Base
attr_reader :product,
:notice,
attr_reader :product, :notice,
def initialize(product_reader_oops:)
end
end
end
# rubocop:enable all

Просмотреть файл

@ -3,7 +3,7 @@
class SlotsV2Component < ViewComponent::Base
renders_one :title
renders_one :subtitle
renders_one :footer, -> (classes: "", &block) do
renders_one :footer, ->(classes: "", &block) do
content_tag :footer, class: "footer #{classes}" do
block.call if block
end
@ -11,7 +11,7 @@ class SlotsV2Component < ViewComponent::Base
renders_many :tabs
renders_many :items, -> (highlighted: false) do
renders_many :items, ->(highlighted: false) do
MyHighlightComponent.new(highlighted: highlighted)
end
renders_one :extra, "ExtraComponent"

Просмотреть файл

@ -2,5 +2,5 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path("../config/environment", __FILE__)
require ::File.expand_path("../config/environment", __FILE__)
run Sandbox::Application

Просмотреть файл

@ -17,7 +17,7 @@ Sandbox::Application.configure do
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
config.action_controller.allow_forgery_protection = false
config.view_component.show_previews = true

Просмотреть файл

@ -1,3 +1,3 @@
# frozen_string_literal: true
Rails.application.config.assets.precompile += %w( admin.css )
Rails.application.config.assets.precompile += %w(admin.css)

Просмотреть файл

@ -1,4 +1,5 @@
# frozen_string_literal: true
require "simplecov"
require "simplecov-console"

Просмотреть файл

@ -10,9 +10,9 @@ class ViewComponent::Base::UnitTest < Minitest::Test
"/tilda~/component/test_component.html.haml"
]
expected = [
{variant: :phone, handler: "erb"},
{variant: :desktop, handler: "slim"},
{variant: nil, handler: "haml"}
{ variant: :phone, handler: "erb" },
{ variant: :desktop, handler: "slim" },
{ variant: nil, handler: "haml" }
]
compiler = ViewComponent::Compiler.new(ViewComponent::Base)
@ -30,17 +30,19 @@ class ViewComponent::Base::UnitTest < Minitest::Test
def test_calling_helpers_outside_render_raises
component = ViewComponent::Base.new
err = assert_raises ViewComponent::Base::ViewContextCalledBeforeRenderError do
component.helpers
end
err =
assert_raises ViewComponent::Base::ViewContextCalledBeforeRenderError do
component.helpers
end
assert_equal "`helpers` can only be called at render time.", err.message
end
def test_calling_controller_outside_render_raises
component = ViewComponent::Base.new
err = assert_raises ViewComponent::Base::ViewContextCalledBeforeRenderError do
component.controller
end
err =
assert_raises ViewComponent::Base::ViewContextCalledBeforeRenderError do
component.controller
end
assert_equal "`controller` can only be called at render time.", err.message
end

Просмотреть файл

@ -312,10 +312,10 @@ class IntegrationTest < ActionDispatch::IntegrationTest
end
def test_renders_preview_source
get "/rails/view_components/preview_component/default"
get "/rails/view_components/preview_component/default"
assert_select ".view-component-source-example h2", "Source:"
assert_select ".view-component-source-example pre.source code"
assert_select ".view-component-source-example h2", "Source:"
assert_select ".view-component-source-example pre.source code"
end
def test_renders_preview_source_with_template_from_layout
@ -400,9 +400,10 @@ class IntegrationTest < ActionDispatch::IntegrationTest
if Rails.version.to_f >= 6.1
def test_rendering_component_using_the_render_component_helper_raises_an_error
error = assert_raises ActionView::Template::Error do
get "/render_component"
end
error =
assert_raises ActionView::Template::Error do
get "/render_component"
end
assert_match(/undefined method `render_component'/, error.message)
end
end
@ -496,9 +497,10 @@ class IntegrationTest < ActionDispatch::IntegrationTest
end
def test_raises_an_error_if_the_template_is_not_present_and_the_render_with_template_method_is_used_in_the_example
error = assert_raises ViewComponent::PreviewTemplateError do
get "/rails/view_components/inline_component/without_template"
end
error =
assert_raises ViewComponent::PreviewTemplateError do
get "/rails/view_components/inline_component/without_template"
end
assert_match(/preview template for example without_template does not exist/, error.message)
end

Просмотреть файл

@ -34,7 +34,6 @@ class SlotableTest < ViewComponent::TestCase
end
end
assert_selector(".card.mt-4")
assert_selector(".title", text: "This is my title!")
@ -82,7 +81,6 @@ class SlotableTest < ViewComponent::TestCase
end
end
assert_selector(".card.mt-4")
assert_selector(".title", text: "This is my title!")
@ -100,11 +98,12 @@ class SlotableTest < ViewComponent::TestCase
end
def test_invalid_slot_class_raises_error
exception = assert_raises ArgumentError do
render_inline(BadSlotComponent.new) do |component|
component.slot(:title)
exception =
assert_raises ArgumentError do
render_inline(BadSlotComponent.new) do |component|
component.slot(:title)
end
end
end
assert_includes exception.message, "Title must inherit from ViewComponent::Slot"
end
@ -129,27 +128,30 @@ class SlotableTest < ViewComponent::TestCase
end
def test_renders_slots_template_raise_with_unknown_content_areas
exception = assert_raises ArgumentError do
render_inline(SlotsComponent.new) do |component|
component.slot(:foo) { "Hello!" }
exception =
assert_raises ArgumentError do
render_inline(SlotsComponent.new) do |component|
component.slot(:foo) { "Hello!" }
end
end
end
assert_includes exception.message, "Unknown slot 'foo' - expected one of '[:title, :subtitle, :footer, :tab, :item]'"
end
def test_with_slot_raise_with_duplicate_slot_name
exception = assert_raises ArgumentError do
SlotsComponent.with_slot :title
end
exception =
assert_raises ArgumentError do
SlotsComponent.with_slot :title
end
assert_includes exception.message, "title slot declared multiple times"
end
def test_with_slot_raise_with_content_keyword
exception = assert_raises ArgumentError do
SlotsComponent.with_slot :content
end
exception =
assert_raises ArgumentError do
SlotsComponent.with_slot :content
end
assert_includes exception.message, ":content is a reserved slot name"
end

Просмотреть файл

@ -125,9 +125,10 @@ class SlotsV2sTest < ViewComponent::TestCase
end
def test_sub_component_raise_with_duplicate_slot_name
exception = assert_raises ArgumentError do
SlotsV2Component.renders_one :title
end
exception =
assert_raises ArgumentError do
SlotsV2Component.renders_one :title
end
assert_includes exception.message, "title slot declared multiple times"
end
@ -264,7 +265,7 @@ class SlotsV2sTest < ViewComponent::TestCase
def test_slot_with_nested_blocks_content_selectable_true
render_inline(NestedSharedState::TableComponent.new(selectable: true)) do |table_card|
table_card.header("regular_argument", class_names: "table__header extracted_kwarg", data: { splatted_kwarg: "splatted_keyword_argument"}) do |header|
table_card.header("regular_argument", class_names: "table__header extracted_kwarg", data: { splatted_kwarg: "splatted_keyword_argument" }) do |header|
header.cell { "Cell1" }
header.cell(class_names: "-has-sort") { "Cell2" }
end
@ -302,11 +303,12 @@ class SlotsV2sTest < ViewComponent::TestCase
end
def test_component_raises_when_given_invalid_slot_name
exception = assert_raises ArgumentError do
Class.new(ViewComponent::Base) do
renders_one :content
exception =
assert_raises ArgumentError do
Class.new(ViewComponent::Base) do
renders_one :content
end
end
end
assert_includes exception.message, "content is not a valid slot name"
end
@ -339,14 +341,15 @@ class SlotsV2sTest < ViewComponent::TestCase
end
def test_raises_if_using_both_block_content_and_with_content
error = assert_raises ArgumentError do
component = SlotsV2Component.new
slot = component.title("some_argument")
slot.with_content("This is my title!")
slot.__vc_content_block = "some block"
error =
assert_raises ArgumentError do
component = SlotsV2Component.new
slot = component.title("some_argument")
slot.with_content("This is my title!")
slot.__vc_content_block = "some block"
render_inline(component)
end
render_inline(component)
end
assert_equal "Block provided after calling `with_content`. Use one or the other.", error.message
end

Просмотреть файл

@ -18,15 +18,20 @@ class TranslatableTest < ViewComponent::TestCase
end
def test_multi_key_support
assert_equal [
"Hello from sidecar translations!",
"This is coming from the sidecar",
"This is coming from Rails",
], translate([
".hello",
".from.sidecar",
"from.rails",
])
assert_equal(
[
"Hello from sidecar translations!",
"This is coming from the sidecar",
"This is coming from Rails",
],
translate(
[
".hello",
".from.sidecar",
"from.rails",
]
)
)
end
def test_relative_keys_missing_from_component_translations

Просмотреть файл

@ -34,19 +34,21 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_raise_error_when_content_already_set
error = assert_raises ArgumentError do
render_inline(WrapperComponent.new.with_content("setter content")) do
"block content"
error =
assert_raises ArgumentError do
render_inline(WrapperComponent.new.with_content("setter content")) do
"block content"
end
end
end
assert_includes error.message, "Block provided after calling `with_content`"
end
def test_raise_error_when_component_implements_with_content
exception = assert_raises ViewComponent::ComponentError do
render_inline(InvalidWithRenderComponent.new)
end
exception =
assert_raises ViewComponent::ComponentError do
render_inline(InvalidWithRenderComponent.new)
end
assert_includes exception.message, "InvalidWithRenderComponent implements a reserved method, `with_content`."
end
@ -58,9 +60,10 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_raises_error_when_with_content_is_called_withot_any_values
exception = assert_raises ArgumentError do
WrapperComponent.new.with_content(nil)
end
exception =
assert_raises ArgumentError do
WrapperComponent.new.with_content(nil)
end
assert_equal "No content provided.", exception.message
end
@ -283,19 +286,21 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_renders_content_areas_template_raise_with_unknown_content_areas
exception = assert_raises ArgumentError do
render_inline(ContentAreasComponent.new(footer: "Bye!")) do |component|
component.with(:foo) { "Hello!" }
exception =
assert_raises ArgumentError do
render_inline(ContentAreasComponent.new(footer: "Bye!")) do |component|
component.with(:foo) { "Hello!" }
end
end
end
assert_includes exception.message, "Unknown content_area 'foo' - expected one of '[:title, :body, :footer]'"
end
def test_with_content_areas_raise_with_content_keyword
exception = assert_raises ArgumentError do
ContentAreasComponent.with_content_areas :content
end
exception =
assert_raises ArgumentError do
ContentAreasComponent.with_content_areas :content
end
assert_includes exception.message, ":content is a reserved content area name"
end
@ -469,18 +474,20 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_validations_component
exception = assert_raises ActiveModel::ValidationError do
render_inline(ValidationsComponent.new)
end
exception =
assert_raises ActiveModel::ValidationError do
render_inline(ValidationsComponent.new)
end
assert_equal "Validation failed: Content can't be blank", exception.message
end
# TODO: Remove in v3.0.0
def test_before_render_check
exception = assert_raises ActiveModel::ValidationError do
render_inline(OldValidationsComponent.new)
end
exception =
assert_raises ActiveModel::ValidationError do
render_inline(OldValidationsComponent.new)
end
assert_equal "Validation failed: Content can't be blank", exception.message
end
@ -500,51 +507,57 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_raises_error_when_sidecar_template_is_missing
exception = assert_raises ViewComponent::TemplateError do
render_inline(MissingTemplateComponent.new)
end
exception =
assert_raises ViewComponent::TemplateError do
render_inline(MissingTemplateComponent.new)
end
assert_includes exception.message, "Could not find a template file or inline render method for MissingTemplateComponent"
end
def test_raises_error_when_more_than_one_sidecar_template_is_present
error = assert_raises ViewComponent::TemplateError do
render_inline(TooManySidecarFilesComponent.new)
end
error =
assert_raises ViewComponent::TemplateError do
render_inline(TooManySidecarFilesComponent.new)
end
assert_includes error.message, "More than one template found for TooManySidecarFilesComponent."
end
def test_raises_error_when_more_than_one_sidecar_template_for_a_variant_is_present
error = assert_raises ViewComponent::TemplateError do
render_inline(TooManySidecarFilesForVariantComponent.new)
end
error =
assert_raises ViewComponent::TemplateError do
render_inline(TooManySidecarFilesForVariantComponent.new)
end
assert_includes error.message, "More than one template found for variants 'test' and 'testing' in TooManySidecarFilesForVariantComponent"
end
def test_raise_error_when_default_template_file_and_inline_default_call_exist
error = assert_raises ViewComponent::TemplateError do
render_inline(DefaultTemplateAndInlineDefaultTemplateComponent.new)
end
error =
assert_raises ViewComponent::TemplateError do
render_inline(DefaultTemplateAndInlineDefaultTemplateComponent.new)
end
assert_includes error.message, "Template file and inline render method found for DefaultTemplateAndInlineDefaultTemplateComponent."
end
def test_raise_error_when_variant_template_file_and_inline_variant_call_exist
error = assert_raises ViewComponent::TemplateError do
with_variant :phone do
render_inline(VariantTemplateAndInlineVariantTemplateComponent.new)
error =
assert_raises ViewComponent::TemplateError do
with_variant :phone do
render_inline(VariantTemplateAndInlineVariantTemplateComponent.new)
end
end
end
assert_includes error.message, "Template file and inline render method found for variant 'phone' in VariantTemplateAndInlineVariantTemplateComponent."
end
def test_raise_error_when_template_file_and_sidecar_directory_template_exist
error = assert_raises ViewComponent::TemplateError do
render_inline(TemplateAndSidecarDirectoryTemplateComponent.new)
end
error =
assert_raises ViewComponent::TemplateError do
render_inline(TemplateAndSidecarDirectoryTemplateComponent.new)
end
assert_includes error.message, "More than one template found for TemplateAndSidecarDirectoryTemplateComponent."
end
@ -558,9 +571,10 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_backtrace_returns_correct_file_and_line_number
error = assert_raises NameError do
render_inline(ExceptionInTemplateComponent.new)
end
error =
assert_raises NameError do
render_inline(ExceptionInTemplateComponent.new)
end
assert_match %r[app/components/exception_in_template_component\.html\.erb:2], error.backtrace[0]
end
@ -622,18 +636,20 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_render_collection_missing_collection_object
exception = assert_raises ArgumentError do
render_inline(ProductComponent.with_collection("foo"))
end
exception =
assert_raises ArgumentError do
render_inline(ProductComponent.with_collection("foo"))
end
assert_equal exception.message, "The value of the argument isn't a valid collection. Make sure it responds to to_ary: \"foo\""
end
def test_render_collection_missing_arg
products = [OpenStruct.new(name: "Radio clock"), OpenStruct.new(name: "Mints")]
exception = assert_raises ArgumentError do
render_inline(ProductComponent.with_collection(products))
end
exception =
assert_raises ArgumentError do
render_inline(ProductComponent.with_collection(products))
end
assert_match(/missing keyword/, exception.message)
assert_match(/notice/, exception.message)
@ -649,19 +665,21 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_collection_component_missing_parameter_name
exception = assert_raises ArgumentError do
render_inline(MissingCollectionParameterNameComponent.with_collection([]))
end
exception =
assert_raises ArgumentError do
render_inline(MissingCollectionParameterNameComponent.with_collection([]))
end
assert_match(/MissingCollectionParameterNameComponent initializer must accept `foo` collection parameter/, exception.message)
end
def test_collection_component_missing_default_parameter_name
exception = assert_raises ArgumentError do
render_inline(
MissingDefaultCollectionParameterComponent.with_collection([OpenStruct.new(name: "Mints")])
)
end
exception =
assert_raises ArgumentError do
render_inline(
MissingDefaultCollectionParameterComponent.with_collection([OpenStruct.new(name: "Mints")])
)
end
assert_match(/MissingDefaultCollectionParameterComponent initializer must accept `missing_default_collection_parameter` collection parameter/, exception.message)
end
@ -671,9 +689,10 @@ class ViewComponentTest < ViewComponent::TestCase
old_cache = ViewComponent::CompileCache.cache
ViewComponent::CompileCache.cache = Set.new
exception = assert_raises ViewComponent::ComponentError do
InvalidParametersComponent.compile(raise_errors: true)
end
exception =
assert_raises ViewComponent::ComponentError do
InvalidParametersComponent.compile(raise_errors: true)
end
assert_match(/InvalidParametersComponent initializer cannot contain `content` since it will override a public ViewComponent method/, exception.message)
ensure
@ -686,9 +705,10 @@ class ViewComponentTest < ViewComponent::TestCase
old_cache = ViewComponent::CompileCache.cache
ViewComponent::CompileCache.cache = Set.new
exception = assert_raises ViewComponent::ComponentError do
InvalidNamedParametersComponent.compile(raise_errors: true)
end
exception =
assert_raises ViewComponent::ComponentError do
InvalidNamedParametersComponent.compile(raise_errors: true)
end
assert_match(/InvalidNamedParametersComponent initializer cannot contain `content` since it will override a public ViewComponent method/, exception.message)
ensure
@ -697,11 +717,12 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_collection_component_with_trailing_comma_attr_reader
exception = assert_raises ArgumentError do
render_inline(
ProductReaderOopsComponent.with_collection(["foo"])
)
end
exception =
assert_raises ArgumentError do
render_inline(
ProductReaderOopsComponent.with_collection(["foo"])
)
end
assert_match(/ProductReaderOopsComponent initializer is empty or invalid/, exception.message)
end
@ -752,17 +773,18 @@ class ViewComponentTest < ViewComponent::TestCase
end
def test_collection_parameter_does_not_require_compile
dynamic_component = Class.new(ViewComponent::Base) do
with_collection_parameter :greeting
dynamic_component =
Class.new(ViewComponent::Base) do
with_collection_parameter :greeting
def initialize(greeting = "hello world")
@greeting = greeting
end
def initialize(greeting = "hello world")
@greeting = greeting
end
def call
content_tag :h1, @greeting
def call
content_tag :h1, @greeting
end
end
end
# Necessary because anonymous classes don't have a `name` property
Object.const_set("MY_COMPONENT", dynamic_component)