test/openagents/project_items_test.exs

main at 58e6347eeb72 · 7 KB

defmodule OpenAgents.ProjectItemsTest do
  use OpenAgents.DataCase

  alias OpenAgents.ProjectItems

  setup do
    Process.put({__MODULE__, :repository}, repository_fixture())
    on_exit(fn -> Process.delete({__MODULE__, :repository}) end)
    :ok
  end

  describe "project_items" do
    alias OpenAgents.ProjectItems.ProjectItem

    import OpenAgents.IssuesFixtures
    import OpenAgents.ProjectItemsFixtures
    import OpenAgents.ProjectsFixtures

    @invalid_attrs %{values: nil, project_id: nil, issue_id: nil}

    test "list_project_items/0 returns all project_items" do
      project_item = project_item_fixture(repository())
      assert ProjectItems.list_project_items(repository()) == [project_item]
    end

    test "list_project_items/0 returns an empty list when none exist" do
      assert ProjectItems.list_project_items(repository()) == []
    end

    test "list_project_items/0 is not scoped to a project" do
      a = project_item_fixture(repository())
      b = project_item_fixture(repository())

      refute a.project_id == b.project_id

      ids = ProjectItems.list_project_items(repository()) |> Enum.map(& &1.id) |> Enum.sort()
      assert ids == Enum.sort([a.id, b.id])
    end

    test "get_project_item!/1 returns the project_item with given id" do
      project_item = project_item_fixture(repository())
      assert ProjectItems.get_project_item!(repository(), project_item.id) == project_item
    end

    test "get_project_item!/1 raises for an unknown id" do
      project_item = project_item_fixture(repository())

      assert_raise Ecto.NoResultsError, fn ->
        ProjectItems.get_project_item!(repository(), project_item.id + 1)
      end
    end

    test "create_project_item/1 with valid data creates a project_item" do
      project = project_fixture(repository())
      issue = issue_fixture(repository())

      valid_attrs = %{
        values: %{"Status" => "In Progress"},
        project_id: project.id,
        issue_id: issue.id
      }

      assert {:ok, %ProjectItem{} = project_item} =
               ProjectItems.create_project_item(repository(), valid_attrs)

      assert project_item.values == %{"Status" => "In Progress"}
      assert project_item.project_id == project.id
      assert project_item.issue_id == issue.id
    end

    test "create_project_item/1 leaves values nil when omitted" do
      project = project_fixture(repository())
      issue = issue_fixture(repository())

      assert {:ok, %ProjectItem{} = project_item} =
               ProjectItems.create_project_item(repository(), %{
                 project_id: project.id,
                 issue_id: issue.id
               })

      assert is_nil(project_item.values)
    end

    test "create_project_item/1 with invalid data returns error changeset" do
      assert {:error, %Ecto.Changeset{} = changeset} =
               ProjectItems.create_project_item(repository(), @invalid_attrs)

      assert %{project_id: ["can't be blank"], issue_id: ["can't be blank"]} =
               errors_on(changeset)
    end

    test "create_project_item/1 does not require values" do
      assert {:error, changeset} = ProjectItems.create_project_item(repository(), %{values: %{}})

      refute Map.has_key?(errors_on(changeset), :values)

      assert %{project_id: ["can't be blank"], issue_id: ["can't be blank"]} =
               errors_on(changeset)
    end

    test "create_project_item/1 requires an issue_id even with a project" do
      project = project_fixture(repository())

      assert {:error, changeset} =
               ProjectItems.create_project_item(repository(), %{project_id: project.id})

      assert %{issue_id: ["can't be blank"]} = errors_on(changeset)
      refute Map.has_key?(errors_on(changeset), :project_id)
    end

    test "create_project_item/1 reports a dangling project as a changeset error" do
      issue = issue_fixture(repository())

      assert {:error, changeset} =
               ProjectItems.create_project_item(repository(), %{
                 project_id: 2_147_483_000,
                 issue_id: issue.id
               })

      assert %{project_id: ["does not exist"]} = errors_on(changeset)
    end

    test "create_project_item/1 allows the same issue in two projects" do
      issue = issue_fixture(repository())
      one = project_fixture(repository(), number: 1)
      two = project_fixture(repository(), number: 2)

      assert {:ok, %ProjectItem{}} =
               ProjectItems.create_project_item(repository(), %{
                 project_id: one.id,
                 issue_id: issue.id
               })

      assert {:ok, %ProjectItem{}} =
               ProjectItems.create_project_item(repository(), %{
                 project_id: two.id,
                 issue_id: issue.id
               })

      assert length(ProjectItems.list_project_items(repository())) == 2
    end

    test "update_project_item/2 with valid data updates the project_item" do
      project_item = project_item_fixture(repository())
      update_attrs = %{values: %{"Status" => "Done"}}

      assert {:ok, %ProjectItem{} = project_item} =
               ProjectItems.update_project_item(project_item, update_attrs)

      assert project_item.values == %{"Status" => "Done"}
    end

    test "update_project_item/2 replaces values wholesale rather than merging" do
      project_item =
        project_item_fixture(repository(), values: %{"Status" => "Todo", "Size" => "L"})

      assert {:ok, %ProjectItem{} = updated} =
               ProjectItems.update_project_item(project_item, %{values: %{"Status" => "Done"}})

      assert updated.values == %{"Status" => "Done"}
    end

    test "update_project_item/2 with invalid data returns error changeset" do
      project_item = project_item_fixture(repository())

      assert {:error, %Ecto.Changeset{}} =
               ProjectItems.update_project_item(project_item, @invalid_attrs)

      assert project_item == ProjectItems.get_project_item!(repository(), project_item.id)
    end

    test "delete_project_item/1 deletes the project_item" do
      project_item = project_item_fixture(repository())
      assert {:ok, %ProjectItem{}} = ProjectItems.delete_project_item(project_item)

      assert_raise Ecto.NoResultsError, fn ->
        ProjectItems.get_project_item!(repository(), project_item.id)
      end
    end

    test "change_project_item/1 returns a project_item changeset" do
      project_item = project_item_fixture(repository())
      assert %Ecto.Changeset{} = ProjectItems.change_project_item(project_item)
    end

    test "change_project_item/2 applies the given attrs" do
      project_item = project_item_fixture(repository())

      changeset = ProjectItems.change_project_item(project_item, %{values: %{"Status" => "Done"}})

      assert changeset.valid?
      assert Ecto.Changeset.get_change(changeset, :values) == %{"Status" => "Done"}
    end

    test "change_project_item/2 surfaces validation errors without touching the database" do
      project_item = project_item_fixture(repository())

      changeset = ProjectItems.change_project_item(project_item, %{issue_id: nil})

      refute changeset.valid?
      assert %{issue_id: ["can't be blank"]} = errors_on(changeset)
      assert project_item == ProjectItems.get_project_item!(repository(), project_item.id)
    end
  end

  defp repository, do: Process.get({__MODULE__, :repository})
end