mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-07-19 17:02:59 +00:00
TDD'd pure planning core (planFolderReorder with payload validation, groupPortfoliosForHome with starred float + recency, planFolderDeletion encoding unfile-then-delete, buildStarChange owning starred_at-as-flag), applied by thin route handlers: folder create/rename/delete/reorder, per-portfolio config upsert, and the grouped home read. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
114 lines
3.3 KiB
TypeScript
114 lines
3.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildStarChange,
|
|
groupPortfoliosForHome,
|
|
planFolderDeletion,
|
|
planFolderReorder,
|
|
} from "./portfolioUserConfig";
|
|
|
|
describe("planFolderReorder", () => {
|
|
it("renumbers every folder to its index in the requested order", () => {
|
|
const plan = planFolderReorder({
|
|
currentIds: [1n, 2n, 3n],
|
|
orderedIds: [3n, 1n, 2n],
|
|
});
|
|
|
|
expect(plan).toEqual({
|
|
updates: [
|
|
{ id: 3n, position: 0 },
|
|
{ id: 1n, position: 1 },
|
|
{ id: 2n, position: 2 },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("rejects an order naming a folder the user does not have", () => {
|
|
const plan = planFolderReorder({
|
|
currentIds: [1n, 2n],
|
|
orderedIds: [2n, 99n],
|
|
});
|
|
|
|
expect(plan).toEqual({
|
|
error: "Folder order does not match your folders",
|
|
});
|
|
});
|
|
|
|
it("rejects an order that lists the same folder twice", () => {
|
|
const plan = planFolderReorder({
|
|
currentIds: [1n, 2n],
|
|
orderedIds: [1n, 1n, 2n],
|
|
});
|
|
|
|
expect(plan).toEqual({
|
|
error: "Folder order does not match your folders",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("groupPortfoliosForHome", () => {
|
|
it("groups portfolios into folders ordered by position, with the rest unfiled", () => {
|
|
const grouped = groupPortfoliosForHome({
|
|
portfolios: [{ id: 1n }, { id: 2n }, { id: 3n }],
|
|
configs: [
|
|
{ portfolioId: 1n, folderId: 10n, starredAt: null },
|
|
{ portfolioId: 2n, folderId: 11n, starredAt: null },
|
|
],
|
|
folders: [
|
|
{ id: 10n, name: "SHDF Wave 3", position: 1 },
|
|
{ id: 11n, name: "Demos", position: 0 },
|
|
],
|
|
});
|
|
|
|
expect(grouped.folders).toEqual([
|
|
{ id: 11n, name: "Demos", portfolios: [{ id: 2n }] },
|
|
{ id: 10n, name: "SHDF Wave 3", portfolios: [{ id: 1n }] },
|
|
]);
|
|
expect(grouped.unfiled).toEqual([{ id: 3n }]);
|
|
});
|
|
|
|
it("floats starred portfolios to the top of their group and lists them most-recently-starred first", () => {
|
|
const grouped = groupPortfoliosForHome({
|
|
portfolios: [{ id: 1n }, { id: 2n }, { id: 3n }, { id: 4n }],
|
|
configs: [
|
|
{ portfolioId: 1n, folderId: 10n, starredAt: null },
|
|
{ portfolioId: 2n, folderId: 10n, starredAt: new Date("2026-07-01") },
|
|
{ portfolioId: 4n, folderId: null, starredAt: new Date("2026-07-05") },
|
|
],
|
|
folders: [{ id: 10n, name: "SHDF Wave 3", position: 0 }],
|
|
});
|
|
|
|
expect(grouped.folders[0].portfolios).toEqual([{ id: 2n }, { id: 1n }]);
|
|
expect(grouped.unfiled).toEqual([{ id: 4n }, { id: 3n }]);
|
|
expect(grouped.starred).toEqual([{ id: 4n }, { id: 2n }]);
|
|
});
|
|
});
|
|
|
|
describe("planFolderDeletion", () => {
|
|
it("unfiles exactly the configs in the folder, then deletes the folder", () => {
|
|
const plan = planFolderDeletion({
|
|
folderId: 10n,
|
|
configs: [
|
|
{ id: 1n, folderId: 10n },
|
|
{ id: 2n, folderId: 11n },
|
|
{ id: 3n, folderId: 10n },
|
|
{ id: 4n, folderId: null },
|
|
],
|
|
});
|
|
|
|
expect(plan).toEqual({
|
|
unfileConfigIds: [1n, 3n],
|
|
deleteFolderId: 10n,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildStarChange", () => {
|
|
it("starring stamps the moment, unstarring clears it", () => {
|
|
const now = new Date("2026-07-07T12:00:00Z");
|
|
|
|
expect(buildStarChange({ starred: true, now })).toEqual({ starredAt: now });
|
|
expect(buildStarChange({ starred: false, now })).toEqual({
|
|
starredAt: null,
|
|
});
|
|
});
|
|
});
|