99 lines
6.8 KiB
TypeScript
99 lines
6.8 KiB
TypeScript
import { test, expect } from "@playwright/test"
|
|
const device = { id: 1, name: "Роутер 1", host: "192.0.2.1", enabled: true, country: "RU", status: null }
|
|
const iface = { id: "*1", serverId: 1, serverName: "Роутер 1", serverSite: "", serverCountry: "RU", instance: "default", area: "backbone", areaId: "0.0.0.0", interface: "ether1", cost: 20, type: "broadcast", disabled: false, inactive: false, priority: 1, helloInterval: 10, deadInterval: 40, useBfd: false }
|
|
const catalog = { neighbors: [], interfaces: [iface], instances: [], bfdSessions: [], routes: [], failures: [] }
|
|
const result = { serverId: 1, serverName: "Роутер 1", pingWeight: 60, optimizedCount: 1, applied: [{ interface: "ether1", from: 20, to: 10 }], interfaces: [{ id: "*1", interface: "ether1", currentCost: 20, optimalCost: 10, score: 1, pingMs: 10, dlMbps: 100, ulMbps: 100 }] }
|
|
|
|
for (const outcome of ["success", "http", "foreign", "malformed", "poll-failure"]) {
|
|
test("OSPF: оптимизация, общий lock и результат " + outcome, async ({ page }) => {
|
|
let writes = 0, polled = false, reads = 0
|
|
let release: (() => void) | undefined
|
|
const gate = new Promise<void>(resolve => { release = resolve })
|
|
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
|
|
await page.route("**/api/**", async r => {
|
|
const path = new URL(r.request().url()).pathname
|
|
if (path === "/api/servers/1/ospf/optimize") {
|
|
writes++
|
|
expect(r.request().method()).toBe("POST")
|
|
expect(r.request().postDataJSON().pingWeight).toBeGreaterThanOrEqual(0)
|
|
await gate
|
|
polled = true
|
|
return r.fulfill(outcome === "http" ? { status: 503, json: { error: "Применение не завершено" } } : { json: outcome === "foreign" ? { ...result, serverId: 2 } : outcome === "malformed" ? { ...result, optimizedCount: 99 } : result })
|
|
}
|
|
if (path === "/api/ospf/catalog") {
|
|
reads++
|
|
if (polled && outcome === "poll-failure") return r.fulfill({ status: 503, json: { error: "Опрос после записи недоступен" } })
|
|
return r.fulfill({ json: catalog })
|
|
}
|
|
return r.fulfill({ json: path === "/api/servers" ? [device] : path === "/api/auth/config" ? { required: false } : {} })
|
|
})
|
|
await page.goto("/ospf")
|
|
await page.getByRole("option").filter({ hasText: "Роутер 1" }).click()
|
|
const optimize = page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })
|
|
await expect(optimize).toBeEnabled()
|
|
await expect(page.getByText("opt 10", { exact: true })).toHaveCount(0)
|
|
await optimize.evaluate(el => { (el as HTMLButtonElement).click(); (el as HTMLButtonElement).click() })
|
|
await expect.poll(() => writes).toBe(1)
|
|
await expect(page.getByRole("button", { name: "Оптимизация OSPF…", exact: true })).toBeDisabled()
|
|
await expect(page.getByRole("button", { name: "Обновить", exact: true })).toBeDisabled()
|
|
await page.getByRole("button", { name: "Обновить", exact: true }).evaluate(el => (el as HTMLButtonElement).click())
|
|
expect(reads).toBe(1)
|
|
release!()
|
|
await expect.poll(() => reads).toBe(2)
|
|
if (["http", "foreign", "malformed"].includes(outcome)) {
|
|
await expect(page.getByRole("alert").filter({ hasText: "Оптимизация OSPF не подтверждена" })).toBeVisible()
|
|
await expect(page.getByText("API подтвердил оптимизацию OSPF", { exact: false })).toHaveCount(0)
|
|
} else {
|
|
await expect(page.getByText("API подтвердил оптимизацию OSPF: 1 интерфейсов", { exact: true })).toBeVisible()
|
|
await expect(page.getByRole("group", { name: "Свежесть OSPF" }).locator('[data-ospf-time="write"]')).toContainText("API подтвердил оптимизацию устройства 1")
|
|
}
|
|
if (outcome === "poll-failure") {
|
|
await expect(page.getByRole("alert").filter({ hasText: "Опрос после записи недоступен" })).toBeVisible()
|
|
await expect(optimize).toBeDisabled()
|
|
} else await expect(optimize).toBeEnabled()
|
|
expect(writes).toBe(1)
|
|
})
|
|
}
|
|
test("OSPF: read-права не разрешают оптимизацию устройства", async ({ page }) => {
|
|
const payload = { sub: "test", email: "test@example.test", name: "Reader", apps: ["mm"], permissions: ["mm:network:read", "mm:servers:read"], exp: 4102444800 }
|
|
await page.addInitScript(value => localStorage.setItem("mmapp_token", "test." + btoa(JSON.stringify(value)) + ".test"), payload)
|
|
let writes = 0
|
|
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
|
|
await page.route("**/api/**", r => {
|
|
const path = new URL(r.request().url()).pathname
|
|
if (r.request().method() === "POST") writes++
|
|
return r.fulfill({ json: path === "/api/auth/config" ? { required: true } : path === "/api/servers" ? [device] : path === "/api/ospf/catalog" ? catalog : {} })
|
|
})
|
|
await page.goto("/ospf")
|
|
await page.getByRole("option").filter({ hasText: "Роутер 1" }).click()
|
|
await expect(page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })).toBeDisabled()
|
|
expect(writes).toBe(0)
|
|
})
|
|
|
|
for (const permission of ["mm:network:write", "mm:servers:write"]) {
|
|
test("OSPF: право оптимизации совпадает с backend — " + permission, async ({ page }) => {
|
|
await page.setViewportSize({ width: 320, height: 1000 })
|
|
const payload = { sub: "test", apps: ["mm"], permissions: ["mm:network:read", "mm:servers:read", permission], exp: 4102444800 }
|
|
await page.addInitScript(value => localStorage.setItem("mmapp_token", "test." + btoa(JSON.stringify(value)) + ".test"), payload)
|
|
let writes = 0
|
|
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/1/ospf/optimize") { writes++; return r.fulfill({ json: result }) }
|
|
return r.fulfill({ json: path === "/api/auth/config" ? { required: true } : path === "/api/servers" ? [device] : path === "/api/ospf/catalog" ? catalog : {} })
|
|
})
|
|
await page.goto("/ospf?server=1&tab=interfaces")
|
|
const button = page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })
|
|
if (permission === "mm:network:write") {
|
|
await expect(button).toBeEnabled(); await button.click()
|
|
await expect.poll(() => writes).toBe(1)
|
|
await expect(page.getByText("API подтвердил оптимизацию OSPF: 1 интерфейсов", { exact: true })).toBeVisible()
|
|
} else {
|
|
await expect(button).toBeDisabled()
|
|
await button.evaluate(el => (el as HTMLButtonElement).click())
|
|
expect(writes).toBe(0)
|
|
}
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
|
})
|
|
}
|