Задача Егора 2ч.

This commit is contained in:
2026-07-17 01:27:02 +03:00
parent 3f685d3e22
commit 3d798c13e3
20 changed files with 2003 additions and 275 deletions

View File

@@ -0,0 +1,151 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
CONFLICT_CHECK_REASON,
CONFLICT_CHECK_STATE,
conflictCheckPresentation,
currentWeekDateRange,
formatLocalDate,
loadDepartmentSchedules
} from '../admin/js/dashboard-conflicts.js';
process.env.TZ = 'Europe/Moscow';
test('неделя для 2026-07-02 охватывает 2026-06-29…2026-07-05', () => {
assert.deepEqual(
currentWeekDateRange(new Date('2026-07-01T21:15:00Z')),
{ startDate: '2026-06-29', endDate: '2026-07-05' }
);
});
test('неделя корректно пересекает границу года', () => {
assert.deepEqual(
currentWeekDateRange(new Date(2026, 0, 1, 8, 30, 0)),
{ startDate: '2025-12-29', endDate: '2026-01-04' }
);
});
test('date-only формируется из локальных компонентов', () => {
assert.equal(formatLocalDate(new Date('2026-01-01T21:15:00Z')), '2026-01-02');
});
test('полный успех разрешает достоверный вывод по всем кафедрам', async () => {
const result = await loadDepartmentSchedules(
[{ id: 1 }, { id: 2 }],
async department => [{ departmentId: department.id }]
);
assert.equal(result.state, CONFLICT_CHECK_STATE.COMPLETE);
assert.equal(result.checkedDepartmentCount, 2);
assert.equal(result.totalDepartmentCount, 2);
assert.deepEqual(result.lessons, [{ departmentId: 1 }, { departmentId: 2 }]);
assert.deepEqual(result.failedDepartments, []);
});
test('единичный отказ даёт частичный результат, а не пустой успешный ответ', async () => {
const departments = [
{ id: 1, departmentName: 'Физика' },
{ id: 2, departmentName: 'Математика' }
];
const result = await loadDepartmentSchedules(departments, async department => {
if (department.id === 2) {
throw new Error('тестовая техническая причина');
}
return [{ departmentId: department.id }];
});
assert.equal(result.state, CONFLICT_CHECK_STATE.PARTIAL);
assert.equal(result.checkedDepartmentCount, 1);
assert.deepEqual(result.lessons, [{ departmentId: 1 }]);
assert.deepEqual(result.failedDepartments, [{ id: 2, name: 'Математика' }]);
assert.equal('reason' in result.failedDepartments[0], false);
});
test('отказ всех запросов означает, что проверка не выполнена', async () => {
const result = await loadDepartmentSchedules(
[{ id: 1 }, { id: 2 }],
async () => { throw new Error('тестовый отказ'); }
);
assert.equal(result.state, CONFLICT_CHECK_STATE.NOT_RUN);
assert.equal(result.reason, CONFLICT_CHECK_REASON.ALL_REQUESTS_FAILED);
assert.equal(result.checkedDepartmentCount, 0);
assert.deepEqual(result.lessons, []);
});
test('отсутствие кафедр не изображается как зелёная успешная проверка', async () => {
const result = await loadDepartmentSchedules([], async () => []);
assert.equal(result.state, CONFLICT_CHECK_STATE.NOT_RUN);
assert.equal(result.reason, CONFLICT_CHECK_REASON.NO_DEPARTMENTS);
});
test('зелёная карточка разрешена только для полной проверки без конфликтов', () => {
const complete = {
state: CONFLICT_CHECK_STATE.COMPLETE,
checkedDepartmentCount: 2,
totalDepartmentCount: 2
};
const range = { startDate: '2026-06-29', endDate: '2026-07-05' };
assert.equal(conflictCheckPresentation(complete, 0, range).tone, 'success');
assert.equal(conflictCheckPresentation(complete, 1, range), null);
});
test('некорректный контракт результата не может породить зелёный статус', () => {
const range = { startDate: '2026-06-29', endDate: '2026-07-05' };
assert.throws(
() => conflictCheckPresentation({
state: CONFLICT_CHECK_STATE.COMPLETE,
checkedDepartmentCount: 1,
totalDepartmentCount: 2
}, 0, range),
/Полная проверка должна охватывать все кафедры/
);
assert.throws(
() => conflictCheckPresentation({
state: CONFLICT_CHECK_STATE.COMPLETE,
checkedDepartmentCount: 2,
totalDepartmentCount: 2
}, Number.NaN, range),
/Количество конфликтов должно быть целым неотрицательным числом/
);
});
test('частичная проверка без конфликтов остаётся предупреждением', () => {
const presentation = conflictCheckPresentation({
state: CONFLICT_CHECK_STATE.PARTIAL,
checkedDepartmentCount: 1,
totalDepartmentCount: 2
}, 0, { startDate: '2026-06-29', endDate: '2026-07-05' });
assert.equal(presentation.tone, 'warning');
assert.equal(presentation.title, 'Проверка выполнена частично');
assert.match(presentation.description, /во всём расписании нельзя/);
});
test('частичная проверка с конфликтами предупреждает о неполноте результата', () => {
const presentation = conflictCheckPresentation({
state: CONFLICT_CHECK_STATE.PARTIAL,
checkedDepartmentCount: 1,
totalDepartmentCount: 3
}, 2, { startDate: '2026-06-29', endDate: '2026-07-05' });
assert.equal(presentation.tone, 'warning');
assert.match(presentation.description, /Показаны найденные конфликты/);
});
test('полный отказ формирует явное состояние «Проверка не выполнена»', () => {
const presentation = conflictCheckPresentation({
state: CONFLICT_CHECK_STATE.NOT_RUN,
reason: CONFLICT_CHECK_REASON.ALL_REQUESTS_FAILED,
checkedDepartmentCount: 0,
totalDepartmentCount: 2
}, 0, { startDate: '2026-06-29', endDate: '2026-07-05' });
assert.equal(presentation.tone, 'error');
assert.equal(presentation.title, 'Проверка не выполнена');
assert.match(presentation.description, /Подтвердить отсутствие конфликтов нельзя/);
});