Tests with render_click + phx-click={JS.dispatch("change")} fail, best way to fix (Testing inputs_for)

:wave:

Hey everyone, I haven’t done too much Phoenix LiveView so far so this may be an easy misunderstanding from me.

Setup

I refactored some code to follow the inputs_for docs to get rid off a bunch of code. The code works.

It’s open source so you can see my PR here: Transition to mainline `.inputs_for` code by PragTob · Pull Request #466 · b310-digital/mindwendel · GitHub

But essentially the offending form looks like this:

    <.simple_form id="form-labels" for={@form} phx-change="save" phx-submit="save">
      <div class="row">
        <div class="col">
          <.inputs_for :let={f_label} field={@form[:labels]}>
            <div class="input-group has-validation mb-2 mt-2">
              <input type="hidden" name="brainstorming[labels_sort][]" value={f_label.index} />
              <.input
                type="color"
                field={f_label[:color]}
                title={gettext("Choose the label color")}
                class="form-control form-control-color"
              />
              <.input
                type="text"
                form_group_wrapper={false}
                phx-debounce={300}
                field={f_label[:name]}
                placeholder={gettext("Type the label name")}
              />

              <.button
                type="button"
                class="btn-outline-secondary"
                name="brainstorming[labels_drop][]"
                value={f_label.index}
                phx-click={JS.dispatch("change")}
              >
                <%= gettext("Remove idea label") %>
              </.button>

              <.error :for={msg <- Enum.map(f_label[:name].errors, &translate_error(&1))}>
                <%= msg %>
              </.error>
            </div>
          </.inputs_for>

          <input type="hidden" name="brainstorming[labels_drop][]" />
        </div>
      </div>
      <div class="row mb-3">
        <div class="col-12 d-grid mt-2">
          <.button
            type="button"
            class="btn btn-secondary"
            name="brainstorming[labels_sort][]"
            value="new"
            phx-click={JS.dispatch("change")}
          >
            <%= gettext("Add idea label") %>
          </.button>
        </div>
      </div>
    </.simple_form>

Problem

Now the problem is I want to test this/there are already tests for this (which is great!).

However, these tests now fail, essentially at this point:

    edit_live_view
    |> element("button", "Add idea label")
    |> render_click()

which tries to click this button:

          <.button
            type="button"
            class="btn btn-secondary"
            name="brainstorming[labels_sort][]"
            value="new"
            phx-click={JS.dispatch("change")}
          >
            <%= gettext("Add idea label") %>
          </.button>

Which throws this error:

  3) test adds and immediately saves new idea label (MindwendelWeb.Admin.BrainstormingLive.EditTest)
     test/mindwendel_web/live/admin/brainstorming_live/edit_test.exs:60
     ** (ArgumentError) no push or navigation command found within JS commands: [["dispatch",{"event":"change"}]]
     code: |> render_click()
     stacktrace:
       (phoenix_live_view 1.0.0-rc.7) lib/phoenix_live_view/test/live_view_test.ex:1106: Phoenix.LiveViewTest.call/2
       test/mindwendel_web/live/admin/brainstorming_live/edit_test.exs:69: (test)

And basically I have failed to find a way to do this properly, I’d also think that this should work but again - not that familiar with LiveView or its testing yet. I understand that it complains that it has no route to navigate to. I just want to simulate clicking the element and assert the state of the page afterwards. I tried to change the click event simply to “save” but that also didn’t work.

I may just be missing a simple helper to use.

On the other hand, since it’s done like this in an official guide/docs I’d hope that either there was an easier helper or this helper worked or pointed you the right way.

Environment

Running phoenix liveview 1.0.0-rc.7. on elixir 1.15.8 & OTP 26

PR/code/docker file for more context here: Transition to mainline `.inputs_for` code by PragTob · Pull Request #466 · b310-digital/mindwendel · GitHub


Thanks for all your help in advance :slight_smile:

Use the form helpers to render_change the form with the values of the buttons. Clicking the button is just a means to make the form include the key/value pair of those.

2 Likes

Thanks a lot! That works! :green_heart:

If google gets anyone here, the full call is:

edit_live_view
 |> element("form#form-labels")
 |> render_change(%{"brainstorming[labels_sort][]" => "new"})

I don’t love how that works but I’ll try to add to the docs to make it easier potentially.

That’s what the JS command does and given live view tests don’t run actual JS you need to mirror the effects of the JS command.

Sure, I get that that’s the case.

I’m just talking about either/both:

  • improve documentation/visibility around this, as I tried and didn’t find it (both mainline docs and maybe in the inputs_for part, whatever the maintainers think is appropriate)
  • maybe render_click could point you that way when it sees these values that it was complaining about being like “hey you try to run a JS command here, but you can’t have a look at render_change” or it might even be able to resolve it itself :man_shrugging:

Just a better experience for the next person running into this situation :slight_smile: