fix(ui): сохранять подтверждённый снимок пути при ошибке API
This commit is contained in:
1 parent
55c9349677
commit
5fdd6ef58c
9 files changed
+85
-53
No files matched your search
@@ -5,7 +5,7 @@ import {dashboardGre,dashboardVxlan,dashboardWg} from "./fixtures/dashboard-over
|
||||
import {bgpSession} from "./fixtures/bgp"
|
||||
|
||||
async function setup(page: Page, initiallyFailed = false, serverCount = 1, initialBgpPayload?:unknown) {
|
||||
const control = { failed: initiallyFailed, partial: false, prefixes: 321 as number|null, grePayload:undefined as unknown,wgPayload:undefined as unknown,vxlanPayload:undefined as unknown,serversPayload:undefined as unknown,probesPayload:undefined as unknown, trafficPayload: undefined as unknown, bgpPayload: initialBgpPayload as unknown, hold: false, holdPath: "/api/bgp/catalog", fallback: false, failFallback: false, pending: 0, release: () => {} }
|
||||
const control = { pathPayload:undefined as unknown,filterPayload:undefined as unknown,speedPayload:undefined as unknown, failed: initiallyFailed, partial: false, prefixes: 321 as number|null, grePayload:undefined as unknown,wgPayload:undefined as unknown,vxlanPayload:undefined as unknown,serversPayload:undefined as unknown,probesPayload:undefined as unknown, trafficPayload: undefined as unknown, bgpPayload: initialBgpPayload as unknown, hold: false, holdPath: "/api/bgp/catalog", fallback: false, failFallback: false, pending: 0, release: () => {} }
|
||||
let release!: () => void
|
||||
const gate = new Promise<void>(resolve => { release = resolve })
|
||||
control.release = release
|
||||
@@ -30,13 +30,13 @@ async function setup(page: Page, initiallyFailed = false, serverCount = 1, initi
|
||||
const json = path === "/api/servers" ? control.serversPayload !== undefined ? control.serversPayload : servers
|
||||
: path === "/api/uptime/overview" ? control.probesPayload !== undefined ? control.probesPayload : { probes: [] }
|
||||
: path === "/api/bgp/catalog" ? control.bgpPayload !== undefined ? control.bgpPayload : {sessions:[bgpSession(1,prefixes)],failures:[]}
|
||||
: path === "/api/filters/rules" ? { rulesets: [] }
|
||||
: path === "/api/filters/rules" ? control.filterPayload!==undefined?control.filterPayload:{ rulesets: [] }
|
||||
: path === "/api/filters/gre-tunnels" ? control.grePayload!==undefined?control.grePayload:{ tunnels: [dashboardGre],failures:[] }
|
||||
: path === "/api/wireguard" ? control.wgPayload!==undefined?control.wgPayload:{ interfaces: [],failures:[] }
|
||||
: path === "/api/vxlan" ? control.vxlanPayload!==undefined?control.vxlanPayload:{ tunnels: [],failures:[] }
|
||||
: path === "/api/traffic/servers" ? control.trafficPayload !== undefined ? control.trafficPayload : { servers: [{ id: "1", rxNow: 1000, txNow: 500, rxSeries: [1000], txSeries: [500],observations:{rxNow:true,txNow:true,rxSeries:[true],txSeries:[true],sampledAt:"2026-09-20T00:00:00Z"} }] }
|
||||
: path === "/api/internet-path/latest" ? { snapshot: control.fallback ? null : snapshot }
|
||||
: path === "/api/uptime/speed-probes" ? { probes: [] }
|
||||
: path === "/api/internet-path/latest" ? control.pathPayload!==undefined?control.pathPayload:{ snapshot: control.fallback ? null : snapshot }
|
||||
: path === "/api/uptime/speed-probes" ? control.speedPayload!==undefined?control.speedPayload:{ probes: [] }
|
||||
: path === "/api/events" ? { events: [{ id: "e1", title: "Событие сохранено", message: "Тестовое событие", level: "info", sourceModule: "system", eventType: "test", createdAt: "2026-09-20T00:00:00Z", entityId: null, entityType: null, payload: {} }] } : {}
|
||||
return route.fulfill({ json })
|
||||
})
|
||||
@@ -246,3 +246,11 @@ for(const state of ["legacy","unmeasured","zero","failure","gaps","invalid"])tes
|
||||
for(const kind of ["gre","wg","vxlan"] as const)for(const broken of ["missing","partial","duplicate"])test("Dashboard overlay complete source and cache/"+kind+"/"+broken,async({page})=>{
|
||||
const control=await setup(page);await expect(refresh(page)).toBeEnabled();const source=page.locator('[data-source="'+kind+'"]'),controlKey=kind==="gre"?"grePayload":kind==="wg"?"wgPayload":"vxlanPayload",rowsKey=kind==="wg"?"interfaces":"tunnels",row=kind==="gre"?dashboardGre:kind==="wg"?dashboardWg:dashboardVxlan;control[controlKey]={[rowsKey]:[row],failures:[]};await refresh(page).click();await expect(source).not.toContainText("ошибка");const receivedAt=await source.locator("time").getAttribute("datetime");control[controlKey]=broken==="missing"?{}:broken==="partial"?{[rowsKey]:[row],failures:[{serverId:"2",serverName:"Узел без ответа",error:"timeout"}]}:{[rowsKey]:[row,row],failures:[]};await refresh(page).click();await expect(source).toContainText("ошибка обновления");await expect(source.locator("time")).toHaveAttribute("datetime",receivedAt!);await expect(page.getByRole("link").filter({hasText:"Туннели работают"})).toContainText("Последний успешный снимок");await expect(page.locator('[data-source="servers"]')).not.toContainText("ошибка");if(kind==="gre")await expect(page.getByText("GRE сохранён",{exact:true})).toBeVisible();control[controlKey]={[rowsKey]:[],failures:[]};await refresh(page).click();await expect(source).not.toContainText("ошибка");if(kind==="gre")await expect(page.getByText("GRE сохранён",{exact:true})).toHaveCount(0)
|
||||
})
|
||||
|
||||
for(const broken of ["missing","incomplete","foreign","invalid-date","corrupt-null","filters","speed"])test("Dashboard Internet path keeps last confirmed source/"+broken,async({page})=>{
|
||||
const control=await setup(page);await expect(refresh(page)).toBeEnabled();const source=page.locator('[data-source="internetPath"]');await expect(source).not.toContainText("ошибка");const times=await source.locator("time").evaluateAll(nodes=>nodes.map(n=>n.getAttribute("datetime")));
|
||||
if(broken==="filters"||broken==="speed"){control.fallback=true;if(broken==="filters")control.filterPayload={rulesets:[],stale:true};else control.speedPayload={}}
|
||||
else control.pathPayload=broken==="missing"?{}:broken==="corrupt-null"?{snapshot:null,sampledAt:"2026-09-20T00:00:00Z"}:{snapshot:{sampledAt:broken==="invalid-date"?"invalid":"2026-09-20T00:00:00Z",servers:[],greTunnels:[],filtersRulesets:[],speedProbes:broken==="incomplete"?undefined:[],routeLookupByServerId:broken==="foreign"?{"99":null}:{},wanRuntimeByHomeId:{}}};
|
||||
await refresh(page).click();await expect(source).toContainText("ошибка обновления");expect(await source.locator("time").evaluateAll(nodes=>nodes.map(n=>n.getAttribute("datetime")))).toEqual(times);await expect(page.locator('[data-source="servers"]')).not.toContainText("ошибка");
|
||||
control.pathPayload=undefined;control.filterPayload=undefined;control.speedPayload=undefined;control.fallback=false;await refresh(page).click();await expect(source).not.toContainText("ошибка");
|
||||
})
|
||||
Reference in new issue
Block a user