diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index cca17fb8..7d0ae69e 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -21,7 +21,7 @@ | 4 | Остальные таблицы, удаление старых API, общая регрессия | Завершён 2026-09-20; границы приёмки ниже | | 5 | Состояния данных, свежесть, частичные сбои, гонки polling | Завершён 2026-09-20 для дашборда; границы проверок ниже | | 6 | Навигация и дашборд | Завершён 2026-09-20 в границах локальной приёмки; ограничения ниже | -| 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | В работе: 7.1–7.2, права серверов и ограничения действий мониторинга выполнены; формы проб сохраняются после API; переключатели подтверждаются API; удаление и звезда подтверждаются API; Speed-test блокирует запись; Ping сериализован с записью; вкладка и Ping-фильтры в URL; Resources-фильтры в URL; далее приёмка 7.5 | +| 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | Завершён в границах локальной приёмки 2026-09-23; внешние ограничения ниже | | 8 | Трафик и статистика | Не начат | | 9 | VPN, Firewall и Filters | Не начат | | 10 | Маршрутизация, диагностика, карта и терминал | Не начат | @@ -29,6 +29,14 @@ | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат | +## Завершение этапа 7 — локальная приёмка (2026-09-23) + +- 94 профильных E2E dashboard-data/servers/uptime-links прошли. Включены сквозные сценарии сервера и Ping-проверки из очереди дашборда, права, ошибки/повторы операций, URL-контекст, формы и адаптивность. Сценарий Ping с действием и возвратом уже существует в uptime-links.spec.ts («очередь проверок…»); ранее он ошибочно оставался в списке следующих шагов журнала. +- Отдельная конфигурация playwright.backend.config.ts запускает только backend-switch.e2e.ts с NEXT_PUBLIC_BACKEND_URL=local. Оба теста прошли: задержанный Ping прежнего backend с 200/500, смена адреса через настройки, возврат к данным нового источника и следующий POST только новому адресу. Обычная конфигурация по-прежнему использует same-origin. Все HTTP-ответы подменены, реальные сетевые операции не выполнялись. +- ESLint новых тестов/конфигурации и TypeScript прошли. Последняя production-сборка приложения ca9474a успешна; после неё до завершения этапа 7 менялись только тесты/документы. Известный lint uptime (1 ошибка/6 предупреждений) остаётся. +- Границы: смена режима/backend проверена через настройки с размонтированием страницы, не через изменение контекста в смонтированной форме. Реальные JWT/RouterOS, длительные bandwidth-test, отмена выполняющейся сетевой операции, конкуренция разных пользователей/вкладок и полноценный экспорт серверов не подтверждены/не реализованы; ограничения из блоков 7.4 сохраняются. Общая приёмка доступности всех экранов — этап 12. +- Следующий этап 8: трафик и статистика, начиная с привязки данных к выбранному периоду/срезу и разделения ошибок и пустых ответов. Коммит этапа 7 локальный, без push. + ## Приёмка 7.5Д — смена режима при незавершённом Ping (2026-09-23) - Новый E2E удерживает POST collect-group, открывает настройки обычной ссылкой, переключает «Живые» на «Моковые», возвращается назад и получает поздний 500 старого запроса. Проверено отсутствие старой ошибки и доступность создания пробы в новом режиме. Тест прошёл; код приложения не менялся. Сценарий включает размонтирование страницы, не доказывает смену контекста без размонтирования. diff --git a/docs/ux-ui-stage-7.md b/docs/ux-ui-stage-7.md index f597801b..5d8e4219 100644 --- a/docs/ux-ui-stage-7.md +++ b/docs/ux-ui-stage-7.md @@ -61,7 +61,7 @@ URL — источник сохранённого состояния. Back/Forwa 3. **7.4 — формы, детали и полный контекст мониторинга.** Восстановление вкладки/фильтров из URL, понятные единицы и подписи, возврат к списку после действия. Не дублировать сохранённые исправления этапа 1; проверить загрузку, отмену, 400/403/500, timeout и повторное нажатие. 4. **7.5 — приёмка этапа.** Сценарий «проблема → сервер/проверка → действие → возврат» с сохранением контекста; профильные E2E, права в HTTP-моках, TypeScript, lint и build. Реальные JWT/RouterOS отдельно в тестовом окружении. -Следующий исполняемый шаг: 7.5 — смена backend/mode при незавершённой операции мониторинга, сквозной сценарий проверки из дашборда и фиксация ограничений. Сквозной сценарий сервера с отказом 403, повтором и Back/Forward проверен; навигация не отправляет запросы записи. Формы серверов проверены на 320/390/1440 px, Resources после прокрутки — на 320/390 px; исправлены переполнение формы и обрезка фильтров/таблицы. Формы Ping/Speed и вкладки проверены на 320/390/1440 px; устранены переполнение форм, перекрытие параметров Speed и сдвиг страницы при выборе вкладки. URL-контекст вкладки, Ping и Resources выполнен. Учесть границы HTTP-моков, экспорт серверов и ограничения сетевых операций из журнала; этап 7 целиком пока не завершён. +Локальная приёмка этапа 7 завершена 2026-09-23: 94 профильных E2E и 2 проверки смены backend. Полные границы и внешние ограничения — в docs/ux-ui-progress.md. Следующий этап — 8, трафик и статистика. ## Решение по синхронизации URL (7.1) diff --git a/playwright.backend.config.ts b/playwright.backend.config.ts new file mode 100644 index 00000000..89aceded --- /dev/null +++ b/playwright.backend.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from '@playwright/test' +import base from './playwright.config' + +const server = base.webServer +if (!server || Array.isArray(server)) throw new Error('Ожидается один frontend сервер') + +export default defineConfig({ + ...base, + testMatch: '**/backend-switch.e2e.ts', + webServer: { + ...server, + env: { ...server.env, NEXT_PUBLIC_BACKEND_URL: 'local' }, + }, +}) diff --git a/tests/e2e/backend-switch.e2e.ts b/tests/e2e/backend-switch.e2e.ts new file mode 100644 index 00000000..2cf758dc --- /dev/null +++ b/tests/e2e/backend-switch.e2e.ts @@ -0,0 +1,56 @@ +import { test, expect } from '@playwright/test' + +// This file runs only via playwright.backend.config.ts; ordinary E2E lock the backend URL. +for (const status of [200, 500]) { + test(`смена backend: поздний Ping ${status} не меняет новый источник`, async ({ page }) => { + let release!: () => void + const pending = new Promise(resolve => { release = resolve }) + const posts: string[] = [] + await page.route('**/health', route => route.fulfill({ json: { ok: true } })) + await page.route('**/api/**', async route => { + const request = route.request() + const url = new URL(request.url()) + const isNew = url.port === '8999' + if (request.method() === 'POST') { + posts.push(url.origin + url.pathname) + if (!isNew && url.pathname === '/api/uptime/probes/collect-group') { + await pending + return route.fulfill({ status, json: status === 200 ? {} : { error: 'Ошибка прежнего backend' } }) + } + } + const servers = [{ id: 1, name: isNew ? 'Новый источник' : 'Старый источник', host: '192.0.2.1', type: 'exit-node', enabled: true, country: 'RU', site: 'TEST', status: 'online', wanUplinks: [] }] + const probes = [{ id: 'p1', srcServerId: '1', name: isNew ? 'Новая проверка' : 'Старая проверка', target: '192.0.2.10', filter: 'main', rtt: 10, loss: 0, status: 'up', series: [10], enabled: true }] + const json = url.pathname === '/api/auth/config' ? { required: false } + : url.pathname === '/api/servers' ? servers + : url.pathname === '/api/uptime/overview' ? { probes, resources: [] } + : url.pathname === '/api/uptime/speed-probes' ? { probes: [] } + : url.pathname === '/api/uptime/speed-test/runs' ? { runs: [] } + : url.pathname === '/api/evobgp/settings' ? { enabled: false } + : {} + await route.fulfill({ json }) + }) + await page.goto('/uptime?probe=p1') + const context = page.getByRole('status', { name: 'Проверка по ссылке' }) + await expect(context).toContainText('Старая проверка') + const started = page.waitForRequest(r => r.url().endsWith('/collect-group')) + await page.getByRole('button', { name: 'Обновить', exact: true }).click() + await started + await page.locator('a[href="/settings"]').first().click() + const backend = page.getByPlaceholder('http://localhost:8000', { exact: true }) + await backend.fill('http://127.0.0.1:8999') + await backend.press('Enter') + await page.goBack() + await expect(context).toContainText('Новая проверка') + const response = page.waitForResponse(r => r.url().includes(':8000/') && r.url().endsWith('/collect-group')) + release() + await response + await expect(context).toContainText('Новая проверка') + await expect(page.getByText('Ошибка прежнего backend', { exact: true })).toHaveCount(0) + await page.getByRole('button', { name: 'Обновить', exact: true }).click() + await expect.poll(() => posts).toEqual([ + 'http://localhost:8000/api/uptime/probes/collect-group', + 'http://127.0.0.1:8999/api/uptime/probes/collect-group', + ]) + await expect(page.getByRole('button', { name: 'Новая проба', exact: true })).toBeEnabled() + }) +}