defmodule LivebookWeb.HomeLiveTest do use LivebookWeb.ConnCase, async: true import Phoenix.LiveViewTest import Livebook.SessionHelpers alias Livebook.{Sessions, Session} test "disconnected and connected render", %{conn: conn} do {:ok, view, disconnected_html} = live(conn, ~p"/") assert disconnected_html =~ "Running sessions" assert render(view) =~ "Running sessions" end test "redirects to session upon creation", %{conn: conn} do {:ok, view, _} = live(conn, ~p"/") assert {:error, {:live_redirect, %{to: to}}} = view |> element(~s/[role="navigation"] button/, "New notebook") |> render_click() assert to =~ "/sessions/" close_session_by_path(to) end describe "sessions list" do test "lists running sessions", %{conn: conn} do {:ok, session1} = Sessions.create_session() {:ok, session2} = Sessions.create_session() {:ok, view, _} = live(conn, ~p"/") assert render(view) =~ session1.id assert render(view) =~ session2.id Session.close([session1.pid, session2.pid]) end test "updates UI whenever a session is added or deleted", %{conn: conn} do Sessions.subscribe() {:ok, view, _} = live(conn, ~p"/") {:ok, %{id: id} = session} = Sessions.create_session() assert_receive {:session_created, %{id: ^id}} assert render(view) =~ id Session.close(session.pid) assert_receive {:session_closed, %{id: ^id}} refute render(view) =~ id end test "allows download the source of an existing session", %{conn: conn} do {:ok, session} = Sessions.create_session() Session.set_notebook_name(session.pid, "My notebook") {:ok, view, _} = live(conn, ~p"/") {:error, {:redirect, %{to: to}}} = view |> element(~s{[data-test-session-id="#{session.id}"] a}, "Download source") |> render_click assert to == ~p"/sessions/#{session.id}/export/download/livemd?include_outputs=false" Session.close(session.pid) end test "allows forking existing session", %{conn: conn} do {:ok, session} = Sessions.create_session() Session.set_notebook_name(session.pid, "My notebook") {:ok, view, _} = live(conn, ~p"/") assert {:error, {:live_redirect, %{to: to}}} = view |> element(~s{[data-test-session-id="#{session.id}"] button}, "Fork") |> render_click() assert to =~ "/sessions/" {:ok, view, _} = live(conn, to) assert render(view) =~ "My notebook - fork" close_session_by_path(to) Session.close(session.pid) end test "allows closing session after confirmation", %{conn: conn} do {:ok, session} = Sessions.create_session() {:ok, view, _} = live(conn, ~p"/") assert render(view) =~ session.id view |> element(~s{[data-test-session-id="#{session.id}"] a}, "Close") |> render_click() view |> element(~s{button[role=button]}, "Close session") |> render_click() refute render(view) =~ session.id end test "close all selected sessions using bulk action", %{conn: conn} do {:ok, session1} = Sessions.create_session() {:ok, session2} = Sessions.create_session() {:ok, session3} = Sessions.create_session() {:ok, view, _} = live(conn, ~p"/") assert render(view) =~ session1.id assert render(view) =~ session2.id assert render(view) =~ session3.id view |> form("#bulk-action-form", %{ "action" => "close_all", "session_ids" => [session1.id, session2.id, session3.id] }) |> render_submit() assert render(view) =~ "Are you sure you want to close 3 sessions?" view |> element(~s{button[role="button"]}, "Close sessions") |> render_click() refute render(view) =~ session1.id refute render(view) =~ session2.id refute render(view) =~ session3.id end end describe "starred notebooks" do @tag :tmp_dir test "starring and unstarring a notebook", %{conn: conn, tmp_dir: tmp_dir} do notebook_path = Path.join(tmp_dir, "notebook.livemd") file = Livebook.FileSystem.File.local(notebook_path) {:ok, session} = Sessions.create_session() Session.set_file(session.pid, file) Session.set_notebook_name(session.pid, "Special notebook") wait_for_session_update(session.pid) {:ok, view, _} = live(conn, ~p"/") Livebook.NotebookManager.add_starred_notebook(file, "Special notebook") render(view) assert view |> element(~s/#starred-notebooks/, "Special notebook") |> has_element?() Livebook.NotebookManager.remove_starred_notebook(file) render(view) refute view |> element(~s/#starred-notebooks/, "Special notebook") |> has_element?() end @tag :tmp_dir test "opening a starred notebook", %{conn: conn, tmp_dir: tmp_dir} do notebook_path = Path.join(tmp_dir, "notebook.livemd") File.write!(notebook_path, "# Starred notebook") file = Livebook.FileSystem.File.local(notebook_path) Livebook.NotebookManager.add_starred_notebook(file, "Starred notebook") {:ok, view, _} = live(conn, ~p"/") card_html = view |> element(~s/#starred-notebooks [data-test-idx]/, "Starred notebook") |> render() assert [attr] = Regex.run(~r/data-test-idx="\d+"/, card_html) view |> element(~s/#starred-notebooks [#{attr}] button/, "Open") |> render_click() {to, _flash} = assert_redirect(view) assert to =~ "/sessions/" {:ok, view, _} = live(conn, to) assert render(view) =~ "Starred notebook" close_session_by_path(to) end end describe "hubs sidebar" do test "render section", %{conn: conn} do {:ok, _view, html} = live(conn, ~p"/") assert html =~ "HUBS" assert html =~ "Add Hub" end test "render persisted hubs", %{conn: conn} do fly = insert_hub(:fly, id: "fly-foo-bar-id") {:ok, _view, html} = live(conn, ~p"/") assert html =~ "HUBS" assert html =~ fly.hub_name Livebook.Hubs.delete_hub("fly-foo-bar-id") end end test "handles user profile update", %{conn: conn} do {:ok, view, _} = live(conn, ~p"/") data = %{user: %{name: "Jake Peralta", hex_color: "#123456"}} view |> element("#user_form") |> render_change(data) view |> element("#user_form") |> render_submit(data) assert render(view) =~ "Jake Peralta" assert render(view) =~ "#123456" end # Helpers defp close_session_by_path("/sessions/" <> session_id) do {:ok, session} = Sessions.fetch_session(session_id) Session.close(session.pid) end end