Files
psu-schedule/test/weeks.test.js
Zakhar Timoshenko 15851b26cd feat: Enhance session handling in timetable and UI
- Introduced session types (exams, credits, consultations, coursework defenses) with distinct icons and colors for better visibility in the UI.
- Updated PlansScreen, ScheduleScreen, and WeekGrid to display session information appropriately.
- Modified CalendarView and PlansView to include session indicators in the calendar and plans.
- Enhanced LessonCard and CompactLesson to show session details and adjust styling based on session presence.
- Added new SessionMark component for consistent session representation across Android and iOS.
- Updated server logic to handle session entries from external documents, ensuring accurate timetable representation.
- Improved date parsing to accommodate session-related dates in various formats.
- Added tests to verify session handling and date parsing functionality.
2026-10-19 20:49:13 +03:00

139 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { parseDocx } from "../server/parser.js";
import { parseWeeksDocx, parseBellsDocx } from "../server/calendar.js";
import {
parseWeekRanges,
parseTextDates,
lessonWeeks,
lessonDates,
dateInWeek,
weekIndexOf,
todayIso,
} from "../shared/weeks.js";
const fixture = (name) =>
readFileSync(new URL(`./fixtures/${name}.docx`, import.meta.url));
const calendar = {
weeks: parseWeeksDocx(fixture("weeks")),
bells: parseBellsDocx(fixture("bells")),
};
const fef = () =>
parseDocx(fixture("fef-23-ba"), { name: "23-ЛГ_23-БА.docx" }).lessons.filter(
(l) => l.groups.includes("23-БА"),
);
test("Таблица недель: 18 недель, нечётные белые, неделя 1 со вторника", () => {
const { weeks } = calendar;
assert.equal(weeks.length, 18);
assert.deepEqual(weeks[0], {
n: 1,
start: "2026-09-01",
end: "2026-09-06",
color: "white",
});
assert.deepEqual(weeks.at(-1), {
n: 18,
start: "2026-12-28",
end: "2027-01-03",
color: "green",
});
assert.ok(weeks.every((w) => (w.n % 2 ? "white" : "green") === w.color));
assert.equal(dateInWeek(weeks[0], 1), null);
assert.equal(dateInWeek(weeks[0], 2), "2026-09-01");
assert.equal(weekIndexOf(calendar, "2026-10-16"), 6);
assert.equal(weekIndexOf(calendar, "2027-02-01"), -1);
assert.equal(todayIso(new Date("2026-10-15T22:30:00Z")), "2026-10-16");
});
test("Звонки: восемь пар с половинами", () => {
assert.equal(calendar.bells.length, 8);
assert.deepEqual(calendar.bells[1], {
pair: 2,
start: "10:05",
end: "11:30",
halves: [
["10:05", "10:45"],
["10:50", "11:30"],
],
});
});
test("Пометки недель: диапазоны, «с N», опечатки остаются для сверки", () => {
assert.deepEqual(parseWeekRanges("1-4,6-11н."), [
[1, 4],
[6, 11],
]);
assert.deepEqual(parseWeekRanges("со 2 нед."), [[2, null]]);
assert.deepEqual(parseWeekRanges("с 4-16н"), [[4, 16]]);
assert.deepEqual(parseWeekRanges("1-8,10-17"), [
[1, 8],
[10, 17],
]);
assert.equal(parseWeekRanges("2,6-12-16н"), null);
assert.equal(parseWeekRanges("26.10"), null);
assert.equal(parseWeekRanges(""), null);
});
test("Цвет строки ограничивает диапазон чётностью недели", () => {
const white = { day: 2, date: null, condition: "13-17н", variant: "upper" };
const green = { day: 4, date: null, condition: "4-12н", variant: "lower" };
const every = { day: 5, date: null, condition: "6-13н", variant: "all" };
const plain = { day: 1, date: null, condition: "", variant: "lower" };
assert.deepEqual(lessonWeeks(white, 18), [13, 15, 17]);
assert.deepEqual(lessonWeeks(green, 18), [4, 6, 8, 10, 12]);
assert.deepEqual(lessonWeeks(every, 18), [6, 7, 8, 9, 10, 11, 12, 13]);
assert.deepEqual(lessonWeeks(plain, 18), [2, 4, 6, 8, 10, 12, 14, 16, 18]);
assert.equal(
lessonWeeks({ ...white, condition: "2,6-12-16н" }, 18),
null,
);
assert.deepEqual(lessonDates(every, calendar).slice(0, 2), [
"2026-10-09",
"2026-10-16",
]);
});
test("Парсер: 23-БА получает номера недель и даты дня информирования", () => {
const lessons = fef();
const friday = lessons.filter((l) => l.day === 5 && l.start === "10:05");
assert.deepEqual(
friday.map((l) => l.weekRanges),
[[[1, 4], [6, 11]], [[12, 15]], [[16, 16]]],
);
const week7 = friday.filter((l) => lessonWeeks(l, 18).includes(7));
assert.deepEqual(
week7.map((l) => l.subject),
["PR-менеджмент"],
);
const info = lessons.find((l) =>
l.subject.startsWith("Единый день информирования"),
);
assert.deepEqual(info.dates, [
"2026-09-10",
"2026-10-15",
"2026-11-19",
"2026-12-17",
]);
assert.deepEqual(parseTextDates("17 декабря и 14 января", 2026), [
"2026-12-17",
"2027-01-14",
]);
// Every coloured-row mark in the real document agrees with the week table.
for (const l of lessons.filter((l) => l.variant !== "all" && l.weekRanges))
for (const [a, b] of l.weekRanges)
for (const n of [a, b ?? a])
assert.equal(n % 2, l.variant === "upper" ? 1 : 0, l.raw);
});
test("Даты числами: «10.09;15.10;19.11;17.12», но не время пары", () => {
// ИСФ пишет дни информирования списком дат, как в 23-АРХ.
assert.deepEqual(parseTextDates("Единый день информирования 10.09;15.10;19.11;17.12", 2026), [
"2026-09-10",
"2026-10-15",
"2026-11-19",
"2026-12-17",
]);
assert.deepEqual(parseTextDates("03.10, 17.10. Физика", 2026), ["2026-10-03", "2026-10-17"]);
assert.deepEqual(parseTextDates("12.01.2027; 19.01.2027 Экзамен", 2026), ["2027-01-12", "2027-01-19"]);
// One number pair alone or a time range is a time, not a date.
for (const time of ["10.05 Лекция", "10.05-11.30", "16.50 Информационный час", "09.11 по 06.12 практика"])
assert.deepEqual(parseTextDates(time, 2026), [], time);
});