defmodule ExshomeTest.LiveViewHelpers do @moduledoc """ API to help testing live views. """ @endpoint ExshomeWeb.Endpoint import Phoenix.ConnTest import Phoenix.LiveViewTest @doc """ Renders a live app page and returns a view. Raises when something bad happens. """ @spec live_with_dependencies(Plug.Conn.t(), module(), atom()) :: Phoenix.LiveViewTest.View def live_with_dependencies(%Plug.Conn{} = conn, app_module, action) when is_atom(app_module) and is_atom(action) do start_dependencies(app_module, action) {:ok, view, _html} = live(conn, app_module.path(conn, action)) view end @doc """ Renders a preview for app page and returns a view. Raises when something bad happens. """ @spec live_preview(Plug.Conn.t(), module()) :: Phoenix.LiveViewTest.View def live_preview(%Plug.Conn{} = conn, app_module) when is_atom(app_module) do module = app_page(app_module, :preview) {:ok, view, _html} = live_isolated(conn, module, []) view end @doc """ Starts dependencies and renders a preview for app page. Returns a view. Raises when something bad happens. """ @spec live_preview_with_dependencies(Plug.Conn.t(), module()) :: Phoenix.LiveViewTest.View def live_preview_with_dependencies(%Plug.Conn{} = conn, app_module) when is_atom(app_module) do start_dependencies(app_module, :preview) live_preview(conn, app_module) end @doc """ Extracts value from input element by selector. """ def get_value(view, selector) do [value] = view |> render() |> Floki.attribute(selector, "value") value end @spec start_dependencies(module(), atom()) :: :ok def start_dependencies(app_module, action) when is_atom(app_module) and is_atom(action) do supervised_dependencies = app_module |> app_page(action) |> then(& &1.dependencies()) |> Keyword.keys() |> Enum.into(MapSet.new()) |> Enum.filter(&function_exported?(&1, :child_spec, 1)) for dependency <- supervised_dependencies do ExshomeTest.TestRegistry.start_dependency(dependency) end :ok end defp app_page(app_module, :preview), do: app_module.preview() defp app_page(app_module, action) do app_module.pages() |> Enum.filter(&(&1.action() == action)) |> List.first() end end