import { observedTrafficFixturePayload } from "./traffic-observation-fixture" import { installOpenLiveStream, resumeLiveStream, sendLiveHeartbeat } from "./live-stream-fixture" import { test, expect } from '@playwright/test' for (const variant of ['closed', 'invalid', 'http-error', 'silent', 'awaiting'] as const) { test(`Трафик: SSE ${variant} не выдаёт старое измерение за live`, async ({ page }) => { 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: observedTrafficFixturePayload({ ok: true }) })) await page.route('**/api/**', route => { const url = new URL(route.request().url()) const path = url.pathname if (path.endsWith('/live')) { if (variant === 'http-error' || url.searchParams.get('iface') === 'ether2') return route.fulfill({ status: 503, json: observedTrafficFixturePayload({ error: 'Поток недоступен' }) }) const sample = { rxMbps: 17, txMbps: 19, at: '2026-09-23T12:00:00Z' } const body = 'event: sample\ndata: ' + JSON.stringify(sample) + '\n\n' + (variant === 'invalid' ? 'event: sample\ndata: {"rxMbps":null,"txMbps":-1}\n\n' : '') return route.fulfill({ contentType: 'text/event-stream', body }) } const json = path === '/api/auth/config' ? { required: false } : path === '/api/traffic/servers' ? { servers: [server] } : path === '/api/traffic/servers/1' ? { 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' ? [] : {} return route.fulfill({ json: observedTrafficFixturePayload(json) }) }) if (variant === 'silent' || variant === 'awaiting') await installOpenLiveStream(page, '/api/traffic/servers/1/live', { rxMbps: 17, txMbps: 19, at: '2026-09-23T12:00:00Z' }, variant !== 'awaiting') const received = new Date('2026-09-28T06:00:00Z') await page.clock.setFixedTime(received) await page.goto('/traffic') const summary = page.getByLabel('Скорость выбранного сервера') await expect(summary).toBeVisible() if (variant === 'awaiting') { const measurement = page.getByLabel('Последнее измерение сервера') await expect(summary.getByText('История · ожидание live', { exact: true }).filter({ visible: true })).toHaveCount(2) await expect(measurement).toHaveCount(0) await expect(summary).not.toContainText('17.0') await page.clock.fastForward(10_000) await sendLiveHeartbeat(page) await page.clock.fastForward(5_001) await expect(summary.getByText('История · live недоступен', { exact: true }).filter({ visible: true })).toHaveCount(2) await expect(measurement).toHaveCount(0) await resumeLiveStream(page) await expect(summary.getByText('live', { exact: true }).filter({ visible: true })).toHaveCount(2) await expect(summary).toContainText('17.0') await expect(measurement).toBeVisible() return } if (variant === 'silent') { await expect(summary.getByText('live', { exact: true }).filter({ visible: true })).toHaveCount(2) const stamp = await page.getByLabel('Последнее измерение сервера').locator('time').first().getAttribute('datetime') await page.clock.fastForward(10_000) await sendLiveHeartbeat(page) await page.clock.fastForward(5_001) await expect(summary.getByText('live', { exact: true })).toHaveCount(0) await expect(summary).toContainText('17.0') await expect(page.getByLabel('Последнее измерение сервера').locator('time').first()).toHaveAttribute('datetime', stamp!) await resumeLiveStream(page) await expect(summary.getByText('live', { exact: true }).filter({ visible: true })).toHaveCount(2) await page.getByRole('group', { name: 'Разделы трафика' }).getByRole('button', { name: 'Клиенты', exact: true }).click() await page.clock.fastForward(15_001) await expect(page.getByLabel('Последнее измерение сервера')).toHaveCount(0) return } const hint = variant === 'http-error' ? 'История · live недоступен' : 'Последнее live' await expect(summary.getByText(hint, { exact: true }).filter({ visible: true })).toHaveCount(2) await expect(summary.getByText('live', { exact: true })).toHaveCount(0) await expect(page.getByLabel('Получение истории сервера').locator('time')).toHaveAttribute('datetime', received.toISOString()) const measurement = page.getByLabel('Последнее измерение сервера') if (variant === 'http-error') await expect(measurement).toHaveCount(0) if (variant !== 'http-error') { await expect(measurement.locator('time').nth(0)).toHaveAttribute('datetime', received.toISOString()) await expect(measurement).toContainText('метка сервера:') await expect(measurement.locator('time').nth(1)).toHaveAttribute('datetime', '2026-09-23T12:00:00Z') await page.clock.setFixedTime(new Date('2026-09-28T06:05:00Z')) await expect(measurement.locator('time').nth(0)).toHaveAttribute('datetime', received.toISOString()) await expect(summary).toContainText('17.0') await expect(summary).toContainText('19.0') if (variant === 'closed') { await page.getByRole('button', { name: 'ether2', exact: true }).click() await expect(summary.getByText('История · live недоступен', { exact: true }).filter({ visible: true })).toHaveCount(2) await expect(measurement).toHaveCount(0) await expect(summary).not.toContainText('17.0') } } }) }