Spec-Zone.ru › Phoenix

Phoenix.LiveViewTest

Исходный код

Удобные средства для тестирования функциональных компонентов, а также LiveView и LiveComponents.

Тестирование функциональных компонентов

Существует два способа тестирования функциональных компонентов. Рассмотрим следующий компонент:

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

Его можно протестировать с помощью render_component/3, передав ссылку на функцию компонента первым аргументом:

import Phoenix.LiveViewTest

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

Однако для сложных компонентов зачастую проще всего тестировать их с помощью самого сигила ~H:

import Phoenix.Component
import Phoenix.LiveViewTest

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

Разница в том, что для преобразования отрендеренного шаблона в строку для тестирования мы используем rendered_to_string/1.

Тестирование LiveView и LiveComponents

В тестах LiveComponents и LiveView мы взаимодействуем с представлениями посредством обмена сообщениями между процессами вместо браузера. Как и браузер, наш тестовый процесс получает сообщения об обновлениях представления, которые можно проверять, чтобы тестировать жизненный цикл и поведение LiveView и их дочерних компонентов.

Тестирование LiveView

В документации Phoenix.LiveView подробно описан жизненный цикл LiveView: представление сначала отображается как HTML без состояния в отключенном сокете. Получив HTML, браузер подключается к серверу, запускается новый процесс LiveView, представление монтируется повторно в подключенном сокете и продолжает работать с сохранением состояния. Функции тестирования LiveView позволяют отдельно проверять монтирование в отключенном и подключенном состояниях, например:

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

Сначала мы используем знакомую функцию Phoenix.ConnTest, get/2, чтобы проверить обычный HTTP-запрос GET, который вызывает mount с отключенным сокетом. Затем вызывается live/1 с переданным соединением, чтобы смонтировать представление в подключенном состоянии и запустить процесс LiveView с сохранением состояния.

Как правило, удобнее проверять монтирование представления за один шаг, если вам не нужен результат HTTP-рендеринга без сохранения состояния. Для этого достаточно одного вызова live/2, который выполняет за нас шаг get:

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

Тестирование событий

Браузер может отправлять в LiveView различные события с помощью привязок phx-. Они передаются в обратный вызов handle_event/3. Чтобы протестировать события, отправляемые браузером, и проверить побочный эффект события при отображении, используйте функции render_*:

  • render_click/1 — отправляет событие phx-click и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_focus/2 — отправляет событие phx-focus и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_blur/1 — отправляет событие phx-blur и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_submit/1 — отправляет событие phx-submit формы и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_change/1 — отправляет событие phx-change формы и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_keydown/1 — отправляет событие phx-keydown формы и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_keyup/1 — отправляет событие phx-keyup формы и значение, возвращая результат отображения обратного вызова handle_event/3.

  • render_hook/3 — отправляет событие хука и значение, возвращая результат отображения обратного вызова handle_event/3.

Например:

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

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

В приведенном выше примере мы ищем на странице конкретный элемент и вызываем его событие phx-click. LiveView проверяет, что у элемента есть phx-click, и автоматически отправляет его значения на сервер.

В большинстве функций можно также пропустить поиск элемента и напрямую вызвать событие LiveView:

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

По возможности предпочтителен стиль element, поскольку он позволяет LiveView выполнять проверки и удостоверяться, что события в HTML действительно соответствуют именам событий на сервере.

Тестирование обычных сообщений

Внутри LiveView являются GenServer и могут отправлять и получать сообщения, как и любой другой сервер. Чтобы проверить побочные эффекты отправки или получения сообщений, просто отправьте сообщение представлению и используйте функцию render для проверки результата:

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

Тестирование LiveComponents

LiveComponents можно тестировать двумя способами. Первый — использовать ту же функцию render_component/2, что и для функциональных компонентов. Она смонтирует LiveComponent и отобразит его один раз, не тестируя его события:

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

