import test from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { parseDocx } from "../server/parser.js"; import { lessonKey, diffSchedules, changeCount, personalFilter, subgroupsOf, } from "../shared/lessons.js"; const fef = () => parseDocx(readFileSync(new URL("./fixtures/fef-23-ba.docx", import.meta.url)), { name: "23-ЛГ_23-БА.docx", }); const find = (s, group, test) => s.lessons.find((l) => l.groups.includes(group) && test(l)); test("Ключ занятия не зависит от строки таблицы и переживает перепубликацию", () => { const a = fef(), b = fef(); // Same content parsed twice: same keys, no changes. assert.deepEqual( a.lessons.map((l) => lessonKey(l, "23-БА")), b.lessons.map((l) => lessonKey(l, "23-БА")), ); assert.equal(changeCount(diffSchedules(a, b, "23-БА")), 0); const moved = { ...a.lessons[0], id: "other-row" }; assert.equal(lessonKey(moved, "23-БА"), lessonKey(a.lessons[0], "23-БА")); }); test("Сравнение версий: аудитория, перенос, новое и удалённое занятие", () => { const before = fef(), after = fef(); const room = find(after, "23-БА", (l) => l.day === 5 && l.start === "08:30"); room.room = "333А"; const pr = find(after, "23-БА", (l) => l.day === 5 && l.subject === "PR-менеджмент"); pr.start = "11:45"; const risk = find(after, "23-БА", (l) => l.day === 3 && l.subject === "Риск-менеджмент"); after.lessons.splice(after.lessons.indexOf(risk), 1); after.lessons.push({ ...pr, id: "new", day: 6, start: "08:30", subject: "Новый предмет" }); // A change for the other group must not reach 23-БА. find(after, "23-ЛГ", (l) => l.room).room = "999"; const diff = diffSchedules(before, after, "23-БА"); assert.deepEqual(diff.added.map((l) => l.subject), ["Новый предмет"]); assert.deepEqual(diff.removed.map((l) => l.subject), ["Риск-менеджмент"]); assert.deepEqual( diff.changed.map((c) => [c.after.subject, c.fields.map((f) => `${f.field}:${f.from}→${f.to}`)]), [ ["Инновационный менеджмент", ["room:333→333А"]], ["PR-менеджмент", ["start:10:05→11:45"]], ], ); assert.equal(changeCount(diff), 4); }); test("Изменённая пометка недель видна как изменение, а не как новое занятие", () => { const before = fef(), after = fef(); find(after, "23-БА", (l) => l.condition === "6-13н").condition = "6-14н"; const diff = diffSchedules(before, after, "23-БА"); assert.equal(diff.added.length + diff.removed.length, 0); assert.deepEqual(diff.changed[0].fields.map((f) => [f.label, f.from, f.to]), [ ["Недели", "6-13н", "6-14н"], ]); }); test("Подгруппа и скрытые занятия фильтруются только для своей группы", () => { const s = fef(); assert.deepEqual(subgroupsOf(s, "23-ЛГ"), ["Подгруппа 1", "Подгруппа 2"]); assert.deepEqual(subgroupsOf(s, "23-БА"), []); const first = find(s, "23-ЛГ", (l) => l.subgroups.some((g) => g.label === "Подгруппа 1")); const second = find(s, "23-ЛГ", (l) => l.subgroups.some((g) => g.label === "Подгруппа 2")); const whole = find(s, "23-ЛГ", (l) => !l.subgroups.length); const prefs = { subgroup: "Подгруппа 2", hidden: [lessonKey(whole, "23-ЛГ")] }; assert.equal(personalFilter(first, "23-ЛГ", prefs), "other-subgroup"); assert.equal(personalFilter(second, "23-ЛГ", prefs), "shown"); assert.equal(personalFilter(whole, "23-ЛГ", prefs), "hidden"); assert.equal(personalFilter(first, "23-ЛГ", null), "shown"); });