Closed revoltaxz closed 8 months ago
Hi @revoltaxz, thanks for opening this issue!
I think I see why your form is failing, and I think it's something we should fix.
PhoenixTest uses LiveViewTest's render_submit/2
helper for LiveView form submissions.
From the docs we can see:
To submit a form along with some with hidden input values:
assert view |> form("#term", user: %{name: "hello"}) |> render_submit(%{user: %{"hidden_field" => "example"}}) =~ "Name updated"
But right now, we're passing all the form data to form/3
-- so we use render_submit/2
without passing hidden values there.
We need to update the code to pass hidden inputs through render_submit/2
's second argument.
I'll try to get to that when I can, but if someone wants to take a stab at it first, feel free!
I don't think it'll be too straightforward since we have to parse the form and pull the hidden fields. But we already do some parsing, so it might not be too complicated either.
@revoltaxz could you share the HTML form you're trying to test that's giving you that error? I'm trying to reproduce this issue, but not hitting it for some reason.
I'm now thinking that the current implementation works (regardless of what the docs say).
And I'm guessing that you're getting that error because your hidden field's HTML doesn't have a value
attribute set. That's why you're seeing the must be one of [""]
error.
@germsvel Sorry my late! Yes, of course, I could:
def render(assigns) do
~H"""
<div>
<.simple_form
for={@form}
id={@id}
phx-submit="submit"
phx-target={@myself}
phx-change="validate"
>
<div class="grid xl:grid-cols-2 lg:grid-cols-2 md:grid-cols-2 sm:grid-cols-1 gap-3">
<.live_select
field={@form[:symbol]}
label="Buscar por"
placeholder="Insira ao menos 4 letras"
phx-target={@myself}
phx-focus="clear"
debounce="500"
options={[]}
update_min_len={4}
dropdown_extra_class="max-h-60 overflow-y-scroll"
/>
<.field
field={@form[:category]}
label="Tipo de posição"
type="select"
options={Helpers.asset_types()}
phx-change="change_category"
/>
<.field
field={@form[:quantity]}
label="Quantidade"
type="number"
step="100"
min="100"
value="100"
/>
<.field field={@form[:price]} label="Valor unitário (R$)" type="text" phx-hook="MoneyMask" />
<.field field={@form[:open_date]} label="Data de compra" type="date" />
<%= if @category == "option" do %>
<.field
field={@form[:contract_type]}
label="Tipo de opção"
type="select"
options={Helpers.options_types()}
/>
<% end %>
</div>
<.field
field={@form[:direction]}
label="Tipo de operação"
type="radio-group"
group_layout="col"
options={Helpers.operation_types()}
/>
<.button type="submit" phx-disable-with="Salvando..." label="Adicionar" />
</.simple_form>
</div>
"""
end
OBS: I'm using the LiveSelect.
@revoltaxz thanks for posting the form. I've never used LiveSelect. I don't see a hidden input there. I imagine the LiveSelect
library is doing some hidden input stuff behind the scenes?
Do you know how you would test that with LiveView? Or how were you testing that previously?
@germsvel No, I was trying to write tests using PhoenixTest, but I found a PR on the Live Select repo with some instructions, so I think that it is possible to pass the hidden input as you mentioned here. Do you think this helps you?
@revoltaxz I don't think it's a matter of whether or not we can test the hidden inputs.
If you look at this branch, I added a test that passes when testing hidden inputs.
I think the issue is that whatever hidden input LiveSelect
is using isn't setting a value
properly (or maybe it sets it with JS or something). But that's why you're seeing the error you're seeing:
** (ArgumentError) value for hidden "position[symbol]" must be one of [""], got: "PETR"
LiveViewTest is saying that position[symbol]
must be one of <potential value
in html element>, but it got "PETR" instead.
So, to give you another example, if you had this HTML
<input type="hidden" name="admin" value="true"/>
And you tried testing it like this:
|> submit_form("#position_form", admin: "Roger")
You would get the error:
** (ArgumentError) value for hidden "admin" must be one of ["true"], got: "Roger"
So, I don't think it's an issue with PhoenixTest. It's an issue of LiveSelect doing something with hidden inputs that is not matching what you're passing to your form.
Does that make sense?
Oh yes, it makes sense! So, I will close this issue and try a workaround with LiveSelect! Thank you for helping me!
Late to the party 😃 I just stumbled upon this thread yesterday by chance...
@revoltaxz @germsvel I have no experience with PhoenixTest
(seems like a cool library btw, I will take a look!), but in order to test a form containing a LiveSelect
input with the standard Phoenix.LiveViewTest
functions the following trick should work:
form_attrs = %{
symbol: "PETR",
category: "stock",
symbol_text_input: "PETR4",
price: "12.50",
quantity: 100,
open_date: "2024-04-01",
direction: "short"
}
Phoenix.LiveView.send_update(
live.pid, # live = your test's live view
LiveSelect.Component,
%{id: live_select_id, value: form_attrs.symbol}
# `live_select_id` is the id of your live select input component
# (you can pass it explicitly, otherwise, one is generated automatically from form + field name)
)
conn
|> form("#position_form", form_attrs)
|> render_submit()
I tested it and it worked for me.
Yes,LiveSelect
does use a hidden input to send the value to the form, and the hidden input's value is set dynamically according to what the user has selected. The value is not set with JS, it's an ordinary LV binding.
However, the interaction with the user (i.e. opening the dropdown and selecting an element) does use JS, and that doesn't run in LV tests of course.
So the send_update/3
call above is used to bypasss the user interaction and programmatically force a selection, which will set the value for the hidden input field.
I think I will add a section to the docs documenting this, since quite a few folks asked similar questions already
Thanks!
Hello! I'm trying to test a Live page with a form with a LiveSelect component. The LiveSelect provides a component with a hidden input with value, but when I try using the
fill_form
orsubmit_form
to pass the arguments, I get the following error:Is there a way to test with hidden inputs in the form?