fix(ui): улучшить клавиатурный ввод Community в Filters
This commit is contained in:
1 parent
4ae5f2edcd
commit
29a4ea2e5b
10 files changed
+130
-37
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import { test, expect } from "@playwright/test"
|
||||
import { mkdirSync } from "node:fs"
|
||||
|
||||
for (const device of ["desktop", "mobile"] as const) {
|
||||
test(`Filters: клавиатурный ввод и layout ${device}`, async ({ page }) => {
|
||||
await page.setViewportSize(device === "desktop" ? { width: 1440, height: 1000 } : { width: 390, height: 844 })
|
||||
await page.clock.install({ time: new Date("2026-09-30T01:00:00Z") })
|
||||
const rulesFor = (id: string) => [
|
||||
{ id: id + "-youtube", community: "65001:100", gateway: "10.0.0.2", gatewayTunnelId: "t" + id, action: "route", description: "Видеосервисы через основной шлюз" },
|
||||
{ id: id + "-streaming", community: "65001:200", gateway: "10.0.0.2", gatewayTunnelId: "t" + id, action: "route", description: "Потоковые сервисы" },
|
||||
{ id: id + "-blackhole", community: "65535:666", gateway: "", gatewayTunnelId: "", action: "blackhole", description: "RTBH — защита от DDoS" },
|
||||
]
|
||||
const rulesets = [{ serverId: "1", rules: rulesFor("1") }, { serverId: "2", rules: rulesFor("2") }]
|
||||
const tunnel = (id: string) => ({ id: "t" + id, serverId: id, name: "gre-core-edge", localAddress: "192.0.2." + id, remoteAddress: "198.51.100.1", localInnerIp: "10.0.0.1/30", remoteInnerIp: "10.0.0.2/30", poolId: "", ipsec: null, mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 3, dscp: "inherit", clampTcpMss: true, allowFastPath: true, comment: "", enabled: true, status: "up" })
|
||||
let writes = 0
|
||||
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
|
||||
await page.route("**/api/**", route => {
|
||||
const url = new URL(route.request().url()), path = url.pathname, id = url.searchParams.get("serverId")
|
||||
if (path === "/api/filters/rules" && route.request().method() === "PUT") {
|
||||
writes++
|
||||
const body = route.request().postDataJSON()
|
||||
expect(body.serverId).toBe(device === "mobile" ? "2" : "1")
|
||||
expect(body.rules.at(-1)).toMatchObject({ community: "65001:777", action: "blackhole", description: "Новый фильтр", gateway: "", gatewayTunnelId: "" })
|
||||
rulesets.find(rs => rs.serverId === body.serverId)!.rules = body.rules
|
||||
return route.fulfill({ json: { ok: true, rules: body.rules } })
|
||||
}
|
||||
return route.fulfill({ json: path === "/api/filters/rules" ? { rulesets: id ? rulesets.filter(rs => rs.serverId === id) : rulesets, greTunnels: [], live: true }
|
||||
: path === "/api/servers" ? [1, 2].map(i => ({ id: i, name: i === 1 ? "Основной роутер" : "Резервный роутер", host: "192.0.2." + i, type: "exit-node", enabled: true, country: "RU", site: "CORE", asn: "65001", status: "online", latency: 3 }))
|
||||
: path === "/api/filters/gre-tunnels" ? { tunnels: [tunnel(id ?? "1")] }
|
||||
: path === "/api/recursive-routes" ? { routes: [], stale: false }
|
||||
: path === "/api/auth/config" ? { required: false } : {} })
|
||||
})
|
||||
await page.goto("/filters")
|
||||
await expect(page.getByRole("button", { name: "Новое правило", exact: true })).toBeEnabled()
|
||||
await expect(page.locator("tr[data-row-id]")).toHaveCount(3)
|
||||
await expect(page.getByRole("group", { name: "Свежесть данных устройства" }).locator("time")).toHaveCount(3)
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true)
|
||||
await page.addStyleTag({ content: "nextjs-portal { display: none !important; }" })
|
||||
mkdirSync("docs/ux-ui/screens", { recursive: true })
|
||||
await page.screenshot({ path: `docs/ux-ui/screens/filters-${device}.png` })
|
||||
if (device === "mobile") {
|
||||
await page.getByRole("button", { name: "Серверы", exact: true }).click()
|
||||
const rail = page.getByRole("dialog")
|
||||
await rail.getByRole("option", { name: /Резервный роутер/ }).click()
|
||||
await expect(rail).toHaveCount(0)
|
||||
await expect(page.getByRole("button", { name: "Новое правило", exact: true })).toBeEnabled()
|
||||
}
|
||||
const create = page.getByRole("button", { name: "Новое правило", exact: true })
|
||||
await create.focus()
|
||||
await page.keyboard.press("Enter")
|
||||
const dialog = page.getByRole("dialog")
|
||||
await dialog.getByRole("button", { name: "Добавить", exact: true }).click()
|
||||
await expect(dialog.getByRole("alert")).toContainText("BGP Community обязательно")
|
||||
const community = dialog.getByRole("combobox", { name: /BGP Community/ })
|
||||
await community.fill("65535")
|
||||
await page.keyboard.press("ArrowDown")
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(community).toHaveValue("65535:666")
|
||||
await expect(dialog.getByRole("button", { name: /⊘ Blackhole/ })).toHaveAttribute("aria-pressed", "true")
|
||||
await community.fill("65001:777")
|
||||
await page.keyboard.press("Tab")
|
||||
await dialog.getByRole("textbox", { name: "Описание правила" }).fill("Новый фильтр")
|
||||
expect(await dialog.evaluate(el => el.getBoundingClientRect().right <= window.innerWidth && el.getBoundingClientRect().left >= 0)).toBe(true)
|
||||
await page.screenshot({ path: `docs/ux-ui/screens/filters-rule-${device}.png` })
|
||||
await dialog.getByRole("button", { name: "Добавить", exact: true }).focus()
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(dialog).toHaveCount(0)
|
||||
await expect(page.locator("tr[data-row-id]")).toHaveCount(4)
|
||||
expect(writes).toBe(1)
|
||||
})
|
||||
}
|
||||
@@ -42,6 +42,7 @@ for (const editing of [false, true]) {
|
||||
const dialog = page.getByRole("dialog")
|
||||
if (!editing) {
|
||||
await dialog.getByPlaceholder("65001:100").fill("65001:999")
|
||||
await page.keyboard.press("Tab")
|
||||
await dialog.getByRole("button", { name: /⊘ Blackhole/ }).click()
|
||||
}
|
||||
const description = dialog.getByRole("textbox", { name: "Описание правила" })
|
||||
|
||||
Reference in new issue
Block a user