Hey, been having very fun with LiveView and the new Components!
So we are trying to find a structure where we can generate forms in our liveviews with compile-time variable checks and we found a way that is working well except when writing the unit tests on the render functions with render_component.
These input components basically look like this:
defmodule TextInput do
use AppWeb, :component
@enforce_keys [:label, :field]
defstruct [:label, :field, :f]
def render(%TextInput{} = assigns) do
~H"""
<%= label @f, @label %>
<%= text_input @f, @field %>
<%= error_tag @f, @field %>
"""
end
In the liveview, we assign the fields of a form like this
fields: [
%TextInput{
label: "Name",
field: :name
},
%TextInput{
label: "Translation Key",
field: :translation_key
}
]
In the heex we render them using a Fields module like this (inside a .form div)
<%= for field <- @fields do %>
<%= Fields.render(field, f) %>
<% end %>
Which are pattern-matched like this (so it picks up diferent types of input fields and renders them using the right struct-backed component)
def render(%TextInput{} = assigns, f) do
assigns
|> Map.put(:f, f)
|> TextInput.render()
end
This works very well until we want to test these components with render_component
The following test code gives a “Enumerable not implemented for type %TextInput{}”, which can be temporarily fixed by implementing the Enumerable with its functions, but we are looking for a better solution to all this.
test "render a text input on good TextInput params" do
changeset = Person.changeset(%Person{}, %{name: "name"})
params = %TextInput{
label: "test",
field: :name,
f: Phoenix.HTML.Form.form_for(changeset, nil)
}
result = render_component(&TextInput.render/1, params)
assert result =~ "test"
end
Any guidelines are highly appreciated, thanks for taking your time!