Testing LiveView form with phx_trigger_action

I’m curious how folks are testing LiveView forms that use phx_trigger_action?

Here’s where its mentioned in the docs: Form bindings — Phoenix LiveView v0.20.2

I have a registration form that I’m validating with LiveView and then submitting to a regular controller action over HTTP.

Once phx-trigger-action is true, LiveView disconnects and then submits the form.

Any idea on how to test that the form actually gets posted?

Calling render_submit/2 returns the rendered HTML which I can test to ensure that there are no changeset errors, but I’m at a loss on how to test that it actually posts.

Here’s my form:

<%= f = form_for @changeset, Routes.user_registration_path(@socket, :create),
  id: "post-form",
  phx_change: "validate",
  phx_submit: "register",
  phx_trigger_action: @trigger_submit %>

  <%= label f, :email %>
  <%= email_input f, :email, required: true, phx_debounce: "blur" %>
  <%= error_tag f, :email %>

  <%= label f, :password %>
  <%= password_input f, :password,
    required: true,
    value: input_value(f, :password),
    phx_debounce: "blur" %>
  <%= error_tag f, :password %>

  <div>
    <%= submit "Register", phx_disable_with: "Registering..." %>
  </div>
</form>

And the corresponding event handlers:

  @impl true
  def handle_event("validate", %{"user" => user_params}, socket) do
    changeset =
      %User{}
      |> Accounts.change_user_registration(user_params)
      |> Map.put(:action, :validate)

    {:noreply, assign(socket, changeset: changeset, changes_from_session: nil)}
  end

  def handle_event("register", %{"user" => user_params}, socket) do
    %User{}
    |> Accounts.change_user_registration(user_params)
    |> Map.put(:action, :validate)
    |> case do
      %{valid?: true} = changeset ->
        {:noreply, assign(socket, changeset: changeset, trigger_submit: true)}

      %{valid?: false} = changeset ->
        {:noreply, assign(socket, changeset: changeset, trigger_submit: false)}
    end
  end

And the test so far:

    test "registers new user", %{conn: conn} do
      {:ok, new_live, html} = live(conn, Routes.user_registration_new_path(conn, :new))

      assert html =~ "<h1>Register</h1>"
      assert html =~ "Log in</a>"
      assert html =~ "Register</a>"

      assert new_live
             |> form("#post-form", user: @invalid_attrs)
             |> render_submit() =~ "can&#39;t be blank"

      refute new_live
             |> form("#post-form", user: @create_attrs)
             |> render_submit() =~ "invalid-feedback"
    end
3 Likes

Bump

I’m having the same issue

Also having the same issue.

Anyone? :slight_smile:

Personally I manually do a POST request (or whatever) to the HTTP endpoint that phx_trigger_action points to, to effectively simulate real life.

It’s a bummer that the LiveView testing tools don’t do this automatically, but you can work around it that way.

Might look something like this:

view
|> form("#some_form", foo: %{field: "value"})
|> render_submit()

# LiveViewTest doesn't jive well with phx_trigger_action yet
# So manually simulate what happens when they submit the form

post(
  conn,
  Routes.foo_path(conn, :create),
  %{"foo" => %{"field" => "value"}}
)
1 Like

Thanks, good enough for now I think.

I don’t know how the test tool can change to include this, but I’d be happy to contribute. I agree that it’s a bummer!

Edit, maybe it would go somewhere here… I will pull down the repo and give it a shot this in the next week or so. phoenix_live_view/dom.ex at master · phoenixframework/phoenix_live_view · GitHub

I made an issue on the repo. LiveViewTest does not support `phx-trigger-action` · Issue #1436 · phoenixframework/phoenix_live_view · GitHub

Sorry, I’ve been meaning to jump back on here for a while. I think I was missing the the point of the phx-trigger-action.

Looking at the docs, it says:

This is useful to perform pre-final validation of a LiveView form submit before posting to a controller route for operations that require Plug session mutation.

So personally, I decided just to test that the final validation happened with the register handler, and not that the form actually submitted. It got me thinking about how I test controllers, and I don’t usually test that the user clicking submit actually submits the form in controller tests. For instance, I’ll test that the :new action renders the form, and I’ll test that the :create action handles the POST; but I don’t actually test that clicking submit actually submits the form. So similar to what @paulstatezny said, I’d just test the controller, but in the actual controller test file.

@carlyleec Personally, I’d say that approach misses a lot of potential value.

Not all tests are created equal. I spent the first 6 years of my career writing unit tests (not integration tests) that simply assumed the integration of the units was working. Looking back, I realize the amount of guarantees these tests provided was limited. And it showed by how often bugs were caught by tests.

If you write tests that demonstrate the integration between the parts, e.g. “I submit this form and it creates the thing” then when you break any part of that chain the test will fail. It’s really useful.

1 Like

It’s merged into the Phoenix liveview repo on master with docs! Jose had a big part in cleaning it up, and it was pushed through. @paulstatezny @carlyleec let’s try it in our apps and report back?

2 Likes

Nice work on that PR! I’ll give that a shot this evening.

1 Like