Files
MikrotikManager/tests/e2e/route-optimizer-data.spec.ts
T

43 lines
4.9 KiB
TypeScript

import {test,expect,type Page} from "@playwright/test"
const hosts=(name="Роутер")=>(["home-router","jump-host","exit-node"] as const).map((type,index)=>({id:index+1,name:name+" "+(index+1),host:"192.0.2."+(index+1),type,site:"TEST",country:"RU",enabled:true,status:"online",latency:10,model:"CHR",...(index===0?{wanUplinks:[{id:"wan",name:"WAN",isp:"ISP",iface:"ether1",ip:"198.51.100.1",maxDl:100,maxUl:100}]}:{})}))
const paths={servers:"/api/servers",rules:"/api/filters/rules",probes:"/api/uptime/speed-probes"} as const
const body=(p:string,name="Роутер")=>p===paths.servers?hosts(name):p===paths.rules?{rulesets:[{serverId:"1",rules:[{id:"r",community:"65001:1",communityName:"Сервис",gateway:"192.0.2.2",gatewayTunnelId:"",description:""}]}]}:p===paths.probes?{probes:[]}:p==="/api/auth/config"?{required:false}:p.endsWith("/preview")?{interfaces:[],changes:[],changedCount:0,interfacesTotal:0}:p.endsWith("/ospf")?{interfaces:[],instances:[],neighbors:[],bfdSessions:[]}:{}
async function health(page:Page){await page.route("**/health",r=>r.fulfill({json:{ok:true}}))}
for(const part of ["servers","rules","probes"] as const)for(const malformed of [false,true])test("Оптимизатор: первоначальная ошибка и повтор "+part+"/"+malformed,async({page})=>{
let failing=true;await health(page)
await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname;return p===paths[part]&&failing?r.fulfill(malformed?{json:{}}:{status:503,json:{error:"Источник недоступен"}}):r.fulfill({json:body(p)})})
await page.goto("/route-optimizer")
await expect(page.getByRole("alert").filter({hasText:"Данные оптимизатора неизвестны"})).toBeVisible()
const stats=page.getByLabel("Сводка оптимизатора");await expect(stats).toContainText("Расчёт пока неизвестен");await expect(stats).not.toContainText("модель не предлагает переключений")
await expect(page.getByRole("table").filter({hasText:"WAN-аплинк"})).toHaveCount(0)
failing=false;await page.getByRole("button",{name:"Обновить",exact:true}).click()
await expect(page.getByRole("table").filter({hasText:"WAN-аплинк"}).locator("tr[data-row-id]")).toHaveCount(1)
await expect(page.getByRole("alert").filter({hasText:"Данные оптимизатора неизвестны"})).toHaveCount(0)
})
for(const part of ["servers","rules","probes"] as const)test("Оптимизатор: частичный сбой сохраняет полный снимок "+part,async({page})=>{
let failing=false;await health(page)
await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname;return p===paths[part]&&failing?r.fulfill({status:503,json:{error:"Отказ части"}}):r.fulfill({json:body(p,failing?"Новый каталог":"Исходный каталог")})})
await page.goto("/route-optimizer")
const grid=page.getByRole("table").filter({hasText:"WAN-аплинк"});await expect(grid.locator("tr[data-row-id]")).toHaveCount(1)
await expect(grid.getByRole("columnheader",{name:/Исходный каталог 2/})).toBeVisible()
failing=true;await page.getByRole("button",{name:"Обновить",exact:true}).click()
await expect(page.getByRole("alert").filter({hasText:"Последний полный снимок"})).toBeVisible()
await expect(grid.getByRole("columnheader",{name:/Исходный каталог 2/})).toBeVisible()
await expect(page.getByRole("button",{name:"Оптимизировать OSPF",exact:true})).toBeDisabled()
})
test("Оптимизатор: поздний расчёт не заменяет новый",async({page})=>{
let version="Исходный",reads=0,started=false,release!:()=>void
const gate=new Promise<void>(resolve=>{release=resolve});await health(page)
await page.route("**/api/**",async r=>{const p=new URL(r.request().url()).pathname,value=body(p,version)
if(p===paths.rules&&++reads===2){started=true;await gate}
return r.fulfill({json:value})})
await page.goto("/route-optimizer");const grid=page.getByRole("table").filter({hasText:"WAN-аплинк"});await expect(grid.locator("tr[data-row-id]")).toHaveCount(1)
await page.getByRole("button",{name:"Настройки оптимизатора",exact:true}).click()
version="Старый";await page.getByRole("button",{name:"Обновить",exact:true}).click();await expect.poll(()=>started).toBe(true)
version="Новый";await page.getByRole("button",{name:"Пересчитать",exact:true}).click()
await expect(grid.getByRole("columnheader",{name:/Новый 2/})).toBeVisible()
const response=page.waitForResponse(r=>new URL(r.url()).pathname===paths.rules);release();await(await response).finished()
await page.evaluate(()=>new Promise<void>(resolve=>requestAnimationFrame(()=>requestAnimationFrame(()=>resolve()))))
await expect(grid.getByRole("columnheader",{name:/Новый 2/})).toBeVisible()
})