Однако, если вы хотите проверить, как компоненты монтируются в LiveView и взаимодействуют с событиями DOM, необходимо использовать обычный макрос live/2, чтобы создать LiveView с компонентом, а затем задать область действия событий, передав представление и селектор DOM в списке:

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

В приведенном выше примере LiveView выполнит поиск элемента с ID=user-13 и получит его phx-target. Если phx-target указывает на компонент, будет использован этот компонент, в противном случае будет использовано представление.

Необязательные предупреждения тестов

Во время тестов LiveView (с использованием live/3 или live_isolated/3) LiveView по умолчанию выполняет дополнительные проверки. Среди них — обнаружение повторяющихся идентификаторов DOM и LiveComponents. Когда LiveViewTest обнаруживает такую проблему, она приводит к исключению или предупреждению.

Это поведение можно настроить двумя способами:

  1. Конфигурация среды приложения

    В конфигурации приложения можно настроить определенные типы проблем:

     config :phoenix_live_view, :test_warnings,
       duplicate_id: :warn, # one of :warn, :raise, :ignore
       ...

    Поддерживаются следующие ключи:

    • :duplicate_id — если LiveViewTest обнаруживает повторяющийся идентификатор DOM
    • :duplicate_live_component — если LiveViewTest обнаруживает, что LiveComponent отображается несколько раз с одинаковым идентификатором
    • :missing_form_id — если LiveViewTest обнаруживает форму без атрибута ID (это препятствует восстановлению формы)

    Поддерживаются следующие значения:

    • :raise — тест завершается с ошибкой; значение по умолчанию
    • :warn — выводится только предупреждение (тесты всё равно завершатся с ошибкой, если задать вместе с --warnings-as-errors)
    • :ignore — проверка пропускается
  2. Параметр on_error для live/3 или live_isolated/3:

    Если указать live(conn, "/path", on_error: :warn), можно изменить значение по умолчанию для конкретного теста. В этом примере для всех типов обнаружения задается значение :warn. Также можно переопределить только отдельные типы:

     {:ok, view, html} = live(conn, "/path", on_error: [duplicate_id: :ignore])

    это значение будет объединено с глобальной конфигурацией.

Обратите внимание: если в конфигурации для проверки задано значение :ignore, включить ее снова с помощью on_error нельзя.

Сводка

Функции

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

Проверяет, что live patch будет выполнен в течение timeout миллисекунд. Значение timeout по умолчанию — assert_receive_timeout модуля ExUnit (100 мс).

assert_patch(view, to, timeout)

Проверяет, что live patch для заданного пути будет выполнен в течение timeout миллисекунд.

assert_patched(view, to)

Проверяет, что live patch был выполнен, и возвращает новый путь.

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

Проверяет, что событие будет отправлено в течение timeout. Значение timeout по умолчанию — assert_receive_timeout модуля ExUnit (100 мс).

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

Проверяет, что перенаправление будет выполнено в течение timeout миллисекунд. Значение timeout по умолчанию — assert_receive_timeout модуля ExUnit (100 мс).

assert_redirect(view, to, timeout)

Проверяет, что перенаправление на заданный путь будет выполнено в течение timeout миллисекунд.

assert_redirected(view, to)

Проверяет, что перенаправление было выполнено.

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

Проверяет, что ответ хука был возвращен из обратного вызова handle_event.

element(view, selector, text_filter \\ nil)

Возвращает элемент, чтобы ограничить область действия функции.

file_input(view, form_selector, name, entries)

Создает поле ввода файла для тестирования загрузок внутри формы.

find_live_child(parent, child_id)

Получает вложенное дочернее представление LiveView по child_id из родительского представления LiveView parent.

follow_redirect(reason, conn, to \\ nil)

Переходит по перенаправлению из действия render_* или кортежа {:error, redirect}.

follow_trigger_action(form, conn)

Получает form_element и проверяет, что для phx-trigger-action установлено значение true, а затем выполняет этот запрос.

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

