Files
kandev/apps/web/lib/github/ci-automation.test.ts
T
2026-08-12 18:36:11 +01:00

135 lines
4.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
autoFixRoundForState,
clampAutoFixRound,
findCIAutomationStateForPR,
findPRAutomationOptionsForPR,
normalizeAutoFixMaxRounds,
} from "./ci-automation";
import type { TaskCIPRAutomationState, TaskPR, TaskPRAutomationOptions } from "@/lib/types/github";
function makePR(repositoryID: string, prNumber = 42, taskID = "task-1"): TaskPR {
return {
task_id: taskID,
repository_id: repositoryID,
pr_number: prNumber,
} as TaskPR;
}
function makePRAutomationOptions(
repositoryID: string,
prNumber: number,
overrides: Partial<TaskPRAutomationOptions> = {},
): TaskPRAutomationOptions {
return {
task_id: "task-1",
repository_id: repositoryID,
pr_number: prNumber,
auto_fix_enabled: false,
auto_merge_enabled: false,
prompt_on_review_requested: false,
prompt_on_merged: false,
prompt_on_closed: false,
created_at: "",
updated_at: "",
...overrides,
};
}
function makeState(
repositoryID: string,
prNumber: number,
roundCount: number,
exhaustedAt: string | null = null,
): TaskCIPRAutomationState {
return {
repository_id: repositoryID,
pr_number: prNumber,
auto_fix_round_count: roundCount,
auto_fix_exhausted_at: exhaustedAt,
} as TaskCIPRAutomationState;
}
describe("CI automation helpers", () => {
it("finds PR automation state by repository id and PR number", () => {
const states = [makeState("", 42, 1), makeState("repo-1", 42, 2), makeState("repo-1", 7, 3)];
expect(findCIAutomationStateForPR(states, makePR("repo-1", 42))).toBe(states[1]);
expect(findCIAutomationStateForPR(states, makePR("", 42))).toBe(states[0]);
expect(findCIAutomationStateForPR(states, makePR("repo-missing", 42))).toBeUndefined();
});
it("returns an empty round state when no PR state exists", () => {
expect(autoFixRoundForState(undefined, 12)).toEqual({
current: 0,
max: 12,
exhausted: false,
});
});
it("treats only backend exhaustion timestamps as paused", () => {
expect(autoFixRoundForState(makeState("repo-1", 42, 10), 10)).toEqual({
current: 10,
max: 10,
exhausted: false,
});
expect(autoFixRoundForState(makeState("repo-1", 42, 3, "2026-06-18T11:00:00Z"), 10)).toEqual({
current: 3,
max: 10,
exhausted: true,
});
});
it("finds PR automation options by repository id and PR number, independent of other PRs", () => {
const options = [
makePRAutomationOptions("repo-1", 1, { auto_fix_enabled: true }),
makePRAutomationOptions("repo-1", 2, { auto_fix_enabled: false }),
makePRAutomationOptions("repo-2", 1, { auto_merge_enabled: true }),
];
expect(findPRAutomationOptionsForPR(options, makePR("repo-1", 1))).toBe(options[0]);
expect(findPRAutomationOptionsForPR(options, makePR("repo-1", 2))).toBe(options[1]);
// Same PR number, different repository — must not collide with repo-1's entry.
expect(findPRAutomationOptionsForPR(options, makePR("repo-2", 1))).toBe(options[2]);
});
it("returns all-off defaults for a PR with no stored automation row", () => {
const options = [makePRAutomationOptions("repo-1", 1, { auto_fix_enabled: true })];
const result = findPRAutomationOptionsForPR(options, makePR("repo-1", 99, "task-9"));
expect(result).toEqual({
task_id: "task-9",
repository_id: "repo-1",
pr_number: 99,
auto_fix_enabled: false,
auto_merge_enabled: false,
prompt_on_review_requested: false,
prompt_on_merged: false,
prompt_on_closed: false,
created_at: "",
updated_at: "",
});
});
it("returns all-off defaults when pr_options is undefined", () => {
expect(findPRAutomationOptionsForPR(undefined, makePR("repo-1", 1)).auto_fix_enabled).toBe(
false,
);
});
it("normalizes max rounds and clamps current rounds", () => {
expect(normalizeAutoFixMaxRounds(undefined)).toBe(10);
expect(normalizeAutoFixMaxRounds(null)).toBe(10);
expect(normalizeAutoFixMaxRounds(Number.NaN)).toBe(10);
expect(normalizeAutoFixMaxRounds(0)).toBe(1);
expect(normalizeAutoFixMaxRounds(-4)).toBe(1);
expect(normalizeAutoFixMaxRounds(12.8)).toBe(12);
expect(clampAutoFixRound(undefined, 10)).toBe(0);
expect(clampAutoFixRound(Number.NaN, 10)).toBe(0);
expect(clampAutoFixRound(-2, 10)).toBe(0);
expect(clampAutoFixRound(4.9, 10)).toBe(4);
expect(clampAutoFixRound(14, 10)).toBe(10);
});
});