I am working on a table component with an inline editing feature. When you click on a cell, the content is replaced with an input to edit the value. To cancel the editing, I use phx-click-away to fire the respective event.
I want to unit test this feature but found no obvious way to fire the phx-click-away.
I tried render_click/2 with a random element of the live view but this does not work, when the target does not have a phx-click binding.
There is render_click/3 but that targets the liev view and not the component.
Is there a way to emit a phx-click-away in testing?
This is not ideal in that it doesn’t interact with the element throwing the event; it simulates it with the live view directly and re-renders the view accordingly. But this is how we have been having to trigger the validate event on forms as well.
defmodule TestLiveView do
use Phoenix.LiveView
def mount(_, _, socket) do
{:ok, socket |> assign(form: to_form(%{}, as: "search"))}
end
def render(assigns) do
~H"""
<div>
<button id="outside" type="button" phx-click="noop">Outside</button>
<div id="search-form-container" phx-click-away="clear_search_form">
<.form for={@form} id="search-form">
<.input field={@form[:query]} type="text" phx-change="search_form_update" />
</.form>
</div>
</div>
"""
end
def handle_event("clear_search_form", _params, socket) do
{:noreply, socket |> assign(form: to_form(%{}, as: "search"))}
end
def handle_event("search_form_update", params, socket) do
updated_search_form =
params["search"]
|> to_form(as: "search")
{:noreply, socket |> assign(form: updated_search_form)}
end
def handle_event("noop", _, socket) do
{:noreply, socket}
end
end
defmodule FooWeb.SearchTest do
@moduledoc false
use FooWeb.ConnCase, async: true
import Phoenix.LiveViewTest
test "clears the search term on click away", %{conn: conn} do
{:ok, lv, _html} = live_isolated(conn, TestLiveView)
render_change(element(lv, "#search-form input"), %{"search" => %{"query" => "asdf"}})
html = render_click(element(lv, "#outside"))
refute html =~ "asdf"
end
end
When we run the test, we see the live view receives the “noop” event (from clicking the “outside” button)…
… but the live view does not receive the “clear_search_form” event.
Also, tried to find a way to send a click-away event instead of a click event, but LiveViewTest doesn’t seem to expose a function to do so.
I was able to figure out how to trigger these click events. I mentioned previously they could be triggered directly against the view with render_hook (provided the event handler exists on the live_view).
I was encountering a problem where moving logic to a shared component broke the existing tests. I was able to get past this with the with_target function, where you can pass an ID for the primary div in a LiveComponent, and trigger an event with a specific target component. This allows me to trigger a click away.
Hope this helps, it got me unblocked on this issue.