Files
kandev/apps/web/components/github/pr-mergeability-notice.test.ts
T
2026-05-30 12:44:35 +01:00

79 lines
2.9 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { describeMergeability, buildConflictResolutionMessage } from "./pr-mergeability-notice";
import type { MergeableState } from "@/lib/types/github";
function describe_({
state,
mergeable = false,
isDraft = false,
prState = "open",
}: {
state: MergeableState | undefined;
mergeable?: boolean;
isDraft?: boolean;
prState?: string;
}) {
return describeMergeability({ state, mergeable, isDraft, prState });
}
describe("describeMergeability", () => {
it("shows the conflict banner for a dirty PR", () => {
expect(describe_({ state: "dirty" })).toEqual({ kind: "banner" });
});
it("shows a 'Blocked' chip for a blocked PR (even when GitHub reports mergeable)", () => {
expect(describe_({ state: "blocked", mergeable: true })).toEqual({
kind: "chip",
label: "Blocked",
});
});
it("shows a 'Behind base' chip for a behind PR", () => {
expect(describe_({ state: "behind", mergeable: true })).toEqual({
kind: "chip",
label: "Behind base",
});
});
it("shows nothing for clean / unstable / has_hooks / draft", () => {
expect(describe_({ state: "clean", mergeable: true })).toEqual({ kind: "none" });
expect(describe_({ state: "unstable", mergeable: true })).toEqual({ kind: "none" });
expect(describe_({ state: "has_hooks", mergeable: true })).toEqual({ kind: "none" });
// "draft" enum on a non-draft PR object must not fall through to "Not mergeable".
expect(describe_({ state: "draft", mergeable: false })).toEqual({ kind: "none" });
});
it("falls back to generic text for unknown states that GitHub deems non-mergeable", () => {
expect(describe_({ state: "unknown", mergeable: false })).toEqual({ kind: "text" });
expect(describe_({ state: "", mergeable: false })).toEqual({ kind: "text" });
expect(describe_({ state: undefined, mergeable: false })).toEqual({ kind: "text" });
});
it("shows nothing for unknown states GitHub still considers mergeable", () => {
expect(describe_({ state: "unknown", mergeable: true })).toEqual({ kind: "none" });
});
it("suppresses every notice for draft PRs", () => {
expect(describe_({ state: "dirty", isDraft: true })).toEqual({ kind: "none" });
});
it("suppresses every notice for non-open PRs", () => {
expect(describe_({ state: "dirty", prState: "merged" })).toEqual({ kind: "none" });
expect(describe_({ state: "dirty", prState: "closed" })).toEqual({ kind: "none" });
});
});
describe("buildConflictResolutionMessage", () => {
it("names the PR and both branches", () => {
const msg = buildConflictResolutionMessage({
prNumber: 1132,
headBranch: "feature/x",
baseBranch: "main",
});
expect(msg).toContain("#1132");
expect(msg).toContain("`feature/x`");
expect(msg).toContain("`main`");
expect(msg.toLowerCase()).toContain("conflict");
});
});