kanban-dev-webapp/src/lib/activity/format.test.ts

167 lines
5.3 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from "vitest";
import { describeActivity } from "@/lib/activity/format";
import type { ActivityRecord } from "@/lib/pb/types";
function row(overrides: Partial<ActivityRecord>): ActivityRecord {
return {
id: "a1",
created: "2026-09-16 10:00:00.000Z",
project: "p1",
card: "c1",
actor: "u1",
action: "card_updated",
field: "",
old_value: "",
new_value: "",
...overrides,
} as ActivityRecord;
}
describe("describeActivity", () => {
it("describes a priority change in words, not codes", () => {
expect(
describeActivity(
row({ action: "priority_changed", field: "priority", old_value: "medium", new_value: "high" })
)
).toBe("changed priority from Medium to High");
});
it("describes setting a target date that had none", () => {
expect(
describeActivity(
row({ action: "date_changed", field: "target_date", old_value: "", new_value: "2026-10-01" })
)
).toBe("set the target date to 1 Oct 2026");
});
it("describes moving a target date", () => {
expect(
describeActivity(
row({
action: "date_changed",
field: "target_date",
old_value: "2026-10-01 00:00:00.000Z",
new_value: "2026-11-15",
})
)
).toBe("moved the target date from 1 Oct 2026 to 15 Nov 2026");
});
it("describes clearing a target date", () => {
expect(
describeActivity(
row({ action: "date_changed", field: "target_date", old_value: "2026-10-01", new_value: "" })
)
).toBe("cleared the target date");
});
it("describes card creation, acceptance and archiving", () => {
expect(describeActivity(row({ action: "card_created", new_value: "Add a POS system" })))
.toBe("added this card");
expect(describeActivity(row({ action: "card_accepted" }))).toBe("accepted this request");
expect(describeActivity(row({ action: "card_archived" }))).toBe("archived this card");
});
it("names the destination when a card moves", () => {
expect(describeActivity(row({ action: "card_moved", new_value: "In Progress" })))
.toBe("moved this card to In Progress");
});
it("falls back gracefully when a move has no destination recorded", () => {
expect(describeActivity(row({ action: "card_moved", new_value: "" })))
.toBe("moved this card");
});
it("describes comments and subtasks", () => {
expect(describeActivity(row({ action: "comment_added" }))).toBe("commented");
expect(
describeActivity(row({ action: "subtask_toggled", new_value: "true", field: "Wire up the till" }))
).toBe("completed “Wire up the till”");
expect(
describeActivity(row({ action: "subtask_toggled", new_value: "false", field: "Wire up the till" }))
).toBe("reopened “Wire up the till”");
});
2026-09-19 16:35:33 +00:00
it("describes a column move with the new column name", () => {
expect(
describeActivity(
row({ action: "column_changed", field: "column", old_value: "col_done", new_value: "Backlog" })
)
).toBe("moved this card to Backlog");
});
it("describes a column move out of a column when only the old name is known", () => {
expect(
describeActivity(
row({ action: "column_changed", field: "column", old_value: "Done", new_value: "" })
)
).toBe("moved this card out of Done");
});
it("describes a client proposal in human terms", () => {
expect(
describeActivity(
row({
action: "date_proposed",
field: "proposed_target_date",
old_value: "",
new_value: "2026-11-15",
})
)
).toBe("proposed moving this card to 15 Nov 2026");
});
it("describes an accepted proposal with its date", () => {
expect(
describeActivity(
row({
action: "date_proposal_resolved",
field: "proposed_target_date",
old_value: "2026-11-15",
new_value: "accepted",
})
)
).toBe("accepted the proposal for 15 Nov 2026");
});
it("describes a dismissed proposal with its date", () => {
expect(
describeActivity(
row({
action: "date_proposal_resolved",
field: "proposed_target_date",
old_value: "2026-11-15",
new_value: "dismissed",
})
)
).toBe("dismissed the proposal for 15 Nov 2026");
});
it("falls back gracefully when a resolved proposal has no date", () => {
expect(
describeActivity(
row({
action: "date_proposal_resolved",
field: "proposed_target_date",
old_value: "",
new_value: "accepted",
})
)
).toBe("accepted a proposal");
});
it("describes a generic update", () => {
expect(describeActivity(row({ action: "card_updated", field: "description" })))
.toBe("updated the description");
expect(describeActivity(row({ action: "card_updated", field: "title" })))
.toBe("renamed this card");
});
it("never returns an empty string for an unknown action", () => {
// Double assertion on purpose: the point is to simulate an action value
// added by a later phase that this switch has not learned yet.
const unknown = "something_new" as unknown as ActivityRecord["action"];
const result = describeActivity(row({ action: unknown }));
expect(result.length).toBeGreaterThan(0);
});
});