View Source Phoenix.LiveViewTest (Phoenix LiveView v1.0.0)

Conveniences for testing function components as well as LiveViews and LiveComponents.

Testing function components

There are two mechanisms for testing function components. Imagine the following component:

def greet(assigns) do
  ~H"""
  <div>Hello, {@name}!</div>
  """
end

You can test it by using render_component/3, passing the function reference to the component as first argument:

import Phoenix.LiveViewTest

test "greets" do
  assert render_component(&MyComponents.greet/1, name: "Mary") ==
           "<div>Hello, Mary!</div>"
end

However, for complex components, often the simplest way to test them is by using the ~H sigil itself:

import Phoenix.Component
import Phoenix.LiveViewTest

test "greets" do
  assigns = %{}
  assert rendered_to_string(~H"""
         <MyComponents.greet name="Mary" />
         """) ==
           "<div>Hello, Mary!</div>"
end

The difference is that we use rendered_to_string/1 to convert the rendered template to a string for testing.

Testing LiveViews and LiveComponents

In LiveComponents and LiveView tests, we interact with views via process communication in substitution of a browser. Like a browser, our test process receives messages about the rendered updates from the view which can be asserted against to test the life-cycle and behavior of LiveViews and their children.

Testing LiveViews

The life-cycle of a LiveView as outlined in the Phoenix.LiveView docs details how a view starts as a stateless HTML render in a disconnected socket state. Once the browser receives the HTML, it connects to the server and a new LiveView process is started, remounted in a connected socket state, and the view continues statefully. The LiveView test functions support testing both disconnected and connected mounts separately, for example:

import Plug.Conn
import Phoenix.ConnTest
import Phoenix.LiveViewTest
@endpoint MyEndpoint

test "disconnected and connected mount", %{conn: conn} do
  conn = get(conn, "/my-path")
  assert html_response(conn, 200) =~ "<h1>My Disconnected View</h1>"

  {:ok, view, html} = live(conn)
end

test "redirected mount", %{conn: conn} do
  assert {:error, {:redirect, %{to: "/somewhere"}}} = live(conn, "my-path")
end

Here, we start by using the familiar Phoenix.ConnTest function, get/2 to test the regular HTTP GET request which invokes mount with a disconnected socket. Next, live/1 is called with our sent connection to mount the view in a connected state, which starts our stateful LiveView process.

In general, it's often more convenient to test the mounting of a view in a single step, provided you don't need the result of the stateless HTTP render. This is done with a single call to live/2, which performs the get step for us:

test "connected mount", %{conn: conn} do
  {:ok, _view, html} = live(conn, "/my-path")
  assert html =~ "<h1>My Connected View</h1>"
end

Testing Events

The browser can send a variety of events to a LiveView via phx- bindings, which are sent to the handle_event/3 callback. To test events sent by the browser and assert on the rendered side effect of the event, use the render_* functions:

  • render_click/1 - sends a phx-click event and value, returning the rendered result of the handle_event/3 callback.

  • render_focus/2 - sends a phx-focus event and value, returning the rendered result of the handle_event/3 callback.

  • render_blur/1 - sends a phx-blur event and value, returning the rendered result of the handle_event/3 callback.

  • render_submit/1 - sends a form phx-submit event and value, returning the rendered result of the handle_event/3 callback.

  • render_change/1 - sends a form phx-change event and value, returning the rendered result of the handle_event/3 callback.

  • render_keydown/1 - sends a form phx-keydown event and value, returning the rendered result of the handle_event/3 callback.

  • render_keyup/1 - sends a form phx-keyup event and value, returning the rendered result of the handle_event/3 callback.

  • render_hook/3 - sends a hook event and value, returning the rendered result of the handle_event/3 callback.

For example:

{:ok, view, _html} = live(conn, "/thermo")

assert view
       |> element("button#inc")
       |> render_click() =~ "The temperature is: 31℉"

In the example above, we are looking for a particular element on the page and triggering its phx-click event. LiveView takes care of making sure the element has a phx-click and automatically sends its values to the server.

You can also bypass the element lookup and directly trigger the LiveView event in most functions:

assert render_click(view, :inc, %{}) =~ "The temperature is: 31℉"

