Files
bedolaga-cabinet/src/utils/nodeVersion.test.ts
c0mrade b4e1de6152 feat(remnawave): GeoCheck ноды в админке — запуск проверки и просмотр отчёта
Кнопка в карточке ноды открывает модалку: выбор маршрута (по умолчанию /
IP-адрес / интерфейс) с подсказками из данных ноды, ожидание, затем отчёт
картинкой либо тем же отчётом в JSON. Есть копирование JSON, скачивание
SVG, повтор проверки и полноэкранный режим.

Кнопка показывается только для узлов 3.3.0+ (versions.node) и только для
подключённых — иначе админ упирался бы в ошибку панели.

Отчёт вставляется как <img src="data:...">, а не сырым SVG в разметку: он
несёт встроенный моноширинный шрифт и <style>, на которых держится
выравнивание колонок, и санитайзер их выбрасывает. В <img> SVG рисуется в
изолированном контексте без скриптов и внешних запросов — и безопаснее, и
вернее по виду.

Зум и панорамирование — react-zoom-pan-pinch с той же конфигурацией, что в
самой панели Remnawave. Своя реализация обязательна: index.html задаёт
user-scalable=no, поэтому браузерного пинча нет ни в мобильном вебе, ни в
Mini App. Колесо намеренно не масштабирует, иначе прокрутка над отчётом
превращается в зум.

В отличие от панели стартовый масштаб считается от читаемой ширины: на
телефоне «вписано по ширине» превращает отчёт в серую рябь. На 390px это
2.42x с панорамированием, на десктопе — 1x. При смене ширины (полный
экран, поворот) масштаб пересчитывается.

Опрос задачи с потолком в три минуты — иначе забытая открытой модалка
опрашивала бы панель бесконечно. Пока проверка идёт, модалка не
закрывается: задача уже поставлена, терять её результат молча хуже.

Заодно в AdminRemnawave.tsx осели автоправки biome (import type,
Math.pow -> **) — файл всё равно правился, они механические.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 16:01:05 +03:00

53 lines
1.7 KiB
TypeScript
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 { describe, expect, it } from 'vitest';
import { GEOCHECK_MIN_NODE_VERSION, isVersionAtLeast, supportsGeoCheck } from './nodeVersion';
describe('isVersionAtLeast', () => {
it.each([
['3.3.0', true],
['3.3.1', true],
['3.4.0', true],
['4.0.0', true],
['v3.3.0', true],
['3.3', true],
['3.2.9', false],
['3.2.99', false],
['2.9.9', false],
['3', false],
])('%s vs 3.3.0 -> %s', (value, expected) => {
expect(isVersionAtLeast(value, '3.3.0')).toBe(expected);
});
it('сравнивает числа, а не строки: 3.10.0 новее 3.9.0', () => {
expect(isVersionAtLeast('3.10.0', '3.9.0')).toBe(true);
});
it('пререлиз целевой версии считается достаточным — фича там уже есть', () => {
expect(isVersionAtLeast('3.3.0-rc.1', '3.3.0')).toBe(true);
});
it.each([
undefined,
null,
'',
'unknown',
'dev',
])('нераспознанное значение %s -> false', (value) => {
expect(isVersionAtLeast(value, '3.3.0')).toBe(false);
});
});
describe('supportsGeoCheck', () => {
it('смотрит именно на версию узла, а не xray', () => {
expect(supportsGeoCheck({ node: '3.3.0' })).toBe(true);
expect(supportsGeoCheck({ node: '3.2.0' })).toBe(false);
});
it.each([undefined, null, {}])('без версии узла — false (%s)', (versions) => {
expect(supportsGeoCheck(versions as { node?: string } | null | undefined)).toBe(false);
});
it('порог совпадает с задокументированным минимумом', () => {
expect(supportsGeoCheck({ node: GEOCHECK_MIN_NODE_VERSION })).toBe(true);
});
});