88 lines
No EOL
3.1 KiB
TypeScript
88 lines
No EOL
3.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { parseCommitMessage } from "@/lib/git/conventional";
|
|
|
|
describe("parseCommitMessage", () => {
|
|
it("pulls out type, scope and subject", () => {
|
|
expect(parseCommitMessage("feat(stock): inline qty editing")).toEqual({
|
|
type: "feat",
|
|
scope: "stock",
|
|
subject: "inline qty editing",
|
|
breaking: false,
|
|
});
|
|
});
|
|
|
|
it("handles a missing scope", () => {
|
|
expect(parseCommitMessage("fix: correct the total")).toEqual({
|
|
type: "fix",
|
|
scope: "",
|
|
subject: "correct the total",
|
|
breaking: false,
|
|
});
|
|
});
|
|
|
|
it("flags a breaking change with and without a scope", () => {
|
|
expect(parseCommitMessage("feat!: drop v1 API").breaking).toBe(true);
|
|
expect(parseCommitMessage("feat(api)!: drop v1").breaking).toBe(true);
|
|
expect(parseCommitMessage("feat(api)!: drop v1").scope).toBe("api");
|
|
});
|
|
|
|
it("reads only the first line", () => {
|
|
const message =
|
|
"feat(customers): lift the toggle\n\nA long body that\nmentions fix(other): things\n";
|
|
expect(parseCommitMessage(message)).toEqual({
|
|
type: "feat",
|
|
scope: "customers",
|
|
subject: "lift the toggle",
|
|
breaking: false,
|
|
});
|
|
});
|
|
|
|
it("lowercases the type and the scope", () => {
|
|
const parsed = parseCommitMessage("Feat(Stock): thing");
|
|
expect(parsed.type).toBe("feat");
|
|
expect(parsed.scope).toBe("stock");
|
|
});
|
|
|
|
it("classifies an unparseable message as other, keeping the subject", () => {
|
|
expect(parseCommitMessage("just some words")).toEqual({
|
|
type: "other",
|
|
scope: "",
|
|
subject: "just some words",
|
|
breaking: false,
|
|
});
|
|
});
|
|
|
|
it("does not accept a space before the parenthesis", () => {
|
|
// "feat (stock): x" is not a conventional commit. Accepting it would make
|
|
// the scope breakdown depend on invisible whitespace.
|
|
expect(parseCommitMessage("feat (stock): x").type).toBe("other");
|
|
});
|
|
|
|
it("accepts any single lowercase word as a type, but not a phrase", () => {
|
|
// "note" is not a conventional type, but the parser cannot tell an unknown
|
|
// type from prose shaped like one, and it must not police a whitelist —
|
|
// see the note after Step 4.
|
|
expect(parseCommitMessage("note: this is not conventional").type).toBe("note");
|
|
// A space before the colon means it is a sentence, not a prefix.
|
|
expect(parseCommitMessage("TODO tomorrow: finish").type).toBe("other");
|
|
});
|
|
|
|
it("rejects a type containing non-letters", () => {
|
|
expect(parseCommitMessage("feat2(x): thing").type).toBe("other");
|
|
});
|
|
|
|
it("trims and caps an over-long subject", () => {
|
|
const parsed = parseCommitMessage(`feat(x): ${"s".repeat(400)}`);
|
|
expect(parsed.subject).toHaveLength(200);
|
|
});
|
|
|
|
it("returns other for an empty message", () => {
|
|
expect(parseCommitMessage("").type).toBe("other");
|
|
expect(parseCommitMessage(" \n ").subject).toBe("");
|
|
});
|
|
|
|
it("handles a scope containing a hyphen or slash", () => {
|
|
expect(parseCommitMessage("fix(delivery-notes): x").scope).toBe("delivery-notes");
|
|
expect(parseCommitMessage("fix(api/v1): x").scope).toBe("api/v1");
|
|
});
|
|
}); |