/* Unit tests for classifier covering deterministicClassify; SKIP_PATTERNS; conventional commits. It also guards the documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the classifier suite's contract for test-file scaffold coverage. */ import { describe, it, expect } from "vitest"; import { deterministicClassify } from "../changelog/agents/classifier-agent.ts"; import type { RawCommit } from "../changelog/types.ts"; function makeCommit(overrides: Partial & { message: string }): RawCommit { return { hash: "deadbeef", treeHash: "tree123", author: "test", date: new Date("2026-01-01"), files: [], diffSummary: "", isConventional: false, ...overrides, }; } describe("deterministicClassify", () => { describe("SKIP_PATTERNS", () => { it("marks lockfile bump commits as skip", () => { const c = makeCommit({ message: "chore: bump version", isConventional: true, conventionalType: "chore", }); expect(deterministicClassify(c).type).toBe("skip"); }); it("marks dep update commits as skip", () => { const c = makeCommit({ message: "chore: update deps", isConventional: true, conventionalType: "chore", }); expect(deterministicClassify(c).type).toBe("skip"); }); it("marks build: commits as skip", () => { const c = makeCommit({ message: "build: update webpack config" }); expect(deterministicClassify(c).type).toBe("skip"); }); it("marks ci: commits as skip", () => { const c = makeCommit({ message: "ci: update node version" }); expect(deterministicClassify(c).type).toBe("skip"); }); it("skip has confidence 1.0", () => { const c = makeCommit({ message: "chore: bump version" }); expect(deterministicClassify(c).confidence).toBe(1.0); }); }); describe("conventional commits", () => { it("feat: → type=feat, severity=minor, confidence=0.95", () => { const c = makeCommit({ message: "feat: add dark mode", isConventional: true, conventionalType: "feat", }); const r = deterministicClassify(c); expect(r.type).toBe("feat"); expect(r.severity).toBe("minor"); expect(r.confidence).toBe(0.95); }); it("fix: → type=fix, severity=patch", () => { const c = makeCommit({ message: "fix: correct auth error", isConventional: true, conventionalType: "fix", }); const r = deterministicClassify(c); expect(r.type).toBe("fix"); expect(r.severity).toBe("patch"); }); it("refactor: → type=refactor, severity=patch", () => { const c = makeCommit({ message: "refactor: simplify parser", isConventional: true, conventionalType: "refactor", }); const r = deterministicClassify(c); expect(r.type).toBe("refactor"); expect(r.severity).toBe("patch"); }); it("feat(auth): → module=auth", () => { const c = makeCommit({ message: "feat(auth): add OAuth", isConventional: true, conventionalType: "feat", }); expect(deterministicClassify(c).module).toBe("auth"); }); it("no scope → module=general", () => { const c = makeCommit({ message: "feat: add feature", isConventional: true, conventionalType: "feat", }); expect(deterministicClassify(c).module).toBe("general"); }); it("summary is trimmed text after colon", () => { const c = makeCommit({ message: "feat: add dark mode", isConventional: true, conventionalType: "feat", }); expect(deterministicClassify(c).summary).toBe("add dark mode"); }); }); describe("breaking changes", () => { it("feat!: → type=breaking, isBreaking=true", () => { const c = makeCommit({ message: "feat!: remove legacy API", isConventional: true, conventionalType: "feat", }); const r = deterministicClassify(c); expect(r.type).toBe("breaking"); expect(r.isBreaking).toBe(true); }); it("feat with BREAKING CHANGE in body → isBreaking=true", () => { const c = makeCommit({ message: "feat: redesign auth", body: "BREAKING CHANGE: token format changed", isConventional: true, conventionalType: "feat", }); const r = deterministicClassify(c); expect(r.type).toBe("breaking"); expect(r.isBreaking).toBe(true); }); it("breaking commit → severity=minor (not none)", () => { const c = makeCommit({ message: "feat!: remove API", isConventional: true, conventionalType: "feat", }); expect(deterministicClassify(c).severity).toBe("minor"); }); }); describe("non-conventional commits", () => { it("free-form message → type=chore, confidence=0.5", () => { const c = makeCommit({ message: "updated some stuff", isConventional: false }); const r = deterministicClassify(c); expect(r.type).toBe("chore"); expect(r.confidence).toBe(0.5); expect(r.severity).toBe("patch"); expect(r.isConventional).toBe(false); }); it("summary is truncated to 100 chars", () => { const long = "a".repeat(150); const c = makeCommit({ message: long, isConventional: false }); expect(deterministicClassify(c).summary).toHaveLength(100); }); }); });