Testの書き方 LiveView編
LiveViewのテストモジュールは、以下の手順で定義することができる。
- テストモジュールに必要なモジュールをインポートする。
- セットアップ関数を定義する。
- テストを記述する。
モジュールのインポート
LiveViewのテストモジュールを定義するためには、最低限以下の記述を必要とする。
use 省略Web.ConnCase
import Phoenix.LiveViewTest
これらは、Phoenixの接続のテストとLiveViewのテストを行えるようにするものである。
セットアップ関数の定義
LiveViewではライフサイクルにデータを追加することができる(socket.assigns)。
このデータ込みのテストを作成するためには、
テストを初期化するセットアップ関数を定義する必要がある。
セットアップ関数は次のように定義することができる。
# セットアップ関数を定義
defp init_data(_) do
%{name: "Taro"}
end
セットアップ関数は次のように、テストに指定することができる。
describe "Test HomeLive.Index" do
# describe別にsetup関数を指定することができる
setup [:init_data]
# セットアップ関数の戻り値のマップにあるものが指定できる
test "home page", %{conn: conn, name: name} do
end
end
またsetup_all
マクロを使用することで、モジュール内のすべてのテストの初期化処理を行うことができる。
次のように記述する。
setup_all do
# 初期化処理
end
これらの実行順は次のようになる。
-
setup_all
マクロ - セットアップ関数
よってテスト全体に適用したい初期化処理はsetup_all
マクロに、テストごとの初期化処理をセットアップ関数で行うと良い。
データが異なる場合のセットアップ関数
データの値が特定の状態のときのLiveViewをテストしたい場合、
複数セットアップ関数を用意するとよい。
defp when_name(_) do
%{name: "Taro", age: nil, from: nil}
end
defp when_age(_) do
%{name: "Taro", age: 34, from: nil}
end
defp when_from(_) do
%{name: "Taro", age: 34, from: "north pole"}
end
Testを実行する
LiveViewをテストする際には、LiveViewのプロセスを生成する必要がある。
次のように記述することで、LiveViewのプロセスを生成することができる。
{:ok, live_view, html} = live(conn, ~p"ルート")
出力されるlive_view
はLiveViewの状態であり、html
はレンダリングされたHTMLである
LiveComponentの表示は次のようにテストすることができる。
# 出力されるHTMLからテスト
assert html =~ "テキスト"
# 特定のLiveComponentからの出力に絞ってテスト
assert render_component(LiveComponentモジュール, データatom: データ) =~ "テキスト"
** (KeyError) key :myself not found
LiveConponent内でイベントの送信先をLiveComponent自身(phx-target={@myself}
)としている場合、次のエラーが表示される。
** (KeyError) key :myself not found 以下省略
このような場合のTestでは、render_componentでid: "LiveComponentに指定したid"
を渡すことで解決する。
assert render_component(LiveComponentモジュール, id: "LiveComponentに指定したid", データatom: データ) =~ "テキスト"
結論
LiveViewのテストを定義する場合、概ね次の手順に沿って記述する。
- LiveViewのテストモジュールをインポートする(
ConnCase
、Phoenix.LiveViewTest
) -
setup_all
マクロですべてのテストで共通の初期化を記述する。 - セットアップ関数を定義して、各describeにまとめられたテストで実行させる。(
setup [:セットアップ関数]
) - test内でLiveViewプロセスを生成する。(
live(conn, ~p"ルート")
) -
assert
で比較を行う。
LiveViewのテストは、処理ごとに細かくdescribe
で分け、結果ごとにtest
を定義したほうがよいと思った。
おまけ
テスト実行後の処理
セットアップ関数やsetup_all
マクロ、テストでの実行後の処理は、
on_exit
コールバックで記述することができる。
on_exit(fn ->
# テスト後の処理
end)
例としてsetup_all
マクロで、on_exit
を記述すると次のようになる。
setup_all do
# テスト実行前にディレクトリとファイルを生成した
:ok = File.mkdir("TEST_DIR")
:ok = File.touch("TEST/TEXT.txt")
on_exit(fn ->
{:ok, ["TEST_DIR", "TEST_DIR/TEXT.txt"]} = FILE.rm_ref("TEST_DIR")
end)
end
要素をクリックした後の表示をテスト
要素をクリックしたときの動作のテストを記述する場合、render_click(要素)
を使用する。
またこの際、指定した要素がイベント処理によって状態(socket内のデータ)を更新する場合、render(状態)
を実行すると
状態の更新後の表示をテストすることができる。
{:ok, live_view, _html} = live(conn, ~p"/")
live_view
|> element("li", "イベント名もしくはphx-value-*の値")
|> render_click() =~ "内容"
# 状態の更新後をテスト
assert render(live_view) =~ "内容"
要素を指定するelement/2
の引数は次のものを指定する。
- 第一引数 - タグの種類を指定する。(
button
、li
など) - 第二引数 -
phx-click
のイベント名やphx-value-*
で指定した値などを指定する。
クリックした要素にphx-click
が記述されていればイベントが送信され、要素が<.link pacth={~p"ルート"}>
であればパッチ処理が行われる。
つまりLiveViewのページでクリックをしたときと同じ処理が行われる。
次のものはli
要素をクリックすることで、
LiveComponentの表示が更新されたことをテストするものである。
# このセットアップ関数は%{selected: nil}を返す
setup [:when_not_selected_exists]
test "Click list", %{conn: conn, selected: selected} do
{:ok, live_view, _html} = live(conn, ~p"/")
# <li phx-value-name="TEST" phx-click="select_li"> という要素があるものとする
# "select_li"イベントは、phx-value-*で指定した値%{"name" => name}を受け取り
# selectedの値をname(つまり"TEST")に更新するものとする
live_view
# すべてのliの内、"TEST"とphx-valueのnameと一致するもの
|> element("li", "TEST")
# この時点でtest時に指定したselectedの値は、イベント処理によって
# nilから"TEST"となっている
# LiveViewの要素(LiveComponent込み)内に"test.pub"というテキストが存在するかテストすることができた。
|> render_click() =~ "test.pub"
end
navigate
とパッチの処理をテスト
要素をクリック後、navigate処理が行われたをしたことをテストする場合
assert_redirected(live_view, ~p"/new")
要素をクリック後、パッチ処理が行われたことをテストする場合
assert_patched(live_view, ~p"/import_form")
テスト名
定義例
-
Test that 要素 be 動詞ed.
- 特定の要素をテストする場合(Test that selected directory file are listed.
等) -
Test 対象 when 条件.
- 条件を満たすとき対象をテストする場合(Test page when selected is nil.
)