Issue in calling render_submit of a LiveViewComponent from the live_view test case

render_submit() event of LiveViewComponent is not triggered during the test case, it always tries to look for the event in LiveView (parent) - but the actual event is defined in LiveComponent(child)

Live View

defmodule UserWeb.Users.Index do
  use Phoenix.LiveView

  alias UserWeb.UserView

  @default_state %{
    action?: nil,
    user_id: nil,
    users: [],
    info_flash: nil
  }

  def render(assign) do
    UserView.render("index.html", assign)
  end

  def mount(_params, _session, socket) do
    users = get_users_list()
    {:ok, assign(socket, %{@default_state | users: users})}
  end

  def handle_event("new", _params, socket) do
    {:noreply,
     live_redirect(socket,
       to: UserWeb.Router.Helpers.users_new_path(socket, __MODULE__),
       replace: false
     )}
  end

  def handle_event("edit", %{"user-id" => user_id}, socket) do
    new_socket =
      socket
      |> assign(:user_id, user_id)

    {:noreply,
     live_redirect(new_socket,
       to:
         UserWeb.Router.Helpers.users_edit_path(
           new_socket,
           __MODULE__,
           user_id
         ),
       replace: false
     )}
  end

  def handle_params(_params, _uri, "new", socket) do
    {:noreply, assign(socket, :action?, "new")}
  end

  def handle_params(_params, _uri, "edit", socket) do
    {:noreply, assign(socket, :action?, "edit")}
  end
end

index.html.leex

<div class="card">
  <%= if @action? == "new" do %>
    <%= live_component(@socket, UserWeb.Users.CreateComponent, id: :new) %>
  <% end %>
  <%= if @action? == "edit" do %>
    <%= live_component(@socket, UserWeb.Users.EditComponent, id: :edit, user_id: @user_id) %> 
  <% end %>
  <%= unless @action? do %>
    <div class="card-header">
      <strong>Users</strong>
      <a class="btn btn-sm btn-success ml-3 pull-right" phx-click="new">
        <i class="fa fa-plus mr-1"></i> Create
      </a>
    </div>
    <div class="card-body">
      <div class="row">
        <%= if @users == [] do %>
          <div class="col-lg-12">
            <h5 class="text-center">No Records found for Users.</h5>
          </div>
        <% else %>
          <div class="col-lg-12">
            <table class="table table-responsive-md table-striped">
              <thead>
                <th>Name</th>
                <th>E-mail</th>
              </thead>
              <tbody>
                <%= for user <- @users do %>
                  <tr>
                    <td><%= user.name %></td>
                    <td><%= user.email %></td>
                    <td>
                      <button phx-click="edit" phx-value-user-id="<%= user.id %>" class="btn btn-sm btn-circle btn-info"><i class="fa fa-pencil mr-1"></i></button>
                    </td>
                  </tr>
                <% end %>
              </tbody>
            </table>
          </div>
        <% end %>
      </div>
    </div>
  <% end %>
</div>

create_component.ex

defmodule UserWeb.Users.CreateComponent do
  use Phoenix.LiveComponent

  alias UserWeb.UserView
  
  def render(assigns) do
    UserView.render("new.html", assigns)
  end

  def mount(socket) do
    {:ok, assign(socket, changeset: %User{})}
  end

  def handle_event("insert", %{"user" => params}, socket) do
    case add_user(params) do
      {:ok, %User{}} ->
        send(self(), :record_created)
        {:noreply, socket}

      {:error, _} ->
        send(self(), :record_exists)
        {:noreply, assign(socket, :changeset, %User{})}
    end
  end

  def add_user(params) do
    "code"
  end
end

new.html.leex

<div class="card-header">
  <strong>Create New User</strong>
</div>
<div class="card-body">
  <div class="row">
    <div class="col-lg-12">
      <div id="<%= @id %>">
        <%= f = form_for @changeset, "#", [phx_submit: :insert, "phx-target": "##{@id}"] %>
          <div class="form-group">
            <%= label f, :Name %>
            <%= text_input f, :name, class: "form-control" %>
            <%= error_tag f, :name %>
          </div>

          <div class="form-group">
            <%= label f, :Email %>
            <%= text_input f, :email, class: "form-control" %>
            <%= error_tag f, :email %>
          </div>

          <div class="form-actions">
            <%= submit class: "btn btn-primary" do %>
              <i class="fa fa-save"></i> Create
            <% end %>
            <a phx-click="cancel" class="btn btn-danger">
              <i class="fa fa-ban mr-1"></i> Cancel
            </a>
          </div>
        </form>
      </div>
    </div>
  </div>
</div>

test_live.ex

defmodule UserWeb.Users..IndexLiveTest do
  use PaymentsFlaskWeb.ConnCase
  import Phoenix.LiveViewTest
  
  setup do
    users = get_users()

    %{users: users}
  end

  test "disconnected and connected mount", %{conn: conn, users: users} do
    conn = get(conn, "/web-app/users")
    html_response = html_response(conn, 200)

    assert html_response =~ "Users Lisitng"
    assert html_response =~ users.name)
    assert {:ok, _view, _html} = live(conn)
  end

  test "open user registration form", %{conn: conn} do
    assert {:ok, view, html} = live(conn, "/web-app/users")
    assert html =~ "Users Lisitng"

    assert render_click(view, :new) =~ "new"
  end

  test "render user registration form", %{conn: conn} do
    new_user = %{name: "User 001", email: "some@email.com")
  
    assert {:ok, view, html} = live(conn, "/web-app/users/new")
    assert html =~ "Create new user"

    render_submit(
      [view, :new],
      :insert,
      %{"user" => new_user}
    )
  end
end

Below is the error

** (EXIT from #PID<0.1046.0>) an exception was raised:
** (ArgumentError) no component with ID “new” found in view

As seen in the source code: https://github.com/phoenixframework/phoenix_live_view/btelob/v0.11.1/lib/phoenix_live_view/test/live_view_test.ex#L510

Events are hardcoded to be sent to the LiveView module and makes no use of phx-target.

Currently, this looks like a limitation of LiveView testing that it cannot test events in the components but only in the parent view.

In the latest version of LiveView (0.12.0), you could test a component by using element/2

  {:ok, view, html} = live(conn, "/users")
  html = view |> element("#user-13 a", "Delete") |> render_click()
  refute html =~ "user-13"
  refute view |> element("#user-13") |> has_element?()

https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html#module-testing-components

1 Like

Hello @shankardevy,

I found the issue, it was with the DB connection.

Anyways thanks for the suggestion. render_submit also worked.