The element style is preferred as much as possible, as it helps LiveView perform validations and ensure the events in the HTML actually matches the event names on the server.

Testing regular messages

LiveViews are GenServer's under the hood, and can send and receive messages just like any other server. To test the side effects of sending or receiving messages, simply message the view and use the render function to test the result:

send(view.pid, {:set_temp, 50})
assert render(view) =~ "The temperature is: 50℉"

Testing LiveComponents

LiveComponents can be tested in two ways. One way is to use the same render_component/2 function as function components. This will mount the LiveComponent and render it once, without testing any of its events:

assert render_component(MyComponent, id: 123, user: %User{}) =~
         "some markup in component"

However, if you want to test how components are mounted by a LiveView and interact with DOM events, you must use the regular live/2 macro to build the LiveView with the component and then scope events by passing the view and a DOM selector in a list:

{: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?()

In the example above, LiveView will lookup for an element with ID=user-13 and retrieve its phx-target. If phx-target points to a component, that will be the component used, otherwise it will fallback to the view.

Summary

Functions

Asserts a live patch will happen within timeout milliseconds. The default timeout is ExUnit's assert_receive_timeout (100 ms).

Asserts a live patch will happen to a given path within timeout milliseconds.

Asserts a live patch was performed, and returns the new path.

Asserts an event will be pushed within timeout. The default timeout is ExUnit's assert_receive_timeout (100 ms).

Asserts a redirect will happen within timeout milliseconds. The default timeout is ExUnit's assert_receive_timeout (100 ms).

Asserts a redirect will happen to a given path within timeout milliseconds.

Asserts a redirect was performed.

Asserts a hook reply was returned from a handle_event callback.

Returns an element to scope a function to.

Builds a file input for testing uploads within a form.

Gets the nested LiveView child by child_id from the parent LiveView.

Follows the redirect from a render_* action or an {:error, redirect} tuple.

Receives a form_element and asserts that phx-trigger-action has been set to true, following up on that request.

Returns a form element to scope a function to.

Checks if the given element exists on the page.

Checks if the given selector with text_filter is on view.

Spawns a connected LiveView process.

Returns the current list of LiveView children for the parent LiveView.

Spawns a connected LiveView process mounted in isolation as the sole rendered element.

Performs a live redirect from one LiveView to another.

Open the default browser to display current HTML of view_or_element.

Returns the most recent title that was updated via a page_title assign.

Performs a preflight upload request.

Puts connect params to be used on LiveView connections.

Puts the submitter element_or_selector on the given form element.

Refutes a redirect to a given path was performed.

Returns the HTML string of the rendered view or element.

Awaits all current assign_async and start_async for a given LiveView or element.

Sends a blur event given by element and returns the rendered result.

Sends a blur event to the view and returns the rendered result.

Sends a form change event given by element and returns the rendered result.

Sends a form change event to the view and returns the rendered result.

Sends a click event given by element and returns the rendered result.

Sends a click event to the view with value and returns the rendered result.

Sends a focus event given by element and returns the rendered result.

Sends a focus event to the view and returns the rendered result.

Sends a hook event to the view or an element and returns the rendered result.

Sends a keydown event given by element and returns the rendered result.

Sends a keydown event to the view and returns the rendered result.

Sends a keyup event given by element and returns the rendered result.

Sends a keyup event to the view and returns the rendered result.

Simulates a push_patch to the given path and returns the rendered result.

Sends a form submit event given by element and returns the rendered result.

Sends a form submit event to the view and returns the rendered result.

Performs an upload of a file input and renders the result.

Converts a rendered template to a string.

Receives a form element and submits the HTTP request through the plug pipeline.

Sets the target of the view for events.

Functions

Link to this function

assert_patch(view, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))

View Source

Asserts a live patch will happen within timeout milliseconds. The default timeout is ExUnit's assert_receive_timeout (100 ms).

It returns the new path.

To assert on the flash message, you can assert on the result of the rendered LiveView.

Examples

render_click(view, :event_that_triggers_patch)
assert_patch view

render_click(view, :event_that_triggers_patch)
assert_patch view, 30

render_click(view, :event_that_triggers_patch)
path = assert_patch view
assert path =~ ~r/path/+/
Link to this function

assert_patch(view, to, timeout)

View Source

