Files

82 lines
5.8 KiB
TypeScript

import { test, expect } from "@playwright/test"
for (const kind of ["rule", "address"] as const) {
for (const editing of [false, true]) {
for (const family of ["ip", "ip6"] as const) {
test(`Firewall: сохранение ${kind}/${editing ? "edit" : "create"}/${family} сохраняет форму при ошибке`, async ({ page }) => {
let attempts = 0
let release: (() => void) | undefined
const gate = new Promise<void>(resolve => { release = resolve })
const rule = { id: "rule-1", rosId: "*R/1", serverId: "1", serverName: "Роутер", family, table: "filter", chain: "forward", action: "accept", proto: "tcp", src: "", dst: "", port: "443", iface: "", comment: "Правило тест", enabled: true, hits: 1 }
const entry = { id: "address-1", rosId: "*A/1", serverId: "1", serverName: "Роутер", family, list: "trusted", address: family === "ip" ? "192.0.2.10" : "2001:db8::10", comment: "Адрес тест", disabled: false }
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
await page.route("**/api/**", async route => {
const path = new URL(route.request().url()).pathname
if (["POST", "PUT"].includes(route.request().method())) {
attempts++
expect(path).toBe(kind === "rule" ? "/api/firewall/rules" : "/api/firewall/address-lists")
expect(route.request().method()).toBe(editing ? "PUT" : "POST")
const payload = route.request().postDataJSON()
expect(payload).toMatchObject({ serverId: "1", family, comment: "Сохранить ввод", disabled: false })
if (kind === "rule") expect(payload).toMatchObject({ table: "filter", action: "accept", chain: editing ? "forward" : "input" })
else expect(payload).toMatchObject({ list: "trusted", address: entry.address })
if (editing) expect(payload.rosId).toBe(kind === "rule" ? "*R/1" : "*A/1")
else expect(payload).not.toHaveProperty("rosId")
if (attempts === 1) { await gate; return route.fulfill({ status: 403, json: { error: "Сохранение запрещено тест" } }) }
if (attempts === 2) return route.fulfill({ json: {} })
if (attempts === 3) return route.fulfill({ json: { ok: false } })
return route.fulfill({ json: { ok: true } })
}
return route.fulfill({ json: path === "/api/auth/config" ? { required: false }
: path === "/api/firewall/all" ? { rules: [rule], addressLists: [entry] }
: path === "/api/servers" ? [{ id: 1, name: "Роутер", host: "192.0.2.1", type: "exit-node", enabled: true, country: "RU", status: "online" }] : {} })
})
await page.goto("/firewall?server=1")
await expect(page.locator("tr[data-row-id]")).toHaveCount(family === "ip" ? 1 : 0)
if (family === "ip6") await page.getByRole("button", { name: "IPv6", exact: true }).click()
if (kind === "address") await page.getByRole("button", { name: /Адр. листы/ }).click()
const open = async () => {
if (editing) {
await page.getByRole("button", { name: kind === "rule" ? "Действия: forward accept" : "Действия: " + entry.address, exact: true }).click()
await page.getByRole("menuitem", { name: "Редактировать", exact: true }).click()
} else {
await page.getByRole("button", { name: kind === "rule" ? "Новое правило" : "Добавить", exact: true }).click()
}
}
await open()
const dialog = page.getByRole("dialog")
const comment = dialog.locator('[data-slot="field"]').filter({ has: page.getByText("Комментарий", { exact: true }) }).getByRole("textbox")
await comment.fill("Сохранить ввод")
if (kind === "address" && !editing) {
await dialog.getByPlaceholder("cdn-bypass").fill("trusted")
await dialog.getByPlaceholder("10.0.0.0/8").fill(entry.address)
}
const submit = dialog.getByRole("button", { name: editing ? "Сохранить" : kind === "rule" ? "Создать правило" : "Добавить", exact: true })
await submit.evaluate(button => { (button as HTMLButtonElement).click(); (button as HTMLButtonElement).click() })
await expect.poll(() => attempts).toBe(1)
await expect(dialog.getByRole("status")).toContainText("Ожидание результата сохранения")
await expect(comment).toBeDisabled()
for (const toggle of await dialog.getByRole("switch").all()) await expect(toggle).toBeDisabled()
await expect(dialog.getByRole("button", { name: "Отмена" })).toBeDisabled()
await page.keyboard.press("Escape")
await expect(dialog).toBeVisible()
release!()
await expect(dialog.getByRole("alert")).toContainText("Сохранение запрещено тест")
await expect(comment).toHaveValue("Сохранить ввод")
for (let i = 2; i <= 3; i++) {
await submit.click()
await expect.poll(() => attempts).toBe(i)
await expect(dialog.getByRole("alert")).toContainText("Сервер не подтвердил сохранение")
await expect(comment).toHaveValue("Сохранить ввод")
await expect(page.getByText(kind === "rule" ? editing ? "Правило сохранено" : "Правило создано" : editing ? "Запись сохранена" : "Запись создана", { exact: true })).toHaveCount(0)
}
await submit.click()
await expect(dialog).toHaveCount(0)
expect(attempts).toBe(4)
await open()
await expect(dialog.getByRole("alert")).toHaveCount(0)
})
}
}
}