Возвращает элемент формы, чтобы ограничить область действия функции.

has_element?(element)

Проверяет, существует ли указанный элемент на странице.

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

Проверяет, присутствует ли на view указанный selector с text_filter.

live(conn, path \\ nil, opts \\ [])

Запускает процесс подключенного LiveView.

live_children(parent)

Возвращает текущий список дочерних представлений LiveView для родительского представления LiveView parent.

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

Запускает процесс подключенного LiveView, смонтированного изолированно в качестве единственного отображаемого элемента.

live_redirect(view, opts)

Выполняет live-перенаправление с одного LiveView на другой.

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

Открывает браузер по умолчанию, чтобы показать текущий HTML view_or_element.

page_title(view)

Возвращает последнее заглавие страницы, обновленное через назначение page_title.

preflight_upload(upload)

Выполняет предварительный запрос на загрузку файла.

put_connect_params(conn, params)

Добавляет параметры подключения, которые будут использоваться при подключении LiveView.

put_submitter(form, element_or_selector)

Добавляет отправителя формы element_or_selector для указанного элемента form.

refute_patched(view)

Проверяет, что live patch для заданного пути не был выполнен.

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

Проверяет, что событие не будет отправлено в течение указанного времени ожидания.

refute_redirected(view)

Проверяет, что перенаправление на заданный путь не было выполнено.

refute_redirected(view, to)
render(view_or_element)

Возвращает HTML-строку отрендеренного представления или элемента.

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

Ожидает завершения всех текущих задач assign_async, stream_async и start_async для указанного LiveView или элемента.

render_blur(element, value \\ %{})

Отправляет событие blur, заданное через element, и возвращает результат отображения.

render_blur(view, event, value)

Отправляет представлению событие blur и возвращает результат отображения.

render_change(element, value \\ %{})

Отправляет событие изменения формы, заданное через element, и возвращает результат отображения.

render_change(view, event, value)

Отправляет представлению событие изменения формы и возвращает результат отображения.

render_click(element, value \\ %{})

Отправляет событие щелчка, заданное через element, и возвращает результат отображения.

render_click(view, event, value)

Отправляет событие щелчка event представлению view с value и возвращает результат отображения.

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

Отображает компонент.

render_focus(element, value \\ %{})

Отправляет событие focus, заданное через element, и возвращает результат отображения.

render_focus(view, event, value)

Отправляет представлению событие focus и возвращает результат отображения.

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

Отправляет событие хука представлению или элементу и возвращает результат отображения.

render_keydown(element, value \\ %{})

Отправляет событие keydown, заданное через element, и возвращает результат отображения.

render_keydown(view, event, value)

Отправляет представлению событие keydown и возвращает результат отображения.

render_keyup(element, value \\ %{})

Отправляет событие keyup, заданное через element, и возвращает результат отображения.

render_keyup(view, event, value)

Отправляет представлению событие keyup и возвращает результат отображения.

render_patch(view, path)

Имитирует push_patch для указанного path и возвращает результат отображения.

render_submit(element, value \\ %{})

Отправляет событие отправки формы, заданное через element, и возвращает результат отображения.

render_submit(view, event, value)

Отправляет представлению событие отправки формы и возвращает результат отображения.

render_upload(upload, entry_name, percent \\ 100)

Выполняет загрузку из поля ввода файла и отображает результат.

rendered_to_string(rendered)

Преобразует отрендеренный шаблон в строку.

submit_form(form, conn)

Получает элемент формы и отправляет HTTP-запрос через конвейер plug.

with_target(view, target)

Задает целевой элемент представления для событий.

Функции

assert_patch(view, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))Источник

Проверяет, что live patch произойдёт в течение timeout миллисекунд. Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Возвращает новый путь.

Проверить flash-сообщение можно по результату рендеринга LiveView.

Примеры

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/+/

assert_patch(view, to, timeout)Источник

Проверяет, что live patch будет выполнен для указанного пути в течение timeout миллисекунд.

Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Возвращает новый путь.