Asserts a live patch will happen to a given path within timeout milliseconds.

The default timeout is ExUnit's assert_receive_timeout (100 ms).

It returns the new path.

To assert on the flash message, you can assert on the result of the rendered LiveView.

Examples

render_click(view, :event_that_triggers_patch)
assert_patch view, "/path"

render_click(view, :event_that_triggers_patch)
assert_patch view, "/path", 30
Link to this function

assert_patched(view, to)

View Source

Asserts a live patch was performed, and returns the new path.

To assert on the flash message, you can assert on the result of the rendered LiveView.

Examples

render_click(view, :event_that_triggers_redirect)
assert_patched view, "/path"
Link to this macro

assert_push_event(view, event, payload, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))

View Source (macro)

Asserts an event will be pushed within timeout. The default timeout is ExUnit's assert_receive_timeout (100 ms).

Examples

assert_push_event view, "scores", %{points: 100, user: "josé"}
Link to this function

assert_redirect(view, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))

View Source

Asserts a redirect will happen within timeout milliseconds. The default timeout is ExUnit's assert_receive_timeout (100 ms).

It returns a tuple containing the new path and the flash messages from said redirect, if any. Note the flash will contain string keys.

Examples

render_click(view, :event_that_triggers_redirect)
{path, flash} = assert_redirect view
assert flash["info"] == "Welcome"
assert path =~ ~r/path\/\d+/

render_click(view, :event_that_triggers_redirect)
assert_redirect view, 30
Link to this function

assert_redirect(view, to, timeout)

View Source

Asserts a redirect will happen to a given path within timeout milliseconds.

The default timeout is ExUnit's assert_receive_timeout (100 ms).

It returns the flash messages from said redirect, if any. Note the flash will contain string keys.

Examples

render_click(view, :event_that_triggers_redirect)
flash = assert_redirect view, "/path"
assert flash["info"] == "Welcome"

render_click(view, :event_that_triggers_redirect)
assert_redirect view, "/path", 30
Link to this function

assert_redirected(view, to)

View Source

Asserts a redirect was performed.

It returns the flash messages from said redirect, if any. Note the flash will contain string keys.

Examples

render_click(view, :event_that_triggers_redirect)
flash = assert_redirected view, "/path"
assert flash["info"] == "Welcome"
Link to this macro

assert_reply(view, payload, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))

View Source (macro)

Asserts a hook reply was returned from a handle_event callback.

The default timeout is ExUnit's assert_receive_timeout (100 ms).

Examples

assert_reply view, %{result: "ok", transaction_id: _}
Link to this function

element(view, selector, text_filter \\ nil)

View Source

Returns an element to scope a function to.

It expects the current LiveView, a query selector, and a text filter.

An optional text filter may be given to filter the results by the query selector. If the text filter is a string or a regex, it will match any element that contains the string (including as a substring) or matches the regex.

So a link containing the text "unopened" will match element("a", "opened"). To prevent this, a regex could specify that "opened" appear without the prefix "un". For example, element("a", ~r{(?<!un)opened}). But it may be clearer to add an HTML attribute to make the element easier to select.

After the text filter is applied, only one element must remain, otherwise an error is raised.

If no text filter is given, then the query selector itself must return a single element.

assert view
      |> element("#term > :first-child", "Increment")
      |> render() =~ "Increment</a>"

Attribute selectors are also supported, and may be used on special cases like ids which contain periods:

assert view
       |> element(~s{[href="/foo"][id="foo.bar.baz"]})
       |> render() =~ "Increment</a>"
Link to this macro

file_input(view, form_selector, name, entries)

View Source (macro)

Builds a file input for testing uploads within a form.

Given the form DOM selector, the upload name, and a list of maps of client metadata for the upload, the returned file input can be passed to render_upload/2.

Client metadata takes the following form:

  • :last_modified - the last modified timestamp
  • :name - the name of the file
  • :content - the binary content of the file
  • :size - the byte size of the content
  • :type - the MIME type of the file
  • :relative_path - for simulating webkitdirectory metadata
  • :meta - optional metadata sent by the client

Examples

avatar = file_input(lv, "#my-form-id", :avatar, [%{
  last_modified: 1_594_171_879_000,
  name: "myfile.jpeg",
  content: File.read!("myfile.jpg"),
  size: 1_396_009,
  type: "image/jpeg"
}])

