Share
Embed
Testing LiveView
Curious how to test LiveView?
Look no further! We’ll learn to write effective LiveView tests using our application's domain language. We'll use the exceptional tools built into LiveViewTest. And we'll see how our LiveView tests can to teach us about the design of our LiveViews. So join me, and let's take a deep dive into LiveView testing.
Key takeaway:
Write tests from the perspective of the user (testing behavior, not implementation) in the domain of your application.
Links mentioned in the talk:
- https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html
- https://www.testingliveview.com/
- https://www.tddphoenix.com/
- https://twitter.com/germsvel
German Velasco
September 04, 2020
Transcript
137 slides
-
Phoenix.LiveViewTest josevalim - chrismccord - preciz alexgaribay - SherSpock -
wojtekmach nthock - NikitaAvvakumov - sneako mcrumm - leandrocp - jmbejar henrik - JonRowe - feliperenan orthodoX - davydog187 - qrede cadebward - axelclark - glennr adamvaughan - SolbiatiAlessandro rhruiz - hasmanyguitars - sevenseacat LostKobrakai - egze - dvic -
Learn by doing → How to write LiveView tests →
Testing the right things -
Learn by doing → How to write LiveView tests →
Testing the right things → Writing explicit tests -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
Anatomy of a test {:ok, view, _html} = live(conn, "/todo")
rendered = view |> element("li", "Hold council of Elrond") |> render_click() assert rendered =~ "Tell tale of Elendil" assert has_element?(view, "p", "Tell tale of Elendil") -
live/2 {:ok, view, html} = live(conn, "/todo") assert html =~
"Your Todo" assert render(view) =~ "Your Todo" -
live/2 {:ok, view, html} = live(conn, "/todo") assert html =~
"Your Todo" assert render(view) =~ "Your Todo" -
live/2 {:ok, view, html} = live(conn, "/todo") assert html =~
"Your Todo" assert render(view) =~ "Your Todo" -
live/2 {:ok, view, html} = live(conn, "/todo") assert html =~
"Your Todo" assert render(view) =~ "Your Todo" -
element/3 view |> element("li", "Hold council of Elrond") %Element{ selector:
"li", text_filter: "Hold council of Elrond" } -
element/3 view |> element("li", "Hold council of Elrond") %Element{ selector:
"li", text_filter: "Hold council of Elrond" } -
form/3 view |> form("#attendee-form", %{ email: "[email protected]" }) %Element{ selector:
"#attendee-form", form_data: %{ email: "[email protected]" } } -
form/3 view |> form("#attendee-form", %{ email: "[email protected]" }) %Element{ selector:
"#attendee-form", form_data: %{ email: "[email protected]" } } -
CSS selectors selector example classes ".button" ids "#user-name" tags "h1"
data attributes "[data-role=user-heading]" -
render_* functions render_blur/2 render_blur/3 render_change/2 render_change/3 render_click/2 render_click/3 render_focus/2 render_focus/3
render_keydown/2 render_keydown/3 render_keyup/2 render_keyup/3 render_submit/2 render_submit/3 -
Assertions assert rendered =~ "Tell tale of Elendil" assert has_element?(view,
"p", "Tell tale of Elendil") -
Assertions assert rendered =~ "Tell tale of Elendil" assert has_element?(view,
"p", "Tell tale of Elendil") -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
render_submit/3 test "user can add a new todo", %{conn: conn}
do {:ok, view, _html} = live(conn, "/todo") view - |> form("#new-todo", todo: %{text: "Decide fate of ring"}) - |> render_submit() + |> render_submit("create-todo", todo: %{text: "Decide fate of ring"}) assert has_element?(view, ".todo", "Decide fate of ring") end -
render_submit/3 test "user can add a new todo", %{conn: conn}
do {:ok, view, _html} = live(conn, "/todo") view - |> form("#new-todo", todo: %{text: "Decide fate of ring"}) - |> render_submit() + |> render_submit("create-todo", todo: %{text: "Decide fate of ring"}) assert has_element?(view, ".todo", "Decide fate of ring") end -
render_submit/3 test "user can add a new todo", %{conn: conn}
do {:ok, view, _html} = live(conn, "/todo") view - |> form("#new-todo", todo: %{text: "Decide fate of ring"}) - |> render_submit() + |> render_submit("create-todo", todo: %{text: "Decide fate of ring"}) assert has_element?(view, ".todo", "Decide fate of ring") end -
Targets this directly def handle_event("create-todo", %{"todo" => params}, socket) do
# event handler {:noreply, socket} end -
You could delete the entire form - <%= f =
form_for @changeset, "#", - phx_submit: "create-todo", - id: "new-todo" %> - - <%= text_input f, :text, placeholder: "Enter todo here" %> - <%= submit "Add todo" %> - </form> -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Asserting text test "user can add a new todo", %{conn:
conn} do {:ok, view, _html} = live(conn, "/todo") + rendered = view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() - assert has_element?(view, ".todo", "Decide fate of ring") + assert rendered =~ "Decide fate of ring" end -
Asserting text test "user can add a new todo", %{conn:
conn} do {:ok, view, _html} = live(conn, "/todo") + rendered = view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() - assert has_element?(view, ".todo", "Decide fate of ring") + assert rendered =~ "Decide fate of ring" end -
Asserting text test "user can add a new todo", %{conn:
conn} do {:ok, view, _html} = live(conn, "/todo") + rendered = view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() - assert has_element?(view, ".todo", "Decide fate of ring") + assert rendered =~ "Decide fate of ring" end -
Adding a new todo test "user can add a new
todo", %{conn: conn} do {:ok, view, _html} = live(conn, "/todo") view |> form("#new-todo", todo: %{text: "Decide fate of ring"}) |> render_submit() assert has_element?(view, ".todo", "Decide fate of ring") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Showing a todo's details test "selecting a todo opens todo
details panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Testing the details defmodule MyAppWeb.TodoComponentTest do use MyAppWeb.ConnCase import Phoenix.LiveViewTest
alias MyAppWeb.TodoComponent test "renders todo with notes" do todo = create_todo(text: "Decide fate of ring", notes: "Cannot be destroyed by axe") html = render_component(TodoComponent, todo: todo) assert html =~ todo.text assert html =~ todo.notes end end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
Assert database changes? test "user can mark todo as complete",
%{conn: conn} do {:ok, todo} = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") updated_todo = Repo.get(MyApp.Todo, todo.id) assert updated_todo.complete end -
Assert database changes? test "user can mark todo as complete",
%{conn: conn} do {:ok, todo} = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") updated_todo = Repo.get(MyApp.Todo, todo.id) assert updated_todo.complete end -
Marking a todo as complete test "user can mark todo
as complete", %{conn: conn} do todo = create_todo("Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} input[name=todo]") |> render_click() assert has_element?(view, "s", "Hold council of Elrond") end -
But how to test this logic? def handle_event("complete-todo", %{"value" =>
todo_id}, socket) do Todo |> Repo.get(todo_id) |> Todo.changeset(%{complete: true}) |> Repo.update!() {:noreply, assign(socket, :todos, Todos.get_all())} end -
But how to test this logic? def handle_event("complete-todo", %{"value" =>
todo_id}, socket) do Todo |> Repo.get(todo_id) |> Todo.changeset(%{complete: true}) |> Repo.update!() {:noreply, assign(socket, :todos, Todos.get_all())} end -
Extract logic def handle_event("complete-todo", %{"value" => todo_id}, socket) do -
Todo - |> Repo.get(todo_id) - |> Todo.changeset(%{complete: true}) - |> Repo.update!() + Todos.complete_todo(todo_id) {:noreply, assign(socket, :todos, Todos.get_all())} end -
Extract logic def handle_event("complete-todo", %{"value" => todo_id}, socket) do Todos.complete_todo(todo_id)
{:noreply, assign(socket, :todos, Todos.get_all())} end -
Implementation Changes <span - phx-click="show-todo" - phx-value-id="<%= todo.id %>" -
data-role="todo-text"> - - <%= todo.text %> + <%= live_patch todo.text, + to: Routes.todo_path(@socket, :show, todo), + data: [role: "todo-text"] + %> </span> -
Implementation Changes <span - phx-click="show-todo" - phx-value-id="<%= todo.id %>" -
data-role="todo-text"> - - <%= todo.text %> + <%= live_patch todo.text, + to: Routes.todo_path(@socket, :show, todo), + data: [role: "todo-text"] + %> </span> -
Implementation Changes <span - phx-click="show-todo" - phx-value-id="<%= todo.id %>" -
data-role="todo-text"> - - <%= todo.text %> + <%= live_patch todo.text, + to: Routes.todo_path(@socket, :show, todo), + data: [role: "todo-text"] + %> </span> -
Change to assert_patched/2? test "selecting a todo opens todo details
panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() - assert has_element?(view, "#todo-#{todo.id}-details") + assert_patched(view, "/todo/#{todo.id}") end -
Change to assert_patched/2? test "selecting a todo opens todo details
panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() - assert has_element?(view, "#todo-#{todo.id}-details") + assert_patched(view, "/todo/#{todo.id}") end -
Change to assert_patched/2? test "selecting a todo opens todo details
panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() - assert has_element?(view, "#todo-#{todo.id}-details") + assert_patched(view, "/todo/#{todo.id}") end -
What does the user see? Existing behavior New behavior clicking
on todo's text opens details panel clicking on todo's text opens details panel -
Test is unchanged test "selecting a todo opens todo details
panel", %{conn: conn} do todo = create_todo(text: "Hold council of Elrond") {:ok, view, _html} = live(conn, "/todo") view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() assert has_element?(view, "#todo-#{todo.id}-details") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") # Opening todo details view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end defp open_todo_details(view, todo) do view |> element("#todo-#{todo.id} [data-role=todo-text]", todo.text) |> render_click() view end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) # Opening editable notes view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end defp edit_notes(view, todo) do view |> element("#todo-#{todo.id}-details [data-role=edit-todo-notes]", "Edit notes") |> render_click() view end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) # Add notes view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) |> add_notes(todo, notes) assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end defp add_notes(view, todo, notes) do view |> form("#todo-#{todo.id}-details [data-role=update-todo-notes]", todo: %{notes: notes}) |> render_submit() view end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) |> add_notes(todo, notes) assert has_element?(view, "#todo-#{todo.id}-details [data-role=todo-notes]", notes) assert has_element?(view, "#todo-#{todo.id} [data-role=notes-icon]") end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) |> add_notes(todo, notes) assert has_element?(view, todo_details(todo), notes) assert has_element?(view, todo_notes_icon(todo)) end defp todo_details(todo) do "#todo-#{todo.id}-details [data-role=todo-notes]" end defp todo_notes_icon(todo) do "#todo-#{todo.id} [data-role=notes-icon]" end -
test "user can edit notes", %{conn: conn} do todo =
create_todo(text: "Decide fate of the ring") notes = "We might have to cast it into mount doom" {:ok, view, _html} = live(conn, "/todo") view |> open_todo_details(todo) |> edit_notes(todo) |> add_notes(todo, notes) assert has_element?(view, todo_details(todo), notes) assert has_element?(view, todo_notes_icon(todo)) end -
Effective LiveView Testing Write tests from the perspective of the
user (testing behavior, not implementation) -
Effective LiveView Testing Write tests from the perspective of the
user (testing behavior, not implementation) in the domain of your application.