Files
MikrotikManager/tests/e2e/large-optimizer-routes.spec.ts

64 lines
6.0 KiB
TypeScript
Raw Permalink 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 { writeFileSync } from "node:fs"
import axe from "axe-core"
import { optimizerServersSchema } from "../../lib/route-optimizer-response"
test("Оптимизатор1000 маршрутов: WAN10 × JH10 × Exit10", async ({ page }, info) => {
test.setTimeout(90000)
const common = { host: "192.0.2.1", enabled: true, status: "online", latency: 10, country: "RU", site: "TEST", model: "CHR" }
let servers = optimizerServersSchema.parse([
{ ...common, id: 1, name: "Домашний роутер", type: "home-router", wanUplinks: Array.from({ length: 10 }, (_, i) => ({ id: `wan${i+1}`, name: `WAN${i+1}`, isp: "ISP", iface: `ether${i+1}`, ip: `198.51.100.${i+1}`, maxDl: 100, maxUl: 100 })) },
...Array.from({ length: 10 }, (_, i) => ({ ...common, id: i+2, name: `Jump ${i+1}`, type: "jump-host" })),
...Array.from({ length: 10 }, (_, i) => ({ ...common, id: i+12, name: `Exit ${i+1}`, type: "exit-node" })),
])
let reads = 0
const writes: string[] = []
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", r => {
const path = new URL(r.request().url()).pathname
if (path === "/api/servers") reads++
if (r.request().method() !== "GET" && !path.endsWith("/preview")) writes.push(path)
return r.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? servers : path === "/api/filters/rules" ? { rulesets: [] } : path === "/api/uptime/speed-probes" ? { probes: [] } : path === "/api/ospf/catalog" ? { interfaces: [], instances: [], neighbors: [], bfdSessions: [], routes: [], failures: [] } : path.endsWith("/ospf/optimize/preview") ? { serverId: 1, serverName: "Домашний роутер", pingWeight: 60, interfacesTotal: 0, changedCount: 0, unchangedCount: 0, interfaces: [], changes: [] } : {} })
})
const start = Date.now(); await page.goto("/route-optimizer?server=1&keep=1")
await page.getByRole("button", { name: "Маршруты (1000)", exact: true }).click()
const table = page.getByRole("table").filter({ hasText: "# Маршрут" })
await expect(table.locator("tr[data-row-id]")).toHaveCount(5)
await page.getByRole("button", { name: "Открыть все 1000 комбинаций", exact: true }).click()
await expect(table.locator("tr[data-row-id]")).toHaveCount(50)
const profile = { combinations: 1000, servers: servers.length, bytes: Buffer.byteLength(JSON.stringify(servers)), rendered: await table.locator("tr[data-row-id]").count(), tableNodes: await table.locator("*").count(), pageNodes: await page.locator("*").count(), readyMs: Date.now()-start }
console.log("Optimizer full routes", JSON.stringify(profile)); writeFileSync(info.outputPath("optimizer-routes-profile.json"), JSON.stringify(profile, null, 2))
const root = page.getByRole("region", { name: "Полные маршруты оптимизатора" })
const rows = table.locator("tr[data-row-id]")
const next = root.getByRole("button", { name: "Следующая страница", exact: true })
await next.click(); const previous = await rows.first().getAttribute("data-row-id")
await expect(rows.first().getByRole("cell").first()).toContainText("51")
const before = reads; await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect.poll(() => reads).toBeGreaterThan(before); await expect(rows.first()).toHaveAttribute("data-row-id", previous!)
for (let i=1; i<19; i++) await next.click()
await expect(next).toBeDisabled(); await expect(rows.first().getByRole("cell").first()).toContainText("951")
const minimum = await rows.last().getByRole("cell").nth(6).innerText()
await expect(rows.last().getByRole("cell").first()).toContainText("1000")
await root.getByRole("button", { name: "Свернуть", exact: true }).click(); await expect(rows).toHaveCount(5)
await root.getByRole("button", { name: "Открыть все 1000 комбинаций", exact: true }).click(); await expect(rows).toHaveCount(50)
await table.getByRole("button", { name: "Индекс", exact: true }).click()
await table.getByRole("button", { name: "Индекс", exact: true }).click()
await expect(rows.first().getByRole("cell").nth(6)).toHaveText(minimum)
expect(Number(await rows.last().getByRole("cell").first().innerText())).toBeGreaterThan(50)
await page.setViewportSize({ width: 320, height: 1000 })
const scroll = root.locator('[data-slot="scroll-area-viewport"]')
await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth })
expect(await rows.first().getByRole("cell").first().evaluate(el => { const a=el.getBoundingClientRect(), v=el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(); return a.left>=v.left-1 && a.right<=v.right+1 })).toBe(true)
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(320)
await scroll.evaluate(el => { el.scrollLeft = 0 })
await root.evaluate(el => el.scrollIntoView({ block: "start" }))
await page.addStyleTag({ content: "nextjs-portal{display:none!important}" })
await page.screenshot({ path: info.outputPath("optimizer-routes-pages-320.png"), animations: "disabled" })
await page.addScriptTag({ content: axe.source })
expect((await page.evaluate(async () => (window as unknown as { axe: typeof axe }).axe.run(document.querySelector('[aria-label="Полные маршруты оптимизатора"]')!, { runOnly: { type: "tag", values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"] } }))).violations.map(v => ({ id: v.id, nodes: v.nodes.map(n => n.target) }))).toEqual([])
await next.click(); servers = servers.filter(server => server.id === 1 || server.id === 2 || server.id === 12).map(server => server.id === 1 ? { ...server, wanUplinks: server.wanUplinks!.slice(0, 1) } : server)
await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect(rows).toHaveCount(1); await expect(rows.first().getByRole("cell").first()).toContainText("1")
expect(writes).toEqual([])
})