Files
magistr/frontend/tests/admin-ui-regressions.test.mjs

107 lines
5.6 KiB
JavaScript
Raw Permalink 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 assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
import { scheduleSlotActionLabel } from '../admin/js/views/schedule.js';
const readFrontendFile = relativePath => readFile(
new URL(`../${relativePath}`, import.meta.url),
'utf8'
);
test('одиночный слот очищается, а несколько слотов удаляются', () => {
assert.equal(scheduleSlotActionLabel(1), 'Очистить');
assert.equal(scheduleSlotActionLabel(2), 'Удалить');
assert.equal(scheduleSlotActionLabel(5), 'Удалить');
});
test('в общих заголовках админ-панели и настроек нет бургер-меню', async () => {
const files = await Promise.all([
readFrontendFile('admin/index.html'),
readFrontendFile('admin/js/main.js'),
readFrontendFile('admin/settings/index.html'),
readFrontendFile('admin/settings/js/main.js')
]);
files.forEach(content => assert.doesNotMatch(content, /menu-toggle/));
});
test('заголовок вкладки соответствует конструктору правил', async () => {
const mainScript = await readFrontendFile('admin/js/main.js');
assert.match(mainScript, /schedule:\s*\{\s*title:\s*'Конструктор правил'/);
});
test('основная кнопка показа находится в заголовке блока параметров', async () => {
const scheduleView = await readFrontendFile('admin/views/schedule-view.html');
const controlHeaderIndex = scheduleView.indexOf('schedule-view-control-header');
const controlGridIndex = scheduleView.indexOf('schedule-view-control-grid');
const loadButtonIndex = scheduleView.indexOf('id="schedule-view-load"');
assert.ok(controlHeaderIndex >= 0);
assert.ok(loadButtonIndex > controlHeaderIndex);
assert.ok(loadButtonIndex < controlGridIndex);
assert.equal(scheduleView.match(/id="schedule-view-load"/g)?.length, 1);
});
test('пустое состояние расписания содержит собственную кнопку обновления', async () => {
const scheduleScript = await readFrontendFile('admin/js/views/schedule-view.js');
assert.match(scheduleScript, /SCHEDULE_REFRESH_PROMPT\s*=\s*'Нажмите «Показать», чтобы обновить расписание'/);
assert.match(scheduleScript, /data-schedule-view-reload/);
assert.match(scheduleScript, /closest\('\[data-schedule-view-reload\]'\)[\s\S]*?loadData\(\)/);
assert.match(scheduleScript, /setTableState\(message,\s*message === SCHEDULE_REFRESH_PROMPT\)/);
});
test('действия слотов имеют размер соседнего поля', async () => {
const [components, scheduleScript] = await Promise.all([
readFrontendFile('admin/css/components.css'),
readFrontendFile('admin/js/views/schedule.js')
]);
assert.match(components, /\.schedule-slot-remove\s*\{[^}]*min-width:\s*125px[^}]*min-height:\s*44px/s);
assert.match(scheduleScript, /class="btn btn-md \$\{actionClass\} schedule-slot-remove"/);
});
test('все варианты системных кнопок имеют видимую обводку', async () => {
const components = await readFrontendFile('admin/css/components.css');
assert.match(components, /\.btn\s*\{[^}]*border:\s*1px solid var\(--button-secondary-border\)/s);
assert.match(components, /\.btn-primary\s*\{[^}]*border-color:\s*var\(--button-primary-border\)/s);
assert.match(components, /\.btn-ghost\s*\{[^}]*border-color:\s*var\(--button-ghost-border\)/s);
assert.match(components, /\.btn-danger\s*\{[^}]*border-color:\s*var\(--button-danger-border\)/s);
});
test('подсказка календарной сетки получает позицию напрямую от курсора', async () => {
const calendarScript = await readFrontendFile('admin/js/views/academic-calendar.js');
assert.match(calendarScript, /translate3d\(\$\{left\}px, \$\{top\}px, 0\) scale\(1\)/);
assert.match(calendarScript, /\{ duration: 1, fill: 'forwards' \}/);
assert.doesNotMatch(calendarScript, /\.style\.(?:left|top)\s*=/);
});
test('светлая тема задаёт контрастные пункты и заголовки левого меню', async () => {
const [layout, index] = await Promise.all([
readFrontendFile('admin/css/layout.css'),
readFrontendFile('admin/index.html')
]);
assert.match(layout, /\[data-theme="light"\] \.sidebar \.nav-item\s*\{[^}]*color:\s*#334155/s);
assert.match(layout, /\[data-theme="light"\] \.sidebar-section-title\s*\{[^}]*color:\s*#64748b !important/s);
assert.match(index, />Расписание<\/div>/);
});
test('таблица календарных графиков не содержит отдельный столбец названия', async () => {
const [calendarView, calendarScript] = await Promise.all([
readFrontendFile('admin/views/academic-calendar.html'),
readFrontendFile('admin/js/views/academic-calendar.js')
]);
const bodyIndex = calendarView.indexOf('id="academic-calendars-tbody"');
const tableStart = calendarView.lastIndexOf('<table>', bodyIndex);
const tableEnd = calendarView.indexOf('</table>', bodyIndex);
const calendarTable = calendarView.slice(tableStart, tableEnd);
assert.doesNotMatch(calendarTable, /<th>Название<\/th>/);
assert.match(calendarTable, /colspan="6"/);
assert.doesNotMatch(calendarScript, /title:\s*buildCalendarTitleFromForm/);
});