Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to specify non-existent field for combobox #28

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/presenters/hotwire_combobox/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def hidden_field_data
end

def hidden_field_value
form&.object&.public_send(name) || value
pranavbabu marked this conversation as resolved.
Show resolved Hide resolved
form&.object&.try(name) || value
end


Expand Down
15 changes: 15 additions & 0 deletions test/application_view_test_case.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ def assert_attrs(tag, tag_name: :input, **attrs)
assert_match /<#{tag_name}.* #{attrs}/, tag
end

def mock_form(form_object: OpenStruct.new)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the instinct to stub this out in the spirit of encapsulation.

In this case I'd rather not stub the form builder methods since they don't "belong" to us.

Let's test the real thing instead. SQLite supports JSON columns. Let's add one to one of the fixtures instead and use that in the tests instead of mocking the form.

form = OpenStruct.new
form.define_singleton_method(:field_id) { |name| "#{name}_id" }
form.define_singleton_method(:field_name) { |name| name }
form.define_singleton_method(:object) { form_object }
form_object.define_singleton_method(:public_send) do |method_name, *args|
if form_object.respond_to?(method_name)
super(method_name, *args)
else
raise NoMethodError, "undefined method `#{method_name}` for #{form_object.inspect}"
end
end
form
end

private
def escape_specials(value)
special_characters = Regexp.union "[]".chars
Expand Down
49 changes: 49 additions & 0 deletions test/presenters/hotwire_combobox/component_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require "test_helper"

class HotwireCombobox::ComponentTest < ApplicationViewTestCase
setup do
@view = ActionView::Base.new(ActionController::Base.view_paths, {}, ActionController::Base.new)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we're inheriting from ApplicationViewTestCase the view object should be accessible by just calling #view anywhere in the test cases. No need to initialize here.

We use this in the Listbox::Option tests in the #render method.

end

test "hidden_field_attrs returns value from form object if available" do
existent_field_on_model = "Peter"
field_name = :name
Comment on lines +9 to +10
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test is clear enough that we don't need these explaining variables. Let's inline the values instead. Same goes for the other tests.

It's okay to introduce a bit of harmless repetition in order to keep less things in mind while reading these tests 👍

component = HotwireCombobox::Component.new @view, field_name,
form: mock_form(form_object: OpenStruct.new("#{field_name}": existent_field_on_model))

assert_equal component.hidden_field_attrs, { id: "#{field_name}_id-hw-hidden-field",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of asserting all attrs, let's just assert that the attr hash includes the correct name and value.

name: :name,
data: { hw_combobox_target: "hiddenField" },
value: existent_field_on_model }
end

test "hidden_field_attrs returns component value if not available in form object" do
field_name = "options[name]"
specified_value = "Peter"
component = HotwireCombobox::Component.new(
@view, field_name,
form: mock_form,
value: specified_value
)

assert_equal component.hidden_field_attrs, { id: "#{field_name}_id-hw-hidden-field",
name: field_name,
data: { hw_combobox_target: "hiddenField" },
value: specified_value }

end

test "hidden_field_attrs returns nil for value if neither form object nor component value is available" do
field_name = "options[name]"
component = HotwireCombobox::Component.new(
@view, field_name,
form: mock_form,
)

assert_equal component.hidden_field_attrs, { id: "#{field_name}_id-hw-hidden-field",
name: field_name,
data: { hw_combobox_target: "hiddenField" },
value: nil }

end
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
end
end

Loading