import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test from 'node:test'; import { decisionOptions, parseDecisionOption, teacherAbsenceTeacherOptionsUrl } from '../admin/js/views/teacher-absences.js'; test('значение мастера преобразуется в payload точечного изменения', () => { assert.deepEqual(parseDecisionOption('REPLACE_TEACHER|17'), { resolution: 'REPLACE_TEACHER', newTeacherId: 17 }); assert.deepEqual(parseDecisionOption('MOVE_TIME|2026-09-21|4'), { resolution: 'MOVE_TIME', targetLessonDate: '2026-09-21', newTimeSlotId: 4 }); assert.deepEqual(parseDecisionOption('CANCEL'), { resolution: 'CANCEL' }); }); test('мастер показывает только реально полученные кандидаты и явное отклонение', () => { const options = decisionOptions({ teacherCandidates: [{ id: 7, name: 'Петров П. П.' }], moveCandidates: [{ targetDate: '2026-09-22', timeSlotId: 3, startTime: '10:40:00', endTime: '12:10:00' }], classroomCandidates: [{ id: 9, name: 'А-201' }], cancellationAvailable: true }); assert.deepEqual(options.map(item => item.value), [ 'REPLACE_TEACHER|7', 'MOVE_TIME|2026-09-22|3', 'CHANGE_CLASSROOM|9', 'CANCEL', 'REJECT' ]); }); test('поиск отсутствующего преподавателя не ограничивает учебный отдел его служебной кафедрой', () => { assert.equal( teacherAbsenceTeacherOptionsUrl({ query: 'Иванов', role: 'EDUCATION_OFFICE', departmentId: 5 }), '/api/users/teachers/options?query=%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2&limit=30' ); assert.equal( teacherAbsenceTeacherOptionsUrl({ query: 'Петров', selectedId: 17, role: 'DEPARTMENT', departmentId: 5 }), '/api/users/teachers/options?query=%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D0%B2&limit=30&departmentId=5&selectedId=17' ); }); test('список преподавателей раскрывается поверх следующей карточки', async () => { const styles = await readFile(new URL('../admin/css/teacher-absences.css', import.meta.url), 'utf8'); assert.match(styles, /\.absence-create-card\s*\{[^}]*z-index:\s*20[^}]*overflow:\s*visible/s); assert.match(styles, /\.absence-create-card:focus-within\s*\{[^}]*z-index:\s*30/s); }); test('вкладка отсутствий доступна ответственным ролям и подключена к SPA', async () => { const [capabilities, main, index] = await Promise.all([ readFile(new URL('../admin/js/role-capabilities.js', import.meta.url), 'utf8'), readFile(new URL('../admin/js/main.js', import.meta.url), 'utf8'), readFile(new URL('../admin/index.html', import.meta.url), 'utf8') ]); assert.match(capabilities, /ADMIN:[\s\S]*teacher-absences/); assert.match(capabilities, /EDUCATION_OFFICE:[\s\S]*teacher-absences/); assert.match(capabilities, /DEPARTMENT:[\s\S]*teacher-absences/); assert.match(main, /'teacher-absences':[\s\S]*teacher-absences\.js/); assert.match(index, /data-tab="teacher-absences"/); });