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

103 lines
7.5 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, type Page } from "@playwright/test"
import type { OptimizerApiServer } from "../../lib/route-optimizer-data"
const ids = Array.from({ length: 12 }, (_, i) => i + 1)
const servers: OptimizerApiServer[] = (["home-router", "jump-host", "exit-node"] as const).map((type, i) => ({
id: i + 1, name: `Роутер ${i + 1}`, host: `192.0.2.${i + 1}`, type,
site: "TEST", country: "RU", enabled: true, status: "online", latency: 10, model: "CHR",
...(i === 0 ? { wanUplinks: ids.map(id => ({ id: `wan${id}`, name: `WAN${id}`, isp: "ISP", iface: `ether${id}`, ip: `198.51.100.${id}`, maxDl: 100, maxUl: 100 })) } : {}),
}))
async function setup(page: Page, preview: "ok" | "empty" | "error" = "ok", missingExit = false, manyHomes = false) {
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
await page.route("**/api/**", route => {
const path = new URL(route.request().url()).pathname
if (path.endsWith("/ospf/optimize/preview")) {
if (preview === "error") return route.fulfill({ status: 500, json: { error: "Расчёт недоступен" } })
const interfaces = preview === "empty" ? [] : ids.map(i => ({ id: String(i), interface: `ether${i}`, currentCost: i, optimalCost: 20, score: i, pingMs: i, dlMbps: 100, ulMbps: 50 }))
return route.fulfill({ json: {serverId:1,serverName:"Роутер 1",pingWeight:60,unchangedCount:0, interfaces, changes: interfaces, changedCount: interfaces.length, interfacesTotal: interfaces.length } })
}
return route.fulfill({ json: path === "/api/servers" ? [...servers.filter(server => !missingExit || server.type !== "exit-node"), ...(manyHomes ? Array.from({ length: 5 }, (_, i) => ({ ...servers[0], id: i+4, name: `Другой дом ${i+4}`, wanUplinks: [] })) : [])]
: path === "/api/auth/config" ? { required: false }
: path === "/api/evobgp/settings" ? { enabled: false, baseUrl: "", secretConfigured: false }
: path === "/api/filters/rules" ? { rulesets: [{ serverId: "1", rules: ids.map(i => ({ id: String(i), community: `65001:${i}`, communityName: `Сервис ${i}`, gateway: "192.0.2.2", gatewayTunnelId: "", description: "" })) }] }
: path === "/api/uptime/speed-probes" ? { probes: [] }
: path === "/api/ospf/catalog" ? { interfaces: [], instances: [], neighbors: [], bfdSessions: [], routes: [], failures: [] } : {} })
})
await page.goto("/route-optimizer")
await expect(page.getByRole("table").filter({ hasText: "WAN-аплинк" }).locator("tr[data-row-id]")).toHaveCount(12)
}
test("Оптимизатор: 12 WAN, все комбинации и закрепление Community после сортировки", async ({ page }) => {
const errors: string[] = []
page.on("pageerror", e => errors.push(e.message))
await setup(page)
const matrix = page.getByRole("table").filter({ hasText: "WAN-аплинк" })
await expect(matrix.locator("tr[data-row-id]")).toHaveCount(12)
await expect(matrix.getByRole("columnheader", { name: /Роутер 2/ })).toBeVisible()
await expect(matrix.locator('tr[data-row-id="wan12"]')).toContainText("WAN12")
await page.getByRole("button", { name: "Маршруты (12)", exact: true }).click()
const routes = page.getByRole("table").filter({ hasText: "# Маршрут" })
await expect(routes.locator("tr[data-row-id]")).toHaveCount(5)
await page.getByRole("button", { name: "Показать все 12 комбинаций", exact: true }).click()
await expect(routes.locator("tr[data-row-id]")).toHaveCount(12)
await routes.getByRole("button", { name: "Индекс", exact: true }).click()
await routes.getByRole("button", { name: "Индекс", exact: true }).click()
await expect(routes.locator("tr[data-row-id]").first()).toHaveAttribute("data-row-id", "1-wan12-2-3")
await page.getByRole("button", { name: "Свернуть", exact: true }).click()
await expect(routes.locator("tr[data-row-id]")).toHaveCount(5)
await page.getByRole("button", { name: "BGP community (12)", exact: true }).click()
const recs = page.getByRole("table").filter({ hasText: "Community" })
await expect(recs.locator("tr[data-row-id]")).toHaveCount(12)
await recs.getByRole("button", { name: "Community", exact: true }).click()
await recs.getByRole("button", { name: "Community", exact: true }).click()
const selected = recs.locator("tr[data-row-id]").first()
await expect(selected).toContainText("65001:12")
await selected.getByRole("button", { name: "Закрепить", exact: true }).click()
await expect(selected.getByRole("button", { name: "Открепить", exact: true })).toBeVisible()
await expect(selected.getByRole("button", { name: "Применить", exact: true })).toHaveCount(0)
expect(errors).toEqual([])
})
test("OSPF preview: 12 интерфейсов и числовая сортировка", async ({ page }) => {
await setup(page)
const table = page.getByRole("table").filter({ hasText: "Speed (dl/ul)" })
await expect(table.locator("tr[data-row-id]")).toHaveCount(12)
await table.getByRole("button", { name: "Cost", exact: true }).click()
await expect(table.locator("tr[data-row-id]").first()).toContainText("ether12")
})
for (const state of ["empty", "error"] as const) {
test(`OSPF preview: состояние ${state}`, async ({ page }) => {
await setup(page, state)
await expect(page.getByText(state === "empty" ? "Интерфейсы OSPF не найдены для выбранного сервера" : /Ошибка preview:.*Расчёт недоступен/)).toBeVisible()
await expect(page.getByRole("table").filter({ hasText: "Speed (dl/ul)" })).toHaveCount(0)
})
}
test("Оптимизатор: без ExitNode отсутствующие индексы не становятся нулями", async ({page}) => {
await setup(page,"ok",true)
await page.getByRole("button",{name:"BGP community (12)",exact:true}).click()
const grid=page.getByRole("table").filter({hasText:"Community"})
await expect(grid.locator("tr[data-row-id]")).toHaveCount(12)
await expect(grid.getByLabel("Индекс неизвестен")).toHaveCount(24)
await expect(grid).not.toContainText("0 б.")
await expect(grid.getByRole("button",{name:"Симулировать",exact:true})).toHaveCount(0)
})
test("Оптимизатор: закрепление Community сохраняется между страницами устройств", async ({ page }) => {
await setup(page, "ok", false, true)
const scope = page.getByRole("region", { name: "Домашние устройства оптимизатора" })
await page.getByRole("button", { name: "BGP community (12)", exact: true }).click()
const rec = scope.getByRole("table").filter({ hasText: "Community" }).locator('tr[data-row-id="1::65001:1::0"]')
await rec.getByRole("button", { name: "Закрепить", exact: true }).click()
await expect(rec.getByRole("button", { name: "Открепить", exact: true })).toBeVisible()
await scope.getByRole("button", { name: "Следующая страница домашних устройств" }).click()
await expect(scope.getByRole("status")).toContainText("6–6 из 6")
await expect(scope.getByText("Другой дом 8", { exact: true })).toBeVisible()
await scope.getByRole("button", { name: "Предыдущая страница домашних устройств" }).click()
await page.getByRole("button", { name: "BGP community (12)", exact: true }).click()
await expect(rec.getByRole("button", { name: "Открепить", exact: true })).toBeVisible()
})