phoenix_test icon indicating copy to clipboard operation
phoenix_test copied to clipboard

When `click_button/2` is used to submit a form `Form.build/1` selects the first button even if it is `type=button`

Open dabaer opened this issue 1 month ago • 1 comments

I believe this is related to #260, in my scenario I am using the Phoenix.Component.inputs_for component to dynamically add association fields.

Specifically I construct the form how the documentation advises:

<input type="hidden" name="event[assoc_drop][]" />

<button
  type="button"
  name="event[assoc_sort][]"
  value="new"
  phx-click={JS.dispatch("change")}
>
  Add Assoc
</button>

<!-- ... -->
 
<.button phx-disable-with="Saving..."variant="primary">Save Event</.button>

And when calling click_button/2 in a test to submit the form, Element.Button.find_first/1 is called which returns the first button of any type to submit the form (in my case the button to add an association).

I was able to work around this by changing Element.Button.find_first/1:

def find_first(html) do
  html
  |> Query.find("button:not([type='button'])") # Avoid buttons of type="button"
  |> case do
    {:found, element} -> build(element)
    {:found_many, elements} -> elements |> Enum.at(0) |> build()
    :not_found -> nil
  end
end

This function is currently only used when constructing the form for submission, but perhaps there is a better way to do this?

Edit: I forgot to mention I originally had this issue with 0.8.3, but it was still happening with 0.9.0.

dabaer avatar Nov 11 '25 15:11 dabaer

@dabaer thanks for opening this issue!

Yeah, it doesn't surprise me that we were looking into the first button regardless of its type. But we should fix that.

You open to contributing with a PR? I'd be happy to review it.

germsvel avatar Dec 01 '25 08:12 germsvel