assert render_upload(avatar, "myfile.jpeg") =~ "100%"
Link to this function

find_live_child(parent, child_id)

View Source

Gets the nested LiveView child by child_id from the parent LiveView.

Examples

{:ok, view, _html} = live(conn, "/thermo")
assert clock_view = find_live_child(view, "clock")
assert render_click(clock_view, :snooze) =~ "snoozing"
Link to this macro

follow_redirect(reason, conn, to \\ nil)

View Source (macro)

Follows the redirect from a render_* action or an {:error, redirect} tuple.

Imagine you have a LiveView that redirects on a render_click event. You can make sure it immediately redirects after the render_click action by calling follow_redirect/3:

live_view
|> render_click("redirect")
|> follow_redirect(conn)

Or in the case of an error tuple:

assert {:error, {:redirect, %{to: "/somewhere"}}} = result = live(conn, "my-path")
{:ok, view, html} = follow_redirect(result, conn)

follow_redirect/3 expects a connection as second argument. This is the connection that will be used to perform the underlying request.

If the LiveView redirects with a live redirect, this macro returns {:ok, live_view, disconnected_html} with the content of the new LiveView, the same as the live/3 macro. If the LiveView redirects with a regular redirect, this macro returns {:ok, conn} with the rendered redirected page. In any other case, this macro raises.

Finally, note that you can optionally assert on the path you are being redirected to by passing a third argument:

live_view
|> render_click("redirect")
|> follow_redirect(conn, "/redirected/page")
Link to this macro

follow_trigger_action(form, conn)

View Source (macro)

Receives a form_element and asserts that phx-trigger-action has been set to true, following up on that request.

Imagine you have a LiveView that sends an HTTP form submission. Say that it sets the phx-trigger-action to true, as a response to a submit event. You can follow the trigger action like this:

form = form(live_view, selector, %{"form" => "data"})

# First we submit the form. Optionally verify that phx-trigger-action
# is now part of the form.
assert render_submit(form) =~ ~r/phx-trigger-action/

# Now follow the request made by the form
conn = follow_trigger_action(form, conn)
assert conn.method == "POST"
assert conn.params == %{"form" => "data"}
Link to this function

form(view, selector, form_data \\ %{})

View Source

Returns a form element to scope a function to.

It expects the current LiveView, a query selector, and the form data. The query selector must return a single element.

The form data will be validated directly against the form markup and make sure the data you are changing/submitting actually exists, failing otherwise.

Examples

assert view
      |> form("#term", user: %{name: "hello"})
      |> render_submit() =~ "Name updated"

This function is meant to mimic what the user can actually do, so you cannot set hidden input values. However, hidden values can be given when calling render_submit/2 or render_change/2, see their docs for examples.

Checks if the given element exists on the page.

Examples

assert view |> element("#some-element") |> has_element?()
Link to this function

has_element?(view, selector, text_filter \\ nil)

View Source

Checks if the given selector with text_filter is on view.

See element/3 for more information.

Examples

assert has_element?(view, "#some-element")
Link to this macro

live(conn, path \\ nil)

View Source (macro)

Spawns a connected LiveView process.

If a path is given, then a regular get(conn, path) is done and the page is upgraded to a LiveView. If no path is given, it assumes a previously rendered %Plug.Conn{} is given, which will be converted to a LiveView immediately.

Examples

{:ok, view, html} = live(conn, "/path")
assert view.module == MyLive
assert html =~ "the count is 3"

assert {:error, {:redirect, %{to: "/somewhere"}}} = live(conn, "/path")

Returns the current list of LiveView children for the parent LiveView.

Children are returned in the order they appear in the rendered HTML.

Examples

{:ok, view, _html} = live(conn, "/thermo")
assert [clock_view] = live_children(view)
assert render_click(clock_view, :snooze) =~ "snoozing"
Link to this macro

live_isolated(conn, live_view, opts \\ [])

View Source (macro)

Spawns a connected LiveView process mounted in isolation as the sole rendered element.

Useful for testing LiveViews that are not directly routable, such as those built as small components to be re-used in multiple parents. Testing routable LiveViews is still recommended whenever possible since features such as live navigation require routable LiveViews.

