import { test, expect, type Page } from '@playwright/test' async function setup(page: Page) { const control = { holdRange: '', failList: false, release: () => {} } const gate = new Promise(resolve => { control.release = resolve }) const server = { id: '1', name: 'Первый сервер', site: 'TEST', country: 'RU', status: 'online', rxNow: 2, txNow: 3, rxPeak: 5, txPeak: 6, rxTotal: 100, txTotal: 200, sessions: 1, rxSeries: [1, 2], txSeries: [2, 3] } await page.route('**/health', route => route.fulfill({ json: { ok: true } })) await page.route('**/api/**', async route => { const url = new URL(route.request().url()), path = url.pathname if (path.endsWith('/live')) return route.fulfill({ status: 503, json: {} }) if (path === '/api/traffic/servers/1') { const range = url.searchParams.get('range'), iface = url.searchParams.get('iface') return route.fulfill({ json: { server: { ...server, name: `Детали ${range} ${iface}`, rxNow: range === '24h' ? 24 : 15 } } }) } if (path === '/api/traffic/servers') { const range = url.searchParams.get('range') if (control.holdRange === range) await gate if (control.failList) return route.fulfill({ status: 500, json: { error: 'Сводка временно недоступна' } }) return route.fulfill({ json: { servers: [{ ...server, name: 'Список ' + range }] } }) } const json = path === '/api/auth/config' ? { required: false } : path === '/api/traffic/servers' ? { servers: [server] } : path === '/api/traffic/servers/1/interfaces' ? { interfaces: [{ name: 'ether2', running: true, disabled: false, rxNow: 0, txNow: 0 }] } : path.endsWith('/interfaces') || path === '/api/traffic/bound-interfaces' ? { interfaces: [] } : path === '/api/traffic/users' ? { users: [] } : path === '/api/servers' ? [] : {} await route.fulfill({ json }) }) await page.goto('/traffic') await expect(page.getByRole('heading', { name: 'Детали 1h __all__', exact: true })).toBeVisible() return control } test('Список трафика: поздний период не заменяет текущий', async ({ page }) => { const control = await setup(page) control.holdRange = '24h' const started = page.waitForRequest(r => new URL(r.url()).pathname === '/api/traffic/servers' && r.url().includes('range=24h')) await page.getByRole('button', { name: '24ч', exact: true }).click() await started await expect(page.getByText('Загрузка списка трафика…', { exact: true })).toBeVisible() await expect(page.getByRole('button').filter({ hasText: 'Список 1h' })).toHaveCount(0) await page.getByRole('button', { name: '15м', exact: true }).click() await expect(page.getByRole('button').filter({ hasText: 'Список 15m' })).toBeVisible() const late = page.waitForResponse(r => new URL(r.url()).pathname === '/api/traffic/servers' && r.url().includes('range=24h')) control.release() await late await expect(page.getByRole('button').filter({ hasText: 'Список 15m' })).toBeVisible() await expect(page.getByRole('button').filter({ hasText: 'Список 24h' })).toHaveCount(0) }) test('Список трафика: ошибка обновления скрывает сводку; повтор восстанавливает список', async ({ page }) => { const control = await setup(page) control.failList = true await page.getByRole('button', { name: 'Обновить', exact: true }).click() await expect(page.getByRole('alert').filter({ hasText: 'Список трафика недоступен' })).toContainText('Сводка временно недоступна') await expect(page.getByLabel('Сводка трафика')).toHaveCount(0) await expect(page.getByRole('button').filter({ hasText: 'Список 1h' })).toHaveCount(0) control.failList = false await page.getByRole('button', { name: 'Повторить загрузку списка', exact: true }).click() await expect(page.getByRole('button').filter({ hasText: 'Список 1h' })).toBeVisible() await expect(page.getByLabel('Сводка трафика')).toBeVisible() })