fix(ui): отличать неизвестные flow-метрики от нулевых

This commit is contained in:
Denozordec committed 2026-09-24 10:02:50 +07:00
1 parent a03909e504
commit 7c6f937cec
3 files changed
+37 -6

No files matched your search

+23 -2
View File
@@ -1,7 +1,7 @@
import { test, expect, type Page } from '@playwright/test'
async function setup(page: Page) {
const control = { hold: '', fail: false, failList: false, invalidSample: undefined as unknown, mergeSample: false, release: () => {} }
const control = { hold: '', fail: false, failList: false, invalidSample: undefined as unknown, mergeSample: false, metrics: {} as Record<string, unknown>, release: () => {} }
const gate = new Promise<void>(resolve => { control.release = resolve })
const card = { id: '1', name: 'Экспортёр тест', subtitle: '', site: 'TEST', country: 'RU', status: 'online', rxNow: 2, txNow: 3, sessions: 1, rxSeries: [1, 2], txSeries: [2, 3], bytes: 200 }
const data = { bpsNow: 1000000, bytes: 200, packets: 2, conversations: 1, uniqueSrc: 1, uniqueDst: 1, topProto: 'TCP', rxSeries: [1], txSeries: [2], applications: [], protocols: [], sources: [], destinations: [], interfaces: [], conversationsList: [], ifaces: [], live: false }
@@ -12,7 +12,7 @@ async function setup(page: Page) {
if (path === '/api/traffic/flow/analytics') {
if (control.hold === range) await gate
if (control.fail) return route.fulfill({ status: 500, json: { error: 'Срез временно недоступен' } })
return route.fulfill({ json: { ...data, topCategory: 'Категория ' + range } })
return route.fulfill({ json: { ...data, ...control.metrics, topCategory: 'Категория ' + range } })
}
if (path === '/api/traffic/flow/live') return route.fulfill({ contentType: 'text/event-stream', body: 'event: sample\ndata: ' + JSON.stringify({ ...data, live: true }) + '\n\n' + (control.invalidSample === undefined ? '' : 'event: sample\ndata: ' + JSON.stringify(control.mergeSample ? { ...data, ...(control.invalidSample as object) } : control.invalidSample) + '\n\n') })
if (path === '/api/traffic/flow/exporters' && control.failList) return route.fulfill({ status: 403, json: { error: 'Нет доступа к экспортёрам' } })
@@ -145,3 +145,24 @@ for (const [name, invalid, merge] of [
await expect(page.getByText('live', { exact: true })).toHaveCount(0)
})
}
for (const [name, metrics, rate, bytes] of [
['отсутствующие', {}, 'Нет данных', 'Нет данных'],
['нулевые', { bpsOverlay: 0, bpsWire: 0, bytesMesh: 0, bytesOverlay: 0 }, '0 Кбит/с', '0 Б'],
['положительные', { bpsOverlay: 2000000, bpsWire: 2000000, bytesMesh: 1500, bytesOverlay: 1500 }, '2.00 Мбит/с', '1.5 КБ'],
['некорректные REST', { bpsOverlay: -1, bpsWire: null, bytesMesh: -1 }, 'Нет данных', 'Нет данных'],
] as const) {
test('Flow: optional-метрики — ' + name, async ({ page }) => {
const control = await setup(page)
control.metrics = metrics
await page.getByRole('button', { name: '15м', exact: true }).click()
await page.getByRole('switch', { name: 'Без mesh', exact: true }).click()
const grid = page.getByLabel('Скорость потоков')
const card = (label: string) => grid.locator('[data-slot="frame-panel"]').filter({ has: page.getByText(label, { exact: true }) })
await expect(card('JH↔EN overlay')).toContainText(rate)
await expect(card('Wire GRE')).toContainText(rate)
await expect(card('Mesh')).toContainText(bytes)
if (name === 'нулевые') await expect(card('JH↔EN overlay')).toContainText('0 Б')
})
}