Options

  • :session - the session to be given to the LiveView

All other options are forwarded to the LiveView for rendering. Refer to Phoenix.Component.live_render/3 for a list of supported render options.

Examples

{:ok, view, html} =
  live_isolated(conn, MyAppWeb.ClockLive, session: %{"tz" => "EST"})

Use put_connect_params/2 to put connect params for a call to Phoenix.LiveView.get_connect_params/1 in Phoenix.LiveView.mount/3:

{:ok, view, html} =
  conn
  |> put_connect_params(%{"param" => "value"})
  |> live_isolated(AppWeb.ClockLive, session: %{"tz" => "EST"})
Link to this function

live_redirect(view, opts)

View Source

Performs a live redirect from one LiveView to another.

When redirecting between two LiveViews of the same live_session, mounts the new LiveView and shutsdown the previous one, which mimics general browser live navigation behaviour.

When attempting to navigate from a LiveView of a different live_session, an error redirect condition is returned indicating a failed push_navigate from the client.

Examples

assert {:ok, page_live, _html} = live(conn, "/page/1")
assert {:ok, page2_live, _html} = live(conn, "/page/2")

assert {:error, {:redirect, _}} = live_redirect(page2_live, to: "/admin")
Link to this function

open_browser(view_or_element, open_fun \\ &open_with_system_cmd/1)

View Source

Open the default browser to display current HTML of view_or_element.

Examples

view
|> element("#term > :first-child", "Increment")
|> open_browser()

assert view
       |> form("#term", user: %{name: "hello"})
       |> open_browser()
       |> render_submit() =~ "Name updated"

Returns the most recent title that was updated via a page_title assign.

Examples

render_click(view, :event_that_triggers_page_title_update)
assert page_title(view) =~ "my title"
Link to this function

preflight_upload(upload)

View Source

Performs a preflight upload request.

Useful for testing external uploaders to retrieve the :external entry metadata.

Examples

avatar = file_input(lv, "#my-form-id", :avatar, [%{name: ..., ...}, ...])
assert {:ok, %{ref: _ref, config: %{chunk_size: _}}} = preflight_upload(avatar)
Link to this function

put_connect_params(conn, params)

View Source

Puts connect params to be used on LiveView connections.

See Phoenix.LiveView.get_connect_params/1.

Link to this function

put_submitter(form, element_or_selector)

View Source

Puts the submitter element_or_selector on the given form element.

A submitter is an element that initiates the form's submit event on the client. When a submitter is put on an element created with form/3 and then the form is submitted via render_submit/2, the name/value pair of the submitter will be included in the submit event payload.

The given element or selector must exist within the form and match one of the following:

  • A button or input element with type="submit".

  • A button element without a type attribute.

Examples

form = view |> form("#my-form")

assert form
       |> put_submitter("button[name=example]")
       |> render_submit() =~ "Submitted example"
Link to this macro

refute_push_event(view, event, payload, timeout \\ Application.fetch_env!(:ex_unit, :refute_receive_timeout))

View Source (macro)

Refutes an event will be pushed within timeout.

The default timeout is ExUnit's refute_receive_timeout (100 ms).

Examples

refute_push_event view, "scores", %{points: _, user: "josé"}
Link to this function

refute_redirected(view, to)

View Source

Refutes a redirect to a given path was performed.

It returns :ok if the specified redirect isn't already in the mailbox.

Examples

render_click(view, :event_that_triggers_redirect_to_path)
:ok = refute_redirected view, "/wrong_path"

Returns the HTML string of the rendered view or element.

If a view is provided, the entire LiveView is rendered. If a view after calling with_target/2 or an element are given, only that particular context is returned.

Examples

{:ok, view, _html} = live(conn, "/thermo")
assert render(view) =~ ~s|<button id="alarm">Snooze</div>|

assert view
       |> element("#alarm")
       |> render() == "Snooze"
Link to this function

render_async(view_or_element, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))

View Source

Awaits all current assign_async and start_async for a given LiveView or element.

It renders the LiveView or Element once complete and returns the result. The default timeout is ExUnit's assert_receive_timeout (100 ms).

Examples

{:ok, lv, html} = live(conn, "/path")
assert html =~ "loading data..."
assert render_async(lv) =~ "data loaded!"
Link to this function

