Files
MikrotikManager/tests/e2e/uptime-speed-data.spec.ts
T

43 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from "@playwright/test"
import { server } from "./fixtures/users"
const run = { id:"history-1", srcServerId:"1", dstServerId:"2", srcInterface:"ether1", dstInterface:"ether1", protocol:"tcp", direction:"both", durationSec:10, txAvgMbps:42, rxAvgMbps:0, status:"done", error:null, createdAt:"2026-10-04T00:00:00Z" }
for (const resource of ["probes", "history"] as const) test("Скорость: initial unknown и независимое recovery/" + resource, async ({ page }) => {
let fail = true
await page.route("**/health",r=>r.fulfill({json:{ok:true}}))
await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname; const target=resource === "probes" ? "/api/uptime/speed-probes" : "/api/uptime/speed-test/runs";return r.fulfill(p === target && fail ? {status:503,json:{error:"Источник недоступен"}} : {json:p === "/api/auth/config" ? {required:false} : p === "/api/servers" ? [server] : p === "/api/uptime/overview" ? {probes:[],resources:[]} : p === "/api/uptime/speed-probes" ? {probes:[]} : p === "/api/uptime/speed-test/runs" ? {runs:[run]} : {}})})
await page.goto("/uptime?tab=speed"); await page.getByRole("button",{name:"Пауза",exact:true}).click()
const alert=page.getByRole("alert",{name:"Чтение скорости: "+resource,exact:true}); await expect(alert).toContainText("Данные пока неизвестны")
if(resource === "probes") { await expect(page.locator('tr[data-row-id="history-1"]')).toBeVisible(); await expect(page.getByText("Нет speed-проб",{exact:true})).toHaveCount(0) }
else { await expect(page.getByText("Нет speed-проб",{exact:true})).toBeVisible(); await expect(page.getByText("История тестов: данные пока неизвестны",{exact:true})).toBeVisible() }
fail=false; await page.getByRole("button",{name:"Обновить",exact:true}).click(); await expect(alert).toHaveCount(0); await expect(page.locator('tr[data-row-id="history-1"]')).toBeVisible()
})
test("Скорость: background503 и malformed сохраняют последнюю историю и свежесть", async ({page}) => {
let failure="",value=42
await page.route("**/health",r=>r.fulfill({json:{ok:true}})); await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname;return r.fulfill(p === "/api/uptime/speed-test/runs" && failure === "503" ? {status:503,json:{error:"История недоступна"}} : {json:p === "/api/auth/config" ? {required:false} : p === "/api/servers" ? [server] : p === "/api/uptime/overview" ? {probes:[],resources:[]} : p === "/api/uptime/speed-probes" ? {probes:[]} : p === "/api/uptime/speed-test/runs" ? failure === "malformed" ? {} : {runs:[{...run,txAvgMbps:value}]} : {}})})
await page.goto("/uptime?tab=speed"); const row=page.locator('tr[data-row-id="history-1"]'); await expect(row).toContainText("42 Мбит/с"); await page.getByRole("button",{name:"Пауза",exact:true}).click()
const freshness=page.getByRole("status").filter({hasText:/^История тестов: получено/}); const original=await freshness.textContent()
for(const kind of ["503","malformed"]) {failure=kind; await page.getByRole("button",{name:"Обновить",exact:true}).click(); await expect(page.getByRole("alert",{name:"Чтение скорости: history",exact:true})).toContainText("Последние данные сохранены"); await expect(row).toContainText("42 Мбит/с"); await expect(freshness).toHaveText(original!); await expect(page.getByText("Нет speed-проб",{exact:true})).toBeVisible()}
failure="";value=84;await page.getByRole("button",{name:"Обновить",exact:true}).click();await expect(row).toContainText("84 Мбит/с");await expect(page.getByRole("alert",{name:"Чтение скорости: history",exact:true})).toHaveCount(0)
})
test("Скорость: поздняя история не задерживает пробы и не заменяет новый ответ", async ({page}) => {
let release!:()=>void;const gate=new Promise<void>(r=>release=r);let historyCalls=0,newer=false
await page.route("**/health",r=>r.fulfill({json:{ok:true}}));await page.route("**/api/**",async r=>{const p=new URL(r.request().url()).pathname;if(p === "/api/uptime/speed-test/runs") {historyCalls++;const old=!newer;if(old) await gate;return r.fulfill({json:{runs:[{...run,id:old ? "stale" : "current"}]}}).catch(()=>{})}return r.fulfill({json:p === "/api/auth/config" ? {required:false} : p === "/api/servers" ? [server] : p === "/api/uptime/overview" ? {probes:[],resources:[]} : p === "/api/uptime/speed-probes" ? {probes:[]} : {}})})
await page.goto("/uptime?tab=speed");await page.getByRole("button",{name:"Пауза",exact:true}).click();await expect(page.getByText("Нет speed-проб",{exact:true})).toBeVisible();await expect(page.getByText("История тестов: данные пока неизвестны",{exact:true})).toBeVisible()
newer=true;await page.getByRole("button",{name:"Обновить",exact:true}).click();await expect(page.locator('tr[data-row-id="current"]')).toBeVisible();const late=page.waitForResponse(async response => response.url().endsWith("/api/uptime/speed-test/runs") && (await response.json()).runs[0].id === "stale");release();await (await late).finished();await page.evaluate(()=>new Promise<void>(resolve=>requestAnimationFrame(()=>requestAnimationFrame(()=>resolve()))));await expect.poll(()=>historyCalls).toBeGreaterThan(1);await expect(page.getByRole("button",{name:"Обновить",exact:true})).toBeEnabled();await expect(page.locator('tr[data-row-id="stale"]')).toHaveCount(0)
})
test("Скорость: null не становится нулём, malformed DTO сохраняет последний результат", async ({page}) => {
let entries:unknown[]=[{...run,txAvgMbps:null,rxAvgMbps:0}]
await page.route("**/health",r=>r.fulfill({json:{ok:true}}));await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname;return r.fulfill({json:p === "/api/auth/config" ? {required:false} : p === "/api/servers" ? [server] : p === "/api/uptime/overview" ? {probes:[],resources:[]} : p === "/api/uptime/speed-probes" ? {probes:[{id:"probe-1",srcServerId:"1",dstServerId:"2",srcInterface:"ether1",dstInterface:"ether1",protocol:"tcp",direction:"both",durationSec:"10",enabled:true,lastStatus:"done",lastRunAt:"2026-10-03T00:00:00Z",lastTxAvgMbps:999,lastRxAvgMbps:0}]} : p === "/api/uptime/speed-test/runs" ? {runs:entries} : {}})})
await page.goto("/uptime?tab=speed");await page.getByRole("button",{name:"Пауза",exact:true}).click();const row=page.locator('tr[data-row-id="history-1"]');await expect(row).toContainText("Неизвестно");await expect(row).toContainText("0 Мбит/с");await expect(page.getByText("999 Мбит/с",{exact:true})).toHaveCount(0)
await page.setViewportSize({width:320,height:1000});expect(await page.evaluate(()=>document.documentElement.scrollWidth <= innerWidth)).toBe(true)
await page.addStyleTag({content:"nextjs-portal{display:none!important}"});await page.screenshot({path:"docs/ux-ui/screens/speed-history-null-320.png",fullPage:true,animations:"disabled"})
const summary=page.locator('[aria-label="Сводка speed-проб"]');await expect(summary).toContainText("Макс TX");await expect(summary).toContainText("—");await expect(summary).toContainText("0 Мбит/с")
for(const bad of [{...run,status:"unknown"},{...run,txAvgMbps:-1},{...run,createdAt:"bad"},run]) {
entries=bad === run ? [run,run] : [bad];await page.getByRole("button",{name:"Обновить",exact:true}).click();await expect(page.getByRole("alert",{name:"Чтение скорости: history",exact:true})).toContainText("Некорректная история тестов скорости");await expect(row).toContainText("Неизвестно")
}
entries=[{...run,txAvgMbps:0}];await page.getByRole("button",{name:"Обновить",exact:true}).click();await expect(page.getByRole("alert",{name:"Чтение скорости: history",exact:true})).toHaveCount(0);await expect(row).not.toContainText("Неизвестно");await expect(row).toContainText("0 Мбит/с")
})