158 lines
4.4 KiB
TypeScript
158 lines
4.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
decisionEffectSchema,
|
|
decisionInputsSchema,
|
|
decisionOptionSchema,
|
|
decisionOptionsSchema,
|
|
} from "./validators/decision.js";
|
|
|
|
const targetIssueId = "11111111-1111-4111-8111-111111111111";
|
|
const secondIssueId = "22222222-2222-4222-8222-222222222222";
|
|
|
|
describe("decision validators", () => {
|
|
it("accepts all six effect variants", () => {
|
|
const effects = [
|
|
{
|
|
type: "comment_on_issue",
|
|
targetIssueId,
|
|
staleness: "lenient",
|
|
bodyMarkdown: "Approved with {{input.note}}",
|
|
},
|
|
{
|
|
type: "create_issue",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
draft: { title: "Follow up", parentId: targetIssueId },
|
|
},
|
|
{
|
|
type: "update_issue_status",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
status: "done",
|
|
comment: "Decision approved",
|
|
},
|
|
{
|
|
type: "assign_issue",
|
|
targetIssueId,
|
|
staleness: "lenient",
|
|
assigneeAgentId: secondIssueId,
|
|
},
|
|
{
|
|
type: "cancel_issue_tree",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
reasonComment: "No longer needed",
|
|
},
|
|
{
|
|
type: "resolve_blocker",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
removeBlockedByIssueIds: [secondIssueId],
|
|
},
|
|
];
|
|
|
|
for (const effect of effects) {
|
|
expect(decisionEffectSchema.parse(effect)).toEqual(effect);
|
|
}
|
|
});
|
|
|
|
it("rejects malformed and unknown effects", () => {
|
|
expect(() => decisionEffectSchema.parse({
|
|
type: "comment_on_issue",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
})).toThrow();
|
|
expect(() => decisionEffectSchema.parse({
|
|
type: "delete_company",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
})).toThrow();
|
|
expect(() => decisionEffectSchema.parse({
|
|
type: "assign_issue",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
})).toThrow();
|
|
});
|
|
|
|
it("forces cancel-tree effects to be strict and destructive", () => {
|
|
expect(() => decisionEffectSchema.parse({
|
|
type: "cancel_issue_tree",
|
|
targetIssueId,
|
|
staleness: "lenient",
|
|
reasonComment: "No longer needed",
|
|
})).toThrow();
|
|
|
|
expect(() => decisionOptionSchema.parse({
|
|
id: "cancel",
|
|
label: "Cancel tree",
|
|
effects: [{
|
|
type: "cancel_issue_tree",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
reasonComment: "No longer needed",
|
|
}],
|
|
})).toThrow();
|
|
|
|
expect(decisionOptionSchema.parse({
|
|
id: "cancel",
|
|
label: "Cancel tree",
|
|
style: "destructive",
|
|
effects: [{
|
|
type: "cancel_issue_tree",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
reasonComment: "No longer needed",
|
|
}],
|
|
}).style).toBe("destructive");
|
|
});
|
|
|
|
it("enforces option, input, and effect limits", () => {
|
|
const dismissOption = { id: "dismiss", label: "Dismiss", effects: [] };
|
|
expect(decisionOptionsSchema.parse(Array.from({ length: 8 }, (_, index) => ({
|
|
...dismissOption,
|
|
id: `option-${index}`,
|
|
})))).toHaveLength(8);
|
|
expect(() => decisionOptionsSchema.parse(Array.from({ length: 9 }, (_, index) => ({
|
|
...dismissOption,
|
|
id: `option-${index}`,
|
|
})))).toThrow();
|
|
|
|
expect(decisionInputsSchema.parse(Array.from({ length: 4 }, (_, index) => ({
|
|
id: `input-${index}`,
|
|
label: `Input ${index}`,
|
|
})))).toHaveLength(4);
|
|
expect(() => decisionInputsSchema.parse(Array.from({ length: 5 }, (_, index) => ({
|
|
id: `input-${index}`,
|
|
label: `Input ${index}`,
|
|
})))).toThrow();
|
|
|
|
const commentEffect = {
|
|
type: "comment_on_issue",
|
|
targetIssueId,
|
|
staleness: "strict",
|
|
bodyMarkdown: "Comment",
|
|
};
|
|
expect(decisionOptionSchema.parse({
|
|
id: "approve",
|
|
label: "Approve",
|
|
effects: Array.from({ length: 10 }, () => commentEffect),
|
|
}).effects).toHaveLength(10);
|
|
expect(() => decisionOptionSchema.parse({
|
|
id: "approve",
|
|
label: "Approve",
|
|
effects: Array.from({ length: 11 }, () => commentEffect),
|
|
})).toThrow();
|
|
});
|
|
|
|
it("rejects duplicate option and input ids", () => {
|
|
expect(() => decisionOptionsSchema.parse([
|
|
{ id: "same", label: "One", effects: [] },
|
|
{ id: "same", label: "Two", effects: [] },
|
|
])).toThrow();
|
|
expect(() => decisionInputsSchema.parse([
|
|
{ id: "same", label: "One" },
|
|
{ id: "same", label: "Two" },
|
|
])).toThrow();
|
|
});
|
|
});
|