germsvel / phoenix_test

MIT License
144 stars 20 forks source link

Support multiple checkboxes #77

Closed totaltrash closed 2 months ago

totaltrash commented 3 months ago

I'm hoping this is something that can be supported by PhoenixTest - this strategy was supported by the removed fill_form but no longer works with the new form helpers (check etc.).

As an alternative to multiple selects, sometimes I will use multiple checkboxes to emulate the behavior of a multiple select - here's a simple example:

image

<div>
  <input type="checkbox" name="roles[]" id="edit_user_form_roles_admin" value="admin">
  <label for="edit_user_form_roles_admin">Administrator</label>
</div>
<div>
  <input type="checkbox" name="roles[]" id="edit_user_form_roles_user" value="user">
  <label for="edit_user_form_roles_user">User</label>
</div>

Phoenix/LiveView handles this just fine, converting the params provided to phx-change and phx-submit to %{"roles" => ["admin" , ...]}.

PhoenixTest, since the introduction of the new form handlers now results in:

** (ArgumentError) could not find non-disabled input, select or textarea with name "roles" within:
         <input type="checkbox" name="roles[]" id="edit_user_form_roles_admin" value="admin"/>
         <input type="checkbox" name="roles[]" id="edit_user_form_roles_user" value="user" checked="checked"/>
totaltrash commented 3 months ago

Furthermore, I sometimes do similar with hidden inputs that are used to back an interactive component for searching and selecting for multiple values.

totaltrash commented 3 months ago

I've been doing a bit of digging into how live view is handling this. Basically any param appended with [] is decoded into a list:

Plug.Conn.Query.decode("roles[]=aaa&roles[]=bbb")
%{"roles" => ["aaa", "bbb"]}

See https://github.com/elixir-plug/plug/blob/82eb2204f59e6e2f4b40cbcab1699076f04a5758/lib/plug/conn/query.ex#L22

Plug.Conn.Query.decode is called from here for live view form submissions and changes:

https://github.com/phoenixframework/phoenix_live_view/blob/bc000b9d681e2456946b08e6e6ed0795bb77ff0e/lib/phoenix_live_view/channel.ex#L774

My proposal would be to treat all submitted params in this way - any param ending in [] should be converted to a list.

germsvel commented 3 months ago

I think multiple selects should now be handled on main. PR #71 introduced something for it. @totaltrash could you check with main and see if what you're looking for is handled?

totaltrash commented 3 months ago

Thanks @germsvel, I updated to main and unfortunately this is not handled - see PR for some failing tests

soundmonster commented 2 months ago

If you extend your example like this:

<label for="edit_user_form_roles">Roles</label>
<input id="edit_user_form_roles" name="roles" type="hidden" value="">
<div>
  <input type="checkbox" name="roles[]" id="edit_user_form_roles_admin" value="admin">
  <label for="edit_user_form_roles_admin">Administrator</label>
</div>
<div>
  <input type="checkbox" name="roles[]" id="edit_user_form_roles_user" value="user">
  <label for="edit_user_form_roles_user">User</label>
</div>

then you can use fill_in with a list like this:

session
|> fill_in("Roles", with: ["user", "admin"])

It's a bit of a hacky workaround but it works until there's proper support for this kind of form layout.

N.B. the example above is what Petal Components does. They call it a checkbox group:

Screenshot 2024-06-12 at 17 55 12

@germsvel would it make sense to use the Petal Components lib as a testbed for PhoenixTest and its form features?

germsvel commented 2 months ago

@soundmonster to your question:

would it make sense to use the Petal Components lib as a testbed for PhoenixTest and its form features?

What do you have in mind? What do you mean by a testbed? (I'm assuming a helpful place to test each release of phoenix_test against?) I don't have an association to Petal Components, nor have I ever used them.