tests/weekReview.test.ts
Rama main · réplica de lectura del repositorio original.
// The weekly review's sums (shared/weekReview.ts): the week's bounds on
// each site's week, pages and hours by book from the sessions, the
// trackers' outlook, the sigils' week, the Orbits grades and the notes.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { parseRoutine } from "../shared/routine.ts";
import { booksThisWeek, localDay, notesThisWeek, orbitsThisWeek, previousWeek, sigilsThisWeek, trackerOutlook, weekOf, type ReviewTracker } from "../shared/weekReview.ts";
function tracker(over: Partial<ReviewTracker>): ReviewTracker {
return { path: "Media/Books/M.md", index: 0, title: "M", kind: "book", kindKey: "book", unit: null, status: "active", done: 100, total: 500, percent: 20, pace: null, due: null, sessions: [], ...over };
}
const s = (date: string, pages: number, minutes: number) => ({ date, from: null, to: null, pages, minutes });
/** Noon on an ISO day, in the machine's own zone — what localDay reads back. */
const noon = (iso: string): number => new Date(`${iso}T12:00:00`).getTime();
describe("the week", () => {
it("runs Monday to Sunday on an English site and Saturday to Friday on an Arabic one", () => {
// 2026-09-15 is a Tuesday.
assert.deepEqual(weekOf("2026-09-15", "en"), { start: "2026-09-14", end: "2026-09-20" });
assert.deepEqual(weekOf("2026-09-15", "ar"), { start: "2026-09-12", end: "2026-09-18" });
assert.deepEqual(previousWeek(weekOf("2026-09-15", "en")), { start: "2026-09-07", end: "2026-09-13" });
assert.equal(localDay(noon("2026-09-15")), "2026-09-15");
});
});
describe("books this week", () => {
it("sums the sessions inside the week per tracker, most read first, with the book's speed", () => {
const week = weekOf("2026-09-15", "en");
const a = tracker({ title: "A", sessions: [s("2026-09-13", 50, 50), s("2026-09-14", 10, 10), s("2026-09-15", 20, 10)] });
const b = tracker({ path: "B.md", title: "B", sessions: [s("2026-09-16", 40, 60)] });
const none = tracker({ path: "C.md", title: "C", sessions: [s("2026-09-01", 99, 99)] });
const rows = booksThisWeek([a, b, none], week);
assert.deepEqual(rows.map((r) => [r.title, r.pages, r.minutes, r.sessions]), [["B", 40, 60, 1], ["A", 30, 20, 2]]);
assert.equal(rows[1].speed, 80 / 70);
});
it("lists the active trackers nearest done first, with the projection and the time left", () => {
const rows = trackerOutlook(
[tracker({ title: "Half", done: 250, percent: 50, pace: 50, sessions: [s("2026-09-14", 30, 20)] }), tracker({ title: "Start", percent: 20 }), tracker({ title: "Done", status: "done", percent: 100 })],
"2026-09-15",
);
assert.deepEqual(rows.map((r) => r.title), ["Half", "Start"]);
assert.deepEqual(rows[0].projection, { kind: "done-by", date: "2026-09-20", pace: 50 });
assert.equal(rows[0].minutesLeft, Math.round(250 / 1.5));
assert.equal(rows[1].projection, null);
assert.equal(rows[1].minutesLeft, null);
});
});
describe("sigils this week", () => {
it("counts each sigil's complete days against its target and carries the streak", () => {
const plan = parseRoutine("title: Walk\nitems: walk\ntarget: 5\n")!;
const entries = ["2026-09-13", "2026-09-14", "2026-09-15"].map((date) => ({ date, done: ["walk"], skipped: [], deferred: [], values: {}, note: null }));
const [row] = sigilsThisWeek([{ path: "Sigils/Walk.md", index: 0, plan, entries }], "2026-09-15", "en");
assert.deepEqual([row.title, row.done, row.of, row.streak], ["Walk", 2, 5, 3]);
});
});
describe("orbits this week", () => {
it("counts the grades in the week, the retention and the days, per deck too", () => {
const week = weekOf("2026-09-15", "en");
const log = [
{ path: "Orbits/Kana.md", grade: "good" as const, ts: noon("2026-09-14") },
{ path: "Orbits/Kana.md", grade: "again" as const, ts: noon("2026-09-14") },
{ path: "Orbits/Verbs.md", grade: "easy" as const, ts: noon("2026-09-15") },
{ path: "Orbits/Verbs.md", grade: "good" as const, ts: noon("2026-09-01") },
];
const week1 = orbitsThisWeek(log, week);
assert.deepEqual([week1.graded, week1.retention, week1.days], [3, 2 / 3, 2]);
assert.deepEqual(week1.decks, [
{ path: "Orbits/Kana.md", graded: 2, retention: 0.5 },
{ path: "Orbits/Verbs.md", graded: 1, retention: 1 },
]);
assert.deepEqual(orbitsThisWeek([], week), { graded: 0, retention: null, days: 0, decks: [] });
});
});
describe("notes this week", () => {
it("separates the notes created in the week from the ones edited, the most edited first", () => {
const week = weekOf("2026-09-15", "en");
const notes = [
{ path: "New.md", title: "New", dateMs: noon("2026-09-15"), mtimeMs: noon("2026-09-15") },
{ path: "Old edited.md", title: "Old edited", dateMs: noon("2026-08-01"), mtimeMs: noon("2026-09-14") },
{ path: "Old busy.md", title: "Old busy", dateMs: noon("2026-08-01"), mtimeMs: noon("2026-09-14") - 1 },
{ path: "Untouched.md", title: "Untouched", dateMs: noon("2026-08-01"), mtimeMs: noon("2026-08-02") },
];
const out = notesThisWeek(notes, week, new Map([["Old busy.md", 7]]));
assert.deepEqual(out.created.map((n) => n.path), ["New.md"]);
assert.deepEqual(out.edited.map((n) => [n.path, n.edits]), [["Old busy.md", 7], ["Old edited.md", 1]]);
assert.equal(out.createdTotal, 1);
assert.equal(out.editedTotal, 2);
});
it("caps each list at the limit and says how many there were", () => {
const week = weekOf("2026-09-15", "en");
const notes = Array.from({ length: 20 }, (_, i) => ({ path: `n${i}.md`, title: `n${i}`, dateMs: noon("2026-09-14") + i, mtimeMs: noon("2026-09-14") + i }));
const out = notesThisWeek(notes, week, new Map(), 5);
assert.equal(out.created.length, 5);
assert.equal(out.createdTotal, 20);
// Newest first.
assert.equal(out.created[0].path, "n19.md");
assert.equal(out.edited.length, 0);
assert.equal(out.editedTotal, 0);
});
});