6.5 KiB · text History b868907
defmodule GitGudWeb.OrgDashboardTest do
  @moduledoc """
  `/orgs/:handle/dashboard` — the landing dashboard, narrowed to one
  organization.

  The assertions that matter are the two ways it could be wrong: work
  from *outside* the org leaking in, and work inside the org the viewer
  isn't allowed to see leaking in.
  """
  use GitGudWeb.ConnCase, async: false

  import GitGud.AccountsFixtures
  import GitGud.ForgeFixtures
  import Phoenix.LiveViewTest

  alias GitGud.Organizations
  alias GitGud.Repositories

  setup do
    owner = user_fixture() |> set_password()

    {:ok, org} =
      Organizations.create_organization(owner, %{
        "handle" => "org#{System.unique_integer([:positive])}",
        "name" => "Test Org"
      })

    {:ok, repo} =
      Repositories.create_repository_for_org(org, owner, %{
        "name" => unique_repo_name(),
        "visibility" => "public"
      })

    {:ok, owner: owner, org: org, repo: GitGud.Repo.preload(repo, [:owner, :organization])}
  end

  defp sign_in(conn, user), do: GitGudWeb.ConnCase.log_in_user(conn, user)

  defp path(org), do: "/orgs/#{org.handle}/dashboard"

  describe "scoping" do
    test "shows the org's open work", %{conn: conn, owner: owner, org: org, repo: repo} do
      issue_fixture(repo, owner, %{"title" => "an org issue"})

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      assert html =~ "an org issue"
      assert html =~ "Open issues"
      assert html =~ "Open pull requests"
      assert html =~ "Needs your review"
    end

    test "does not show work from outside the org", %{conn: conn, owner: owner, org: org} do
      {_other_user, personal} = repository_fixture(%{owner: owner, visibility: "public"})
      issue_fixture(personal, owner, %{"title" => "a personal issue"})

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      refute html =~ "a personal issue"
    end

    test "someone else's work shows too — an org dashboard is not the landing page", %{
      conn: conn,
      owner: owner,
      org: org,
      repo: repo
    } do
      other = user_fixture()
      issue_fixture(repo, other, %{"title" => "opened by someone else"})

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      assert html =~ "opened by someone else"
    end

    test "your own work is separated out", %{conn: conn, owner: owner, org: org, repo: repo} do
      issue_fixture(repo, owner, %{"title" => "mine here"})

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      assert html =~ "Your work here"
      assert html =~ "mine here"
    end

    test "a brand-new org renders the panels with their own empty copy", %{
      conn: conn,
      owner: owner
    } do
      {:ok, fresh} =
        Organizations.create_organization(owner, %{
          "handle" => "fresh#{System.unique_integer([:positive])}",
          "name" => "Fresh"
        })

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(fresh))

      # Every org gets an auto-provisioned profile repo, so "no
      # repositories at all" isn't a state a viewer reaches; the panels
      # say what's empty, the same way the landing dashboard does.
      assert html =~ "No open pull requests."
      assert html =~ "No open issues."
      assert html =~ "Nothing waiting on you here."
    end
  end

  describe "visibility" do
    test "a private repo's issues are hidden from a non-member", %{
      conn: conn,
      owner: owner,
      org: org
    } do
      {:ok, private} =
        Repositories.create_repository_for_org(org, owner, %{
          "name" => unique_repo_name(),
          "visibility" => "private"
        })

      issue_fixture(private, owner, %{"title" => "a private issue"})

      outsider = user_fixture() |> set_password()

      {:ok, _view, html} = conn |> sign_in(outsider) |> live(path(org))

      refute html =~ "a private issue"
    end

    test "…and visible to a member", %{conn: conn, owner: owner, org: org} do
      {:ok, private} =
        Repositories.create_repository_for_org(org, owner, %{
          "name" => unique_repo_name(),
          "visibility" => "private"
        })

      issue_fixture(private, owner, %{"title" => "a private issue"})

      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      assert html =~ "a private issue"
    end

    test "a private org's dashboard redirects a non-member", %{conn: conn, owner: owner} do
      {:ok, secret} =
        Organizations.create_organization(owner, %{
          "handle" => "secret#{System.unique_integer([:positive])}",
          "name" => "Secret",
          "visibility" => "private"
        })

      outsider = user_fixture() |> set_password()

      assert {:error, {:live_redirect, %{to: "/"}}} =
               conn |> sign_in(outsider) |> live(path(secret))
    end

    test "signing in is required", %{conn: conn, org: org} do
      assert {:error, {:redirect, %{to: redirect}}} = live(conn, path(org))
      assert redirect =~ "/users/log-in"
    end

    test "404 for an org that doesn't exist", %{conn: conn, owner: owner} do
      assert_raise Ecto.NoResultsError, fn ->
        conn |> sign_in(owner) |> live("/orgs/nobody-at-all/dashboard")
      end
    end
  end

  describe "chrome" do
    test "links back to the org and its CI", %{conn: conn, owner: owner, org: org} do
      {:ok, _view, html} = conn |> sign_in(owner) |> live(path(org))

      assert html =~ ~s(href="/orgs/#{org.handle}")
      assert html =~ ~s(href="/orgs/#{org.handle}/actions")
    end

    test "an admin gets the New repository button; a plain member doesn't", %{
      conn: conn,
      owner: owner,
      org: org
    } do
      {:ok, admin_view, _html} = conn |> sign_in(owner) |> live(path(org))
      assert has_element?(admin_view, "#org-new-repo")

      member = user_fixture() |> set_password()
      {:ok, _} = Organizations.add_member(org, member, "member")

      {:ok, member_view, _html} = build_conn() |> sign_in(member) |> live(path(org))
      # Matched by id, not by text: the app layout has its own "New
      # repository" link for every signed-in visitor.
      refute has_element?(member_view, "#org-new-repo")
    end

    test "the org page offers the dashboard to signed-in visitors", %{
      conn: conn,
      owner: owner,
      org: org
    } do
      {:ok, _view, html} = conn |> sign_in(owner) |> live("/orgs/#{org.handle}")
      assert html =~ "/orgs/#{org.handle}/dashboard"

      {:ok, _view, anon} = live(build_conn(), "/orgs/#{org.handle}")
      refute anon =~ "/orgs/#{org.handle}/dashboard"
    end
  end
end