Проверить flash-сообщение можно по результату рендеринга LiveView.

Примеры

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

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

assert_patched(view, to)Источник

Проверяет, что live patch был выполнен, и возвращает новый путь.

Проверить flash-сообщение можно по результату рендеринга LiveView.

Примеры

render_click(view, :event_that_triggers_redirect)
assert_patched view, "/path"

assert_push_event(view, event, payload, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))Источник

Проверяет, что событие будет отправлено в течение timeout. Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Примеры

assert_push_event view, "scores", %{points: 100, user: "josé"}

assert_redirect(view, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))Источник

Проверяет, что перенаправление произойдёт в течение timeout миллисекунд. Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Возвращает кортеж с новым путём и flash-сообщениями перенаправления, если они есть. Обратите внимание: ключи в flash будут строками.

Примеры

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

assert_redirect(view, to, timeout)Источник

Проверяет, что перенаправление на указанный путь произойдёт в течение timeout миллисекунд.

Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Возвращает flash-сообщения перенаправления, если они есть. Обратите внимание: ключи в flash будут строками.

Примеры

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

assert_redirected(view, to)Источник

Проверяет, что перенаправление было выполнено.

Возвращает flash-сообщения перенаправления, если они есть. Обратите внимание: ключи в flash будут строками.

Примеры

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

assert_reply(view, payload, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))Источник

Проверяет, что ответ hook был получен из callback handle_event.

Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Примеры

assert_reply view, %{result: "ok", transaction_id: _}

element(view, selector, text_filter \\ nil)Источник

Возвращает элемент, чтобы ограничить область действия функции.

Ожидает текущий LiveView, селектор запроса и текстовый фильтр.

Можно указать необязательный текстовый фильтр, чтобы отфильтровать результаты по селектору запроса. Если текстовый фильтр является строкой или регулярным выражением, он найдёт любой элемент, содержащий эту строку (в том числе как подстроку) или соответствующий регулярному выражению.

Таким образом, ссылка с текстом "unopened" будет соответствовать element("a", "opened"). Чтобы этого избежать, можно задать регулярное выражение, указывающее, что "opened" должно встречаться без префикса "un". Например, element("a", ~r{(?<!un)opened}). Однако может быть понятнее добавить HTML-атрибут, чтобы упростить выбор элемента.

После применения текстового фильтра должен остаться только один элемент, иначе будет вызвана ошибка.

Если текстовый фильтр не указан, селектор запроса сам должен возвращать один элемент.

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

Также поддерживаются селекторы атрибутов; их можно использовать, например, для идентификаторов, содержащих точки:

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

file_input(view, form_selector, name, entries)Источник

Создаёт поле ввода файла для тестирования загрузки файлов в форме.

Для заданного DOM-селектора формы, имени загрузки и списка отображений с метаданными клиента для загрузки возвращённое поле ввода файла можно передать в render_upload/2.

Метаданные клиента имеют следующий формат:

  • :last_modified — время последнего изменения
  • :name — имя файла
  • :content — двоичное содержимое файла
  • :size — размер содержимого в байтах
  • :type — MIME-тип файла
  • :relative_path — для имитации метаданных webkitdirectory
  • :meta — необязательные метаданные, отправленные клиентом

Примеры

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%"

find_live_child(parent, child_id)Источник

Получает вложенный дочерний LiveView по child_id из родительского LiveView parent.

Примеры

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

follow_redirect(reason, conn, to \\ nil)Источник

Выполняет перенаправление после действия render_* или кортежа {:error, redirect}.

Представьте, что у вас есть LiveView, который выполняет перенаправление при событии render_click. Убедиться, что перенаправление произойдёт сразу после действия render_click, можно вызвав follow_redirect/3:

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

Или в случае кортежа с ошибкой:

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

В качестве второго аргумента follow_redirect/3 ожидает connection. Это connection, который будет использоваться для выполнения базового запроса.

