Submatter/packages/shared/src/convoy-lifecycle/state-machine.test.ts

79 lines
1.9 KiB
TypeScript
Raw Normal View History

import { describe, expect, it } from "vitest";
import { ConvoyTransitionError, validateConvoyTransition } from "./state-machine";
describe("validateConvoyTransition", () => {
it("rejects draft → released", () => {
expect(() =>
validateConvoyTransition({
from: "draft",
to: "released",
actor: "human-gate-1",
}),
).toThrow(ConvoyTransitionError);
try {
validateConvoyTransition({
from: "draft",
to: "released",
actor: "human-gate-1",
});
} catch (error) {
expect(error).toBeInstanceOf(ConvoyTransitionError);
expect((error as ConvoyTransitionError).code).toBe("INVALID_TRANSITION");
}
});
it("rejects role-architect on human-gate-1 transition", () => {
expect(() =>
validateConvoyTransition({
from: "convoy_review",
to: "ready",
actor: "role-architect",
}),
).toThrow(ConvoyTransitionError);
try {
validateConvoyTransition({
from: "convoy_review",
to: "ready",
actor: "role-architect",
});
} catch (error) {
expect((error as ConvoyTransitionError).code).toBe("FORBIDDEN_ACTOR");
}
});
it("allows human-gate-1 to approve plan", () => {
expect(() =>
validateConvoyTransition({
from: "convoy_review",
to: "ready",
actor: "human-gate-1",
}),
).not.toThrow();
});
it("allows role-architect to submit plan for review", () => {
expect(() =>
validateConvoyTransition({
from: "draft",
to: "convoy_review",
actor: "role-architect",
}),
).not.toThrow();
});
it("requires reason for blocked transitions", () => {
try {
validateConvoyTransition({
from: "ready",
to: "blocked",
actor: "role-implementer",
});
} catch (error) {
expect((error as ConvoyTransitionError).code).toBe("REASON_REQUIRED");
}
});
});