Refactor code structure for improved readability and maintainability
This commit is contained in:
27
test/errors.test.js
Normal file
27
test/errors.test.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { apiError, describe, sourceError } from "../server/errors.js";
|
||||
|
||||
test("Ошибки API: код и статус для клиентов", () => {
|
||||
assert.deepEqual(describe(apiError(404, "group_not_found", "В документе нет группы 1-А.")), {
|
||||
status: 404,
|
||||
code: "group_not_found",
|
||||
message: "В документе нет группы 1-А.",
|
||||
});
|
||||
assert.deepEqual(describe({ code: "LIMIT_FILE_SIZE" }).code, "file_too_large");
|
||||
// Faults of the server itself never show their technical text.
|
||||
const internal = describe(new TypeError("Cannot read properties of undefined"));
|
||||
assert.equal(internal.status, 500);
|
||||
assert.equal(internal.code, "internal");
|
||||
assert.doesNotMatch(internal.message, /undefined/);
|
||||
});
|
||||
|
||||
test("Ошибки источника: таймаут curl отдельно от недоступности", () => {
|
||||
assert.equal(sourceError({ code: 28 }).code, "source_timeout");
|
||||
assert.equal(sourceError({ code: 28 }).status, 504);
|
||||
assert.equal(sourceError({ killed: true, signal: "SIGTERM" }).code, "source_timeout");
|
||||
assert.equal(sourceError({ code: 6 }).code, "source_unavailable");
|
||||
assert.equal(sourceError({ code: 22 }).status, 502);
|
||||
const own = apiError(502, "source_invalid", "Таблица недель не распознана.");
|
||||
assert.equal(sourceError(own), own);
|
||||
});
|
||||
BIN
test/fixtures/isf-credits-26-arh.docx
vendored
Normal file
BIN
test/fixtures/isf-credits-26-arh.docx
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/itzs-summer-2026.docx
vendored
Normal file
BIN
test/fixtures/itzs-summer-2026.docx
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/itzs-winter-2024.docx
vendored
Normal file
BIN
test/fixtures/itzs-winter-2024.docx
vendored
Normal file
Binary file not shown.
@@ -14,7 +14,7 @@ test("Импорт: не больше двух разборов сразу, ли
|
||||
active--;
|
||||
});
|
||||
const running = [task(), task(), task()];
|
||||
await assert.rejects(task(), (e) => e.status === 429 && e.message === "Занято");
|
||||
await assert.rejects(task(), (e) => e.status === 429 && e.code === "busy" && e.message === "Занято");
|
||||
// Each finished task hands its slot to the one waiting.
|
||||
while (release.length) {
|
||||
release.shift()();
|
||||
@@ -47,6 +47,10 @@ test("Импорт: лимит запросов считается по адре
|
||||
};
|
||||
assert.ok(call("10.0.0.1").passed);
|
||||
assert.ok(call("10.0.0.1").passed);
|
||||
assert.deepEqual(call("10.0.0.1"), { status: 429, body: { error: "Подождите" }, passed: false });
|
||||
assert.deepEqual(call("10.0.0.1"), {
|
||||
status: 429,
|
||||
body: { error: "Подождите", code: "too_many_requests" },
|
||||
passed: false,
|
||||
});
|
||||
assert.ok(call("10.0.0.2").passed);
|
||||
});
|
||||
|
||||
@@ -160,3 +160,79 @@ test("DAV: метаданные вложенных документов и то
|
||||
assert.equal(file.course, "4 курс");
|
||||
assert.equal(file.name, "23-ЛГ_23-БА.docx");
|
||||
});
|
||||
|
||||
// Laboratory-examination sessions of correspondence students (23-ИТзс): weeks side by side,
|
||||
// the group named only in the title, a date on every day.
|
||||
const itzs = (name) => parseDocx(fixture(name), { name: `${name}.docx` });
|
||||
const at = (s, date, start) =>
|
||||
s.lessons
|
||||
.filter((l) => l.date === date && l.start === start)
|
||||
.map((l) => [l.type, l.subject, l.teacher, l.room, l.subgroups.map((g) => g.label).join()]);
|
||||
|
||||
test("Заочная сессия: группа из заголовка, недели рядом, даты из Word", () => {
|
||||
const s = itzs("itzs-winter-2024");
|
||||
assert.deepEqual(s.groups, ["23-ИТзс"]);
|
||||
assert.equal(s.period, "Лабораторно-экзаменационная сессия");
|
||||
// Every filled discipline cell of the three weeks is one lesson.
|
||||
assert.equal(s.lessons.length, 36);
|
||||
assert.ok(s.lessons.every((l) => l.date >= "2024-01-08" && l.date <= "2024-01-28"));
|
||||
// Two columns under one heading are the subgroups' laboratory classes.
|
||||
assert.deepEqual(at(s, "2024-01-08", "17:00"), [
|
||||
["Лабораторная", "Основы информационных технологий и компьютерной графики", "Михнович О.В.", "217Д", "Подгруппа 1"],
|
||||
["Лабораторная", "Основы алгоритмизации и программирования", "Конаплева Г.Ф.", "218Д", "Подгруппа 2"],
|
||||
]);
|
||||
assert.deepEqual(at(s, "2024-01-15", "17:00"), [
|
||||
["Установочная лекция", "Математический анализ", "Забелендик О.Н.", "220Д", ""],
|
||||
]);
|
||||
// "Экзамен по учебной дисциплине «…»": the subject from the quotes, a room with a name.
|
||||
assert.deepEqual(at(s, "2024-01-18", "08:30"), [
|
||||
["Экзамен", "Основы алгоритмизации и программирования", "Чертков В.М.", "Медиа", ""],
|
||||
]);
|
||||
assert.deepEqual(at(s, "2024-01-16", "13:40"), [
|
||||
["Защита курсовой работы", "Основы алгоритмизации и программирования", "Чертков В.М.", "254В", ""],
|
||||
]);
|
||||
});
|
||||
|
||||
test("Заочная сессия: неровное деление столбцов и экзамен без конца", () => {
|
||||
const s = itzs("itzs-summer-2026");
|
||||
assert.deepEqual(s.groups, ["23-ИТзс"]);
|
||||
assert.equal(s.lessons.length, 58);
|
||||
// The third week's heading spans three columns, split 2+1 or 1+2: left and right subgroup.
|
||||
assert.deepEqual(at(s, "2026-06-24", "08:30").map((l) => [l[1], l[4]]), [
|
||||
["Методы и алгоритмы принятия", "Подгруппа 1"],
|
||||
["Распределенные вычисления", "Подгруппа 2"],
|
||||
]);
|
||||
// "8.30" alone: the exam starts then; its end comes from the bell table.
|
||||
const exam = s.lessons.find((l) => l.date === "2026-06-18" && l.type === "Экзамен");
|
||||
assert.deepEqual([exam.start, exam.end, exam.subject], ["08:30", null, "Базы данных"]);
|
||||
assert.equal(s.lessons.filter((l) => l.type === "Консультация").length, 4);
|
||||
});
|
||||
|
||||
test("Расписание зачетов: дата перед днём недели, одно время, зачёты по умолчанию", () => {
|
||||
const s = parseDocx(fixture("isf-credits-26-arh"), { name: "26-АРХ.docx" });
|
||||
assert.deepEqual(s.groups, ["26-АРХ"]);
|
||||
assert.equal(s.period, "Зачёты");
|
||||
assert.equal(s.lessons.length, 9);
|
||||
const row = (l) => [l.date, l.start, l.end, l.type, l.subject, l.subgroups.map((g) => g.label).join()];
|
||||
const sorted = [...s.lessons].sort((a, b) => (a.date + a.start).localeCompare(b.date + b.start));
|
||||
assert.deepEqual(sorted.slice(0, 2).map(row), [
|
||||
["2026-10-27", "17:00", null, "Консультация", "Введение в архитектурное проектирование", ""],
|
||||
["2026-10-31", "08:30", null, "Зачёт", "Введение в архитектурное проектирование", ""],
|
||||
]);
|
||||
// An empty date cell continues the day above: the second consultation on 18 December.
|
||||
assert.deepEqual(
|
||||
s.lessons.filter((l) => l.date === "2026-12-18").map((l) => [l.start, l.subject]),
|
||||
[
|
||||
["08:30", "Проектирование небольшого архитектурного сооружения"],
|
||||
["15:20", "Рисунок"],
|
||||
],
|
||||
);
|
||||
// Two columns under the group: each subgroup takes its credit with its own teacher.
|
||||
assert.deepEqual(
|
||||
s.lessons.filter((l) => l.date === "2026-12-22").map((l) => [l.teacher, l.room, l.subgroups[0]?.label]),
|
||||
[
|
||||
["Кузякова О.Д.", "361", "Подгруппа 1"],
|
||||
["Пискун А.А.", "370", "Подгруппа 2"],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -58,3 +58,28 @@ test("range=semester: все дни текущего семестра от пе
|
||||
assert.equal(t.days.at(-1).date, t.semester.end);
|
||||
assert.ok(t.days.length > 62, "больше обычного предела в 62 дня");
|
||||
});
|
||||
|
||||
test("Сессия с датами в Word не зависит от таблицы недель", () => {
|
||||
// June 2026 lies outside the 2026/27 week table, yet every lesson has its own date.
|
||||
const session = parseDocx(fixture("itzs-summer-2026"), { name: "23-ИТзс.docx" });
|
||||
const t = timetable({
|
||||
file: { id: "itzs", name: "23-ИТзс.docx" },
|
||||
schedule: session,
|
||||
calendar,
|
||||
group: "23-ИТзс",
|
||||
from: "2026-10-19",
|
||||
range: "semester",
|
||||
today: "2026-10-19",
|
||||
});
|
||||
assert.deepEqual(t.semester, {
|
||||
id: "session-2026-06-08",
|
||||
label: "Лабораторно-экзаменационная сессия",
|
||||
start: "2026-06-08",
|
||||
end: "2026-06-27",
|
||||
});
|
||||
assert.equal(t.note, null);
|
||||
assert.equal(t.days.length, 20);
|
||||
assert.equal(t.days.reduce((n, d) => n + d.lessons.length, 0), 58);
|
||||
const exam = t.days.find((d) => d.date === "2026-06-18").lessons.find((l) => l.type === "Экзамен");
|
||||
assert.deepEqual([exam.start, exam.end, exam.pair], ["08:30", "09:55", 1]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user