Если LiveView выполняет live redirect, эта макрокоманда возвращает {:ok, live_view, disconnected_html} с содержимым нового LiveView, как и макрокоманда live/3. Если LiveView выполняет обычное перенаправление, эта макрокоманда возвращает {:ok, conn} с отрендеренной страницей перенаправления. Во всех остальных случаях макрокоманда вызывает ошибку.

Наконец, можно дополнительно проверить путь перенаправления, передав третий аргумент:

live_view
|> render_click("redirect")
|> follow_redirect(conn, "/redirected/page")

follow_trigger_action(form, conn)Источник

Получает form_element и проверяет, что phx-trigger-action установлен в true, продолжая обработку этого запроса.

Представьте, что ваш LiveView отправляет HTTP-форму. Допустим, в ответ на событие отправки формы он устанавливает phx-trigger-action в true. Продолжить выполнение действия можно так:

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"}

form(view, selector, form_data \\ %{})Источник

Возвращает элемент формы, чтобы ограничить область действия функции.

Ожидает текущий LiveView, селектор запроса и данные формы. Селектор запроса должен возвращать один элемент.

Данные формы проверяются непосредственно по разметке формы: функция удостоверяется, что изменяемые или отправляемые данные действительно существуют, иначе завершается с ошибкой.

Примеры

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

Эта функция предназначена для имитации действий, которые действительно может выполнять пользователь, поэтому задать значения скрытых полей ввода нельзя. Однако скрытые значения можно передать при вызове render_submit/2 или render_change/2; примеры приведены в документации к этим функциям.

has_element?(element)Источник

Проверяет, существует ли указанный элемент на странице.

Примеры

assert view |> element("#some-element") |> has_element?()

has_element?(view, selector, text_filter \\ nil)Источник

Проверяет, присутствует ли selector с text_filter на view.

Подробнее см. element/3.

Примеры

assert has_element?(view, "#some-element")

live(conn, path \\ nil, opts \\ [])Источник

Запускает подключённый процесс LiveView.

Если указан path, выполняется обычный get(conn, path), а страница преобразуется в LiveView. Если путь не указан, предполагается, что задан ранее отрендеренный %Plug.Conn{}, который немедленно преобразуется в LiveView.

Параметры

  • :on_error — может быть :raise или :warn и определяет, будут ли обнаруженные ошибки, например дублирующиеся ID или live-компоненты, приводить к сбою теста или только записываться в журнал как предупреждение. По умолчанию — :raise.

Примеры

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

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

live_children(parent)Источник

Возвращает текущий список дочерних LiveView для родительского LiveView parent.

Дочерние элементы возвращаются в том порядке, в котором они расположены в отрендеренном HTML.

Примеры

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

live_isolated(conn, live_view, opts \\ [])Источник

Запускает подключённый процесс LiveView, смонтированный изолированно в качестве единственного отрендеренного элемента.

Полезно для тестирования LiveView, которые нельзя напрямую открыть по маршруту, например небольших компонентов, предназначенных для повторного использования в разных родительских представлениях. По возможности всё же рекомендуется тестировать LiveView с маршрутом, поскольку такие возможности, как live-навигация, требуют наличия маршрута.

Параметры

  • :session — сессия, передаваемая LiveView
  • :on_error — может быть :raise или :warn и определяет, будут ли обнаруженные ошибки, например дублирующиеся ID или live-компоненты, приводить к сбою теста или только записываться в журнал как предупреждение. По умолчанию — :raise.

Все остальные параметры передаются LiveView для рендеринга. Список поддерживаемых параметров рендеринга см. в Phoenix.Component.live_render/3.

Примеры

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

Используйте put_connect_params/2, чтобы передать параметры подключения для вызова Phoenix.LiveView.get_connect_params/1 в Phoenix.LiveView.mount/3:

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

live_redirect(view, opts)Источник

Выполняет live-перенаправление из одного LiveView в другой.

