Testing LiveView clears text input after submit

I’m trying to test in a LiveViewTest that an input field is cleared after form submission.

There is only one text input that doesn’t need validation so I’m not bothering with a changeset (though I do still notice this problem with a changeset) and am controlling the field like so:

  def mount(_params, _session, socket) do
    # ...
    {:ok, assign(socket, :message_content, ""}

  def render(assigns) do
    <.simple_form let={f} for={:message} ... phx-change="update-input-text" phx-submit="save">
      <.input field={{f, :content}} value={@input_text} />

  def handle_event("update-input-text", %{"message" => message_params}, socket) do
    {:noreply, assign(socket, :message_content, message_params["content"]}

  def handle_event("save", %{"message" => message_params}, socket) do
    # ...
    # successful submit:
    {:noreply, assign(socket, :message_content, "")}
# ...

Then I have this test (this is all simplified—I’m using better selectors and whatnot):

  test "clears output after sending messages", %{conn: conn, room: room} do
    {:ok, lv, _html} = live(conn, ~p"/chat/#{room}")

    |> form("form", %{"message" => %{"content" => "Some message"}})
    |> render_submit()

    refute lv
            |> element("input")
            |> render() =~ "Some message"

The problem is is that if I change the "save" handler to simply return {:noreply, socket} (ie, it’s no longer resetting the message_content assign,) the test still passes. I certainly confirmed in the browser that this is not what’s happening—the text stays in the box. Possibly weirder still is that if I change that line to {:noreply, assign(socket, :message_content, "Some message"} then the test picks that up and fails.

I’ve also tried this with “raw” <form> and <input> elements and it’s the same deal.

It’s my understanding that render_submit/2 simply triggers the phx-submit action for the form. Anyone know what’s going on here?

It fails because as you said it triggers the phx-submit but does not “type into/fill” the input on the page.

To test what you want you need to first trigger the update-input-text event and assert the page has “Some message” (because it will add to the assign and then be displayed on the page) and then submit and assert it was cleared.


Ohhhhhhhhhhhhhhhhhhhhhhh kriky yes of course! Thank you!

For posterity:

  test "clears input after sending messages", %{conn: conn, room: room} do
    {:ok, lv, _html} = live(conn, ~p"/chat/#{room}")

    assert lv
            |> form("form", %{"message" => %{"content" => "Some message"}})
            |> render_change() =~ "Some message"

    refute lv
            |> form("form")
            |> render_submit() =~ "Some message"