5.4 KiB · text History dc2edab
defmodule DiogramosWeb.FolderManageTest do
  use DiogramosWeb.ConnCase, async: true

  import Phoenix.LiveViewTest
  import Diogramos.AccountsFixtures
  import Diogramos.DiagramsFixtures

  alias Diogramos.Accounts.Scope
  alias Diogramos.Diagrams

  setup %{conn: conn} do
    owner = user_fixture()
    scope = Scope.for_user(owner)

    %{conn: log_in_user(conn, owner), owner: owner, scope: scope}
  end

  describe "the folder list" do
    test "survives filtering, which used to wipe it until a reload", %{
      conn: conn,
      scope: scope
    } do
      keep = folder_fixture(scope, %{name: "Keep"})
      other = folder_fixture(scope, %{name: "Other"})

      {:ok, lv, html} = live(conn, ~p"/canvases")
      assert html =~ "Keep"
      assert html =~ "Other"

      # Filtering re-streams the canvases; the folders must not go with
      # them.
      html = lv |> element("button[phx-value-folder_id='#{keep.id}']") |> render_click()
      assert html =~ "Keep"
      assert html =~ "Other"

      html = lv |> element("button[phx-value-folder_id='all']") |> render_click()
      assert html =~ "Keep"
      assert html =~ "Other"
      assert other.id
    end
  end

  describe "renaming" do
    test "renames from the manage modal", %{conn: conn, scope: scope} do
      folder = folder_fixture(scope, %{name: "Before"})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-id='#{folder.id}']") |> render_click()

      html =
        lv |> form("#folder-rename-form", %{"name" => "After"}) |> render_submit()

      assert html =~ "Renamed to After."
      assert html =~ "After"
      assert Diagrams.get_folder!(scope, folder.id).name == "After"
    end

    test "reports a rejected name instead of swallowing it", %{conn: conn, scope: scope} do
      folder = folder_fixture(scope, %{name: "Before"})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-id='#{folder.id}']") |> render_click()

      html = lv |> form("#folder-rename-form", %{"name" => ""}) |> render_submit()

      assert html =~ "can't be blank" or html =~ "can't be blank"
      assert Diagrams.get_folder!(scope, folder.id).name == "Before"
    end
  end

  describe "deleting" do
    test "empties its canvases into all canvases rather than deleting them", %{
      conn: conn,
      scope: scope
    } do
      folder = folder_fixture(scope, %{name: "Doomed"})
      canvas = canvas_fixture(scope, %{title: "Survivor", folder_id: folder.id})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-id='#{folder.id}']") |> render_click()

      html = lv |> element("button", "Delete folder") |> render_click()

      assert html =~ "Its canvases are in All canvases."
      # The flash names the folder, so check the list, not the page.
      refute has_element?(lv, "button[phx-value-folder_id='#{folder.id}']")

      kept = Diagrams.get_canvas_by_slug(scope, canvas.slug)
      assert kept, "the canvas must outlive its folder"
      assert kept.folder_id == nil
      assert html =~ "Survivor"
    end

    test "moves nested folders up instead of destroying them", %{conn: conn, scope: scope} do
      parent = folder_fixture(scope, %{name: "Parent"})
      {:ok, child} = Diagrams.create_folder(scope, %{name: "Child", parent_id: parent.id})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-id='#{parent.id}']") |> render_click()

      html = lv |> element("button", "Delete folder") |> render_click()

      # folders.parent_id cascades in the database, so without the
      # re-parent this child would be gone too.
      assert html =~ "Child"
      assert Diagrams.get_folder!(scope, child.id).parent_id == nil
    end

    test "a canvas in a nested folder survives its grandparent's delete", %{
      conn: conn,
      scope: scope
    } do
      parent = folder_fixture(scope, %{name: "Parent"})
      {:ok, child} = Diagrams.create_folder(scope, %{name: "Child", parent_id: parent.id})
      canvas = canvas_fixture(scope, %{title: "Deep", folder_id: child.id})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-id='#{parent.id}']") |> render_click()
      lv |> element("button", "Delete folder") |> render_click()

      kept = Diagrams.get_canvas_by_slug(scope, canvas.slug)
      assert kept
      # It stays where it was: only the deleted folder's own contents move.
      assert kept.folder_id == child.id
    end

    test "clears the filter when the folder being viewed is deleted", %{
      conn: conn,
      scope: scope
    } do
      folder = folder_fixture(scope, %{name: "Viewing"})
      _elsewhere = canvas_fixture(scope, %{title: "Elsewhere"})

      {:ok, lv, _html} = live(conn, ~p"/canvases")
      lv |> element("button[phx-value-folder_id='#{folder.id}']") |> render_click()
      lv |> element("button[phx-value-id='#{folder.id}']") |> render_click()

      html = lv |> element("button", "Delete folder") |> render_click()

      # Otherwise the list stays filtered by a folder that no longer
      # exists, and looks empty for no visible reason.
      assert html =~ "Elsewhere"
    end

    test "someone else's folder is refused by the context", %{scope: scope} do
      folder = folder_fixture(scope, %{name: "Mine"})
      stranger = user_fixture()

      assert {:error, :forbidden} =
               Diagrams.delete_folder(Scope.for_user(stranger), folder)
    end
  end
end