При перенаправлении между двумя LiveView одного и того же live_session монтируется новый LiveView и завершается работа предыдущего, что имитирует поведение live-навигации в браузере.

При попытке перейти из LiveView с другим live_session возвращается условие перенаправления с ошибкой, указывающее на неудачный push_navigate со стороны клиента.

Примеры

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")

open_browser(view_or_element, open_fun \\ &open_with_system_cmd/1)Источник

Открывает браузер по умолчанию, чтобы показать текущий HTML-код view_or_element.

Примеры

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

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

page_title(view)Источник

Возвращает последнее обновлённое заглавие, заданное через assign page_title.

Примеры

render_click(view, :event_that_triggers_page_title_update)
assert page_title(view) =~ "my title"

preflight_upload(upload)Источник

Выполняет предварительный запрос на загрузку.

Полезно для тестирования внешних загрузчиков, чтобы получить метаданные записи :external.

Примеры

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

put_connect_params(conn, params)Источник

Устанавливает параметры подключения, которые будут использоваться при подключении LiveView.

См. Phoenix.LiveView.get_connect_params/1.

put_submitter(form, element_or_selector)Источник

Устанавливает отправляющий элемент element_or_selector для указанного элемента form.

Отправляющий элемент инициирует событие отправки формы на клиенте. Если установить его для элемента, созданного с помощью form/3, а затем отправить форму через render_submit/2, пара имени и значения отправляющего элемента будет включена в данные события отправки.

Указанный элемент или селектор должен существовать внутри формы и соответствовать одному из следующих условий:

  • Элемент button или input с type="submit".

  • Элемент button без атрибута type.

Примеры

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

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

refute_patched(view)Источник

Проверяет, что live patch на указанный путь не был выполнен.

Возвращает :ok, если указанного patch ещё нет в почтовом ящике.

Примеры

render_click(view, :event_that_triggers_patch_to_path)
:ok = refute_patched view, "/wrong_path"

refute_patched(view, to)Источник

refute_push_event(view, event, payload, timeout \\ Application.fetch_env!(:ex_unit, :refute_receive_timeout))Источник

Проверяет, что событие не будет отправлено в течение указанного времени ожидания.

Значение timeout по умолчанию — refute_receive_timeout (100 мс) в ExUnit.

Примеры

refute_push_event view, "scores", %{points: _, user: "josé"}

refute_redirected(view)Источник

Проверяет, что перенаправление на указанный путь не было выполнено.

Возвращает :ok, если указанного перенаправления ещё нет в почтовом ящике.

Если путь не указан, проверяет, что для данного представления не было выполнено ни одного перенаправления.

Примеры

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

refute_redirected(view, to)Источник

render(view_or_element)Источник

Возвращает HTML-строку отрендеренного представления или элемента.

Если передано представление, рендерится весь LiveView. Если передано представление после вызова with_target/2 или элемент, возвращается только соответствующий контекст.

Примеры

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

assert view
       |> element("#alarm")
       |> render() == "Snooze"

render_async(view_or_element, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout))Источник

Ожидает завершения всех текущих задач assign_async, stream_async и start_async для указанного LiveView или элемента.

По завершении рендерит LiveView или элемент и возвращает результат. Значение timeout по умолчанию — assert_receive_timeout (100 мс) в ExUnit.

Примеры

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

render_blur(element, value \\ %{})Источник

Отправляет событие потери фокуса, заданное элементом element, и возвращает результат рендеринга.

element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-blur. Затем событие с именем, заданным в phx-blur, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все записи phx-value-* элемента отправляются в качестве значений. Дополнительные значения можно передать с помощью аргумента value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

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

render_blur(view, event, value)Источник

Отправляет событие потери фокуса в представление и возвращает результат рендеринга.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_change(element, value \\ %{})Источник

Отправляет событие изменения формы, заданное элементом element, и возвращает результат рендеринга.