render_blur(element, value \\ %{})

View Source

Sends a blur event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-blur attribute in it. The event name given set on phx-blur is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values can be given with the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("#inactive")
       |> render_blur() =~ "Tap to wake"
Link to this function

render_blur(view, event, value)

View Source

Sends a blur event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_blur(view, :inactive) =~ "Tap to wake"
Link to this function

render_change(element, value \\ %{})

View Source

Sends a form change event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-change attribute in it. The event name given set on phx-change is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values.

If you need to pass any extra values or metadata, such as the "_target" parameter, you can do so by giving a map under the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("form")
       |> render_change(%{deg: 123}) =~ "123 exceeds limits"

# Passing metadata
{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("form")
       |> render_change(%{_target: ["deg"], deg: 123}) =~ "123 exceeds limits"

As with render_submit/2, hidden input field values can be provided like so:

refute view
      |> form("#term", user: %{name: "hello"})
      |> render_change(%{user: %{"hidden_field" => "example"}}) =~ "can't be blank"
Link to this function

render_change(view, event, value)

View Source

Sends a form change event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_change(view, :validate, %{deg: 123}) =~ "123 exceeds limits"
Link to this function

render_click(element, value \\ %{})

View Source

Sends a click event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-click attribute in it. The event name given set on phx-click is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values can be given with the value argument.

If the element does not have a phx-click attribute but it is a link (the <a> tag), the link will be followed accordingly:

  • if the link is a patch, the current view will be patched
  • if the link is a navigate, this function will return {:error, {:live_redirect, %{to: url}}}, which can be followed with follow_redirect/2
  • if the link is a regular link, this function will return {:error, {:redirect, %{to: url}}}, which can be followed with follow_redirect/2

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("button", "Increment")
       |> render_click() =~ "The temperature is: 30℉"
Link to this function

render_click(view, event, value)

View Source

Sends a click event to the view with value and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temperature is: 30℉"
assert render_click(view, :inc) =~ "The temperature is: 31℉"
Link to this macro

render_component(component, assigns \\ Macro.escape(%{}), opts \\ [])

View Source (macro)

Renders a component.

The first argument may either be a function component, as an anonymous function:

assert render_component(&Weather.city/1, name: "Kraków") =~
         "some markup in component"

Or a stateful component as a module. In this case, this function will mount, update, and render the component. The :id option is a required argument:

assert render_component(MyComponent, id: 123, user: %User{}) =~
         "some markup in component"

If your component is using the router, you can pass it as argument:

assert render_component(MyComponent, %{id: 123, user: %User{}}, router: SomeRouter) =~
         "some markup in component"
Link to this function

render_focus(element, value \\ %{})

View Source

Sends a focus event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-focus attribute in it. The event name given set on phx-focus is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values can be given with the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("#inactive")
       |> render_focus() =~ "Tap to wake"
Link to this function

render_focus(view, event, value)

View Source

Sends a focus event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_focus(view, :inactive) =~ "Tap to wake"
Link to this function

render_hook(view_or_element, event, value \\ %{})

View Source

Sends a hook event to the view or an element and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_hook(view, :refresh, %{deg: 32}) =~ "The temp is: 32℉"

If you are pushing events from a hook to a component, then you must pass an element, created with element/3, as first argument and it must point to a single element on the page with a phx-target attribute in it:

{:ok, view, _html} = live(conn, "/thermo")
assert view
       |> element("#thermo-component")
       |> render_hook(:refresh, %{deg: 32}) =~ "The temp is: 32℉"
Link to this function

render_keydown(element, value \\ %{})

View Source

Sends a keydown event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-keydown or phx-window-keydown attribute in it. The event name given set on phx-keydown is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values can be given with the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert view |> element("#inc") |> render_keydown() =~ "The temp is: 31℉"
Link to this function

render_keydown(view, event, value)

View Source

Sends a keydown event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_keydown(view, :inc) =~ "The temp is: 31℉"
Link to this function

render_keyup(element, value \\ %{})

View Source

Sends a keyup event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-keyup or phx-window-keyup attribute in it. The event name given set on phx-keyup is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values can be given with the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert view |> element("#inc") |> render_keyup() =~ "The temp is: 31℉"
Link to this function

render_keyup(view, event, value)

View Source

Sends a keyup event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_keyup(view, :inc) =~ "The temp is: 31℉"
Link to this function

render_patch(view, path)

View Source

Simulates a push_patch to the given path and returns the rendered result.

Link to this function

render_submit(element, value \\ %{})

View Source

Sends a form submit event given by element and returns the rendered result.

The element is created with element/3 and must point to a single element on the page with a phx-submit attribute in it. The event name given set on phx-submit is then sent to the appropriate LiveView (or component if phx-target is set accordingly). All phx-value-* entries in the element are sent as values. Extra values, including hidden input fields, can be given with the value argument.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")

assert view
       |> element("form")
       |> render_submit(%{deg: 123, avatar: upload}) =~ "123 exceeds limits"

To submit a form along with some with hidden input values:

assert view
       |> form("#term", user: %{name: "hello"})
       |> render_submit(%{user: %{"hidden_field" => "example"}}) =~ "Name updated"

To submit a form by a specific submit element via put_submitter/2:

assert view
       |> form("#term", user: %{name: "hello"})
       |> put_submitter("button[name=example_action]")
       |> render_submit() =~ "Action taken"
Link to this function

render_submit(view, event, value)

View Source

Sends a form submit event to the view and returns the rendered result.

It returns the contents of the whole LiveView or an {:error, redirect} tuple.

Examples

{:ok, view, html} = live(conn, "/thermo")
assert html =~ "The temp is: 30℉"
assert render_submit(view, :refresh, %{deg: 32}) =~ "The temp is: 32℉"
Link to this function

render_upload(upload, entry_name, percent \\ 100)

View Source

Performs an upload of a file input and renders the result.

See file_input/4 for details on building a file input.

Examples

Given the following LiveView template:

<%= for entry <- @uploads.avatar.entries do %>
  {entry.name}: {entry.progress}%
<% end %>

Your test case can assert the uploaded content:

avatar = file_input(lv, "#my-form-id", :avatar, [
  %{
    last_modified: 1_594_171_879_000,
    name: "myfile.jpeg",
    content: File.read!("myfile.jpg"),
    size: 1_396_009,
    type: "image/jpeg"
  }
])

assert render_upload(avatar, "myfile.jpeg") =~ "100%"

By default, the entire file is chunked to the server, but an optional percentage to chunk can be passed to test chunk-by-chunk uploads:

assert render_upload(avatar, "myfile.jpeg", 49) =~ "49%"
assert render_upload(avatar, "myfile.jpeg", 51) =~ "100%"

Before making assertions about the how the upload is consumed server-side, you will need to call render_submit/1.

In the case where an upload progress callback issues a navigate, patch, or redirect, the following will be returned:

  • for a patch, the current view will be patched
  • for a navigate, this function will return {:error, {:live_redirect, %{to: url}}}, which can be followed with follow_redirect/2
  • for a regular redirect, this function will return {:error, {:redirect, %{to: url}}}, which can be followed with follow_redirect/2
Link to this function

rendered_to_string(rendered)

View Source

Converts a rendered template to a string.

Examples

import Phoenix.Component
import Phoenix.LiveViewTest

test "greets" do
  assigns = %{}
  assert rendered_to_string(~H"""
         <MyComponents.greet name="Mary" />
         """) ==
           "<div>Hello, Mary!</div>"
end
Link to this macro

submit_form(form, conn)

View Source (macro)

Receives a form element and submits the HTTP request through the plug pipeline.

Imagine you have a LiveView that validates form data, but submits the form to a controller via the normal form action attribute. This is especially useful in scenarios where the result of a form submit needs to write to the plug session.

You can follow submit the form with the %Plug.Conn{}, like this:

form = form(live_view, selector, %{"form" => "data"})

# Now submit the LiveView form to the plug pipeline
conn = submit_form(form, conn)
assert conn.method == "POST"
assert conn.params == %{"form" => "data"}
Link to this function

with_target(view, target)

View Source

Sets the target of the view for events.

This emulates phx-target directly in tests, without having to dispatch the event to a specific element. This can be useful for invoking events to one or multiple components at the same time:

view
|> with_target("#user-1,#user-2")
|> render_click("Hide", %{})