fix(traffic): проверять live-срез и прекращать опрос выключенных устройств

This commit is contained in:
Denozordec committed 2026-10-12 21:35:55 +07:00
1 parent 1275dd7b9b
commit 2358ecef60
29 files changed
+1620 -114

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
import { test, expect, type Page } from "@playwright/test"
import { observedTrafficFixturePayload } from "./traffic-observation-fixture"
async function setup(page: Page, terminal = true) {
const control = { calls: 0, release: () => {} }
const gate = new Promise<void>(resolve => { control.release = resolve })
const server = { id:"1",name:"CHR live",site:"TEST",country:"RU",status:"online",rxNow:2,txNow:3,rxPeak:4,txPeak:5,rxTotal:1,txTotal:2,sessions:1,rxSeries:[1,2],txSeries:[2,3] }
await page.route("**/health",r=>r.fulfill({json:{ok:true}}))
await page.route("**/api/**",async r=>{
const path=new URL(r.request().url()).pathname
if(path.endsWith("/live")) {
control.calls++
if(control.calls>1) await gate
const sample={rxMbps:control.calls===1?17:0,txMbps:0,at:"2026-10-12T12:00:00Z",timestampKind:"backend-receipt"}
const end=terminal&&control.calls===1?'event: error\ndata: '+JSON.stringify({error:"Устройство выключено. Live-поток остановлен"})+'\n\n':''
return r.fulfill({contentType:"text/event-stream",body:'event: sample\ndata: '+JSON.stringify(sample)+'\n\n'+end})
}
return r.fulfill({json:observedTrafficFixturePayload(path==="/api/auth/config"?{required:false}:path==="/api/traffic/servers"?{servers:[server]}:path==="/api/traffic/servers/1"?{server}:path.endsWith("/interfaces")||path==="/api/traffic/bound-interfaces"?{interfaces:[]}:path==="/api/traffic/users"?{users:[]}:path==="/api/servers"?[]:{})})
})
await page.goto("/traffic")
await expect(page.getByRole("heading",{name:"CHR live",exact:true})).toBeVisible()
return control
}
for(const width of [1440,320])test(`Причина закрытия live сохранена, переподключение сохраняет последнее значение ${width}`,async({page})=>{
await page.setViewportSize({width,height:1000});const c=await setup(page)
const status=page.getByRole("status").filter({hasText:"Live-поток: нет свежих данных"})
await expect(status).toContainText("Устройство выключено")
await expect(status).not.toContainText("Поток live завершён")
await expect(page.getByLabel("Скорость выбранного сервера")).toContainText("17.0")
await expect(page.getByLabel("Последнее измерение сервера")).toContainText("ответ RouterOS получен приложением")
await status.scrollIntoViewIfNeeded()
await status.evaluate(el => { let parent=el.parentElement;while(parent&&(!/auto|scroll/.test(getComputedStyle(parent).overflowY)||parent.scrollHeight<=parent.clientHeight))parent=parent.parentElement;if(parent)parent.scrollTop+=el.getBoundingClientRect().top-parent.getBoundingClientRect().top-24 })
await page.screenshot({path:`docs/ux-ui/screens/traffic-live-error-${width}-2026-10-12.png`,fullPage:true})
await page.getByRole("button",{name:"Переподключить live",exact:true}).click()
await expect.poll(()=>c.calls).toBe(2)
await expect(page.getByRole("status").filter({hasText:"Подключение live-потока"})).toBeVisible()
await expect(page.getByLabel("Скорость выбранного сервера")).toContainText("17.0")
c.release();await expect(page.getByLabel("Скорость выбранного сервера")).not.toContainText("17.0")
await expect(page.getByLabel("Скорость выбранного сервера").getByText("0 Кбит/с",{exact:true})).toHaveCount(2)
expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth+1)).toBe(true)
})
+1 -1
View File
@@ -62,7 +62,7 @@ for (const variant of ['closed', 'invalid', 'http-error', 'silent', 'awaiting']
await expect(page.getByLabel('Последнее измерение сервера')).toHaveCount(0)
return
}
const hint = variant === 'http-error' ? 'История · live недоступен' : 'Последнее live-измерение · поток недоступен'
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())