element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-change. Затем событие с именем, заданным в phx-change, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все записи phx-value-* элемента отправляются в качестве значений.

Дополнительные значения или метаданные, например параметр "_target", можно передать в виде отображения через аргумент value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

{: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"

Как и в случае с render_submit/2, значения скрытых полей ввода можно передать следующим образом:

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

render_change(view, event, value)Источник

Отправляет событие изменения формы в представление и возвращает результат рендеринга.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_click(element, value \\ %{})Источник

Отправляет событие щелчка, заданное элементом element, и возвращает результат рендеринга.

element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-click. Затем событие с именем, заданным в phx-click, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все записи phx-value-* элемента отправляются в качестве значений. Дополнительные значения можно передать с помощью аргумента value.

Если у элемента нет атрибута phx-click, но он является ссылкой (тег <a>), ссылка будет обработана следующим образом:

  • если ссылка — patch, для текущего представления будет выполнен patch
  • если ссылка — navigate, функция вернёт {:error, {:live_redirect, %{to: url}}}, для обработки которого можно вызвать follow_redirect/2
  • если ссылка обычная, функция вернёт {:error, {:redirect, %{to: url}}}, для обработки которого можно вызвать follow_redirect/2

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

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

render_click(view, event, value)Источник

Отправляет событие щелчка event в view с помощью value и возвращает результат рендеринга.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_component(component, assigns \\ Macro.escape(%{}), opts \\ [])Исходный код

Отображает компонент.

Первый аргумент может быть функциональным компонентом, например анонимной функцией:

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

Или компонентом с состоянием в виде модуля. В этом случае эта функция смонтирует, обновит и отобразит компонент. Параметр :id является обязательным аргументом:

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

Если компонент использует маршрутизатор, его можно передать в качестве аргумента:

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

render_focus(element, value \\ %{})Исходный код

Отправляет событие фокуса, заданное параметром element, и возвращает результат отображения.

Параметр element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-focus. Затем событие с именем, заданным в phx-focus, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все значения phx-value-* элемента отправляются в качестве значений. Дополнительные значения можно передать с помощью аргумента value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

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

render_focus(view, event, value)Исходный код

Отправляет событие фокуса представлению и возвращает результат отображения.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_hook(view_or_element, event, value \\ %{})Исходный код

Отправляет событие хука представлению или элементу и возвращает результат отображения.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

Если вы отправляете события из хука компоненту, первым аргументом необходимо передать element, созданный с помощью element/3. Он должен указывать на один элемент страницы с атрибутом phx-target:

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

render_keydown(element, value \\ %{})Исходный код

Отправляет событие нажатия клавиши, заданное параметром element, и возвращает результат отображения.

Параметр element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-keydown или phx-window-keydown. Затем событие с именем, заданным в phx-keydown, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все значения phx-value-* элемента отправляются в качестве значений. Дополнительные значения можно передать с помощью аргумента value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_keydown(view, event, value)Исходный код

Отправляет событие нажатия клавиши представлению и возвращает результат отображения.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_keyup(element, value \\ %{})Исходный код

Отправляет событие отпускания клавиши, заданное параметром element, и возвращает результат отображения.

Параметр element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-keyup или phx-window-keyup. Затем событие с именем, заданным в phx-keyup, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все значения phx-value-* элемента отправляются в качестве значений. Дополнительные значения можно передать с помощью аргумента value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_keyup(view, event, value)Исходный код

Отправляет событие отпускания клавиши представлению и возвращает результат отображения.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_patch(view, path)Исходный код

Имитирует push_patch для указанного path и возвращает результат отображения.

render_submit(element, value \\ %{})Исходный код

Отправляет событие отправки формы, заданное параметром element, и возвращает результат отображения.

Параметр element создаётся с помощью element/3 и должен указывать на один элемент страницы с атрибутом phx-submit. Затем событие с именем, заданным в phx-submit, отправляется соответствующему LiveView (или компоненту, если phx-target задан соответствующим образом). Все значения phx-value-* элемента отправляются в качестве значений. Дополнительные значения, включая скрытые поля ввода, можно передать с помощью аргумента value.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

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

Чтобы отправить форму вместе со значениями скрытых полей ввода:

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

Чтобы отправить форму с помощью определённого элемента отправки через put_submitter/2:

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

Антипаттерн: без необходимости обходить проверку формы в LiveViewTest

НЕ используйте параметр value для передачи данных, которые должны вводиться в обычные поля формы. Значения, напрямую переданные в render_submit, не проверяются на соответствие полям ввода, отображённым в составе формы.

Предположим, у вас есть такой код:

def render(assigns) do
  ~H"""
  <form phx-submit="save">
    <input name="name" value="" />
    <button type="submit">Submit</button>
  </form>
  """
end

def handle_event("save", %{"name" => name}, socket) do
  ...
end

А вы тестируете его так:

view |> form("form") |> render_submit(%{name: "hello"})

Поскольку значения, переданные в render_submit, не проверяются на соответствие форме, тест не завершится ошибкой, если позже вы измените имя поля ввода. Вместо этого всегда передавайте значения видимых полей ввода в вызове form/3:

view |> form("form", %{name: "hello"}) |> render_submit()

Так, если вы запустите тесты, а поле ввода будет называться <input name="other_name">, вы получите ошибку:

** (ArgumentError) could not find non-disabled input, select or textarea with name "name" within:

<input name="other_name" value=""/>

Используйте параметр value только для передачи значений скрытых полей ввода или событий отправки из хука, которые нельзя передать в form/3. То же относится к render_change/2.

render_submit(view, event, value)Исходный код

Отправляет событие отправки формы представлению и возвращает результат отображения.

Возвращает содержимое всего LiveView или кортеж {:error, redirect}.

Примеры

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

render_upload(upload, entry_name, percent \\ 100)Исходный код

Загружает файл из поля ввода файла и отображает результат.

Подробнее о создании поля ввода файла см. в разделе file_input/4.

Примеры

Предположим, у вас есть следующий шаблон LiveView:

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

В тестовом примере можно проверить загруженное содержимое:

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%"

По умолчанию весь файл передаётся на сервер частями, но для проверки загрузки по частям можно указать необязательный процент передаваемых данных:

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

Прежде чем проверять, как загруженный файл обрабатывается на стороне сервера, необходимо вызвать render_submit/1.

Если обратный вызов прогресса загрузки выполняет navigate, patch или redirect, будет возвращён следующий результат:

  • при patch текущее представление будет обновлено
  • при navigate эта функция вернёт {:error, {:live_redirect, %{to: url}}}, после чего можно вызвать follow_redirect/2
  • при обычном redirect эта функция вернёт {:error, {:redirect, %{to: url}}}, после чего можно вызвать follow_redirect/2

rendered_to_string(rendered)Исходный код

Преобразует отображённый шаблон в строку.

Примеры

import Phoenix.Component
import Phoenix.LiveViewTest

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

submit_form(form, conn)Исходный код

Получает элемент формы и отправляет HTTP-запрос через конвейер plug.

Предположим, у вас есть LiveView, который проверяет данные формы, но отправляет форму контроллеру обычным атрибутом action формы. Это особенно полезно, когда результат отправки формы должен записать данные в сессию plug.

Форму можно отправить с помощью %Plug.Conn{}, например так:

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"}

with_target(view, target)Исходный код

Задаёт целевой компонент представления для событий.

Это имитирует phx-target непосредственно в тестах, не требуя отправлять событие конкретному элементу. Это может быть полезно для вызова событий в одном или нескольких компонентах одновременно:

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

Пакет Hex Предпросмотр Hex Просмотреть llms.txt Скачать версию ePub

Создано с помощью ExDoc (v0.40.3) для языка программирования Elixir

© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix-live-view.hexdocs.pm/Phoenix.LiveViewTest.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API