3.6 KiB · text History b868907
defmodule GitGudWeb.CiDurationChartTest do
  @moduledoc """
  The run-time history on both CI dashboards.

  Colour is status here, so the things that keep it readable without
  colour are asserted too: every bar names its outcome in a tooltip,
  and the legend spells the states out.
  """
  use GitGudWeb.ConnCase, async: false

  import Phoenix.LiveViewTest
  import GitGud.ForgeFixtures

  alias GitGud.Workflows.WorkflowRun

  setup %{conn: conn} do
    {user, repo} = repository_fixture(%{visibility: "public"})
    %{conn: log_in_user(conn, user), user: user, repo: repo, handle: user.handle}
  end

  defp finished_run(repo, number, seconds, conclusion \\ "success") do
    started = DateTime.add(~U[2026-09-01 00:00:00Z], number * 3600, :second)

    %WorkflowRun{repository_id: repo.id}
    |> WorkflowRun.create_changeset(%{
      number: number,
      workflow_path: ".forgejo/workflows/build.yml",
      workflow_name: "build",
      trigger: "push",
      head_sha: :crypto.strong_rand_bytes(20)
    })
    |> Ecto.Changeset.change(
      status: conclusion,
      conclusion: conclusion,
      started_at: started,
      completed_at: DateTime.add(started, seconds, :second)
    )
    |> GitGud.Repo.insert!()
  end

  describe "the repository dashboard" do
    test "charts finished runs with a median", %{conn: conn, repo: repo, handle: handle} do
      finished_run(repo, 1, 30)
      finished_run(repo, 2, 90)
      finished_run(repo, 3, 600, "failure")

      {:ok, _view, html} = live(conn, ~p"/r/#{handle}/#{repo.name}/actions")

      assert html =~ "Run times"
      # The peak bounds the scale for a chart with no y-axis.
      assert html =~ "median 1m30s"
      assert html =~ "peak 10m00s"
      assert html =~ "over 3 runs"

      # Status is never colour alone: each bar says what it was.
      assert html =~ "1m30s"
      assert html =~ "10m00s"
      assert html =~ "succeeded"
      assert html =~ "failed"
    end

    test "says nothing at all when no run has finished", %{conn: conn, repo: repo, handle: handle} do
      {:ok, _view, html} = live(conn, ~p"/r/#{handle}/#{repo.name}/actions")

      refute html =~ "Run times"
    end

    test "a running run isn't charted — its duration is still changing", %{
      conn: conn,
      repo: repo,
      handle: handle
    } do
      finished_run(repo, 1, 45)

      %WorkflowRun{repository_id: repo.id}
      |> WorkflowRun.create_changeset(%{
        number: 2,
        workflow_path: ".forgejo/workflows/build.yml",
        trigger: "push",
        head_sha: :crypto.strong_rand_bytes(20)
      })
      |> Ecto.Changeset.change(status: "running", started_at: DateTime.utc_now(:second))
      |> GitGud.Repo.insert!()

      {:ok, _view, html} = live(conn, ~p"/r/#{handle}/#{repo.name}/actions")

      assert html =~ "over 1 run"
    end
  end

  describe "the organization dashboard" do
    setup %{user: user} do
      {:ok, org} =
        GitGud.Organizations.create_organization(user, %{
          "handle" => "org#{System.unique_integer([:positive])}",
          "name" => "Test Org"
        })

      {:ok, repo} =
        GitGud.Repositories.create_repository_for_org(org, user, %{
          "name" => "widgets",
          "visibility" => "public"
        })

      %{org: org, org_repo: repo}
    end

    test "draws one sparkline per repository", %{conn: conn, org: org, org_repo: repo} do
      finished_run(repo, 1, 120)
      finished_run(repo, 2, 240)

      {:ok, _view, html} = live(conn, ~p"/orgs/#{org.handle}/actions")

      assert html =~ "Run times"
      assert html =~ "widgets"
      # The median, in the compact spelling the row uses.
      assert html =~ "3m"
    end
  end
end