90 lines
5.4 KiB
TypeScript
90 lines
5.4 KiB
TypeScript
import { test, expect, type Page } from "@playwright/test"
|
|
import { wgListResponseSchema } from "../../packages/contracts/src/wireguard"
|
|
|
|
const fixture = wgListResponseSchema.parse({ interfaces: Array.from({ length: 12 }, (_, i) => ({
|
|
id: `wg-${i + 1}`, rosId: `*${i + 1}`, name: `wg-test-${i + 1}`, serverId: "1",
|
|
serverName: "Тестовый роутер", serverCountry: "RU", listenPort: 13231 + i, mtu: 1420,
|
|
comment: "Тест", enabled: true, status: "up",
|
|
peers: [{ id: `peer-${i + 1}`, rosId: `*${i + 20}`, publicKey: `fixture-public-key-${i + 1}`,
|
|
name: `Пир ${i + 1}`, allowedIps: [`10.0.0.${i + 1}/32`], transferRx: i + 1, transferTx: i + 1 }],
|
|
})) })
|
|
|
|
async function setup(page: Page, empty = false) {
|
|
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
|
|
await page.route("**/api/**", route => {
|
|
const path = new URL(route.request().url()).pathname
|
|
return route.fulfill({ json: path === "/api/wireguard" ? (empty ? { interfaces: [] } : fixture)
|
|
: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [] : {} })
|
|
})
|
|
await page.goto("/wireguard")
|
|
}
|
|
|
|
test("WireGuard: 12 интерфейсов, сортировка порта, раскрытие и список пиров", async ({ page }) => {
|
|
const errors: string[] = []
|
|
page.on("pageerror", e => errors.push(e.message))
|
|
await setup(page)
|
|
const rows = page.locator("tr[data-row-id]")
|
|
await expect(rows).toHaveCount(12)
|
|
await page.getByRole("button", { name: "Порт", exact: true }).click()
|
|
await expect(rows.first()).toContainText("wg-test-12")
|
|
await rows.first().click()
|
|
await expect(page.getByText("10.0.0.12/32", { exact: true })).toBeVisible()
|
|
await rows.first().click()
|
|
await expect(page.getByText("10.0.0.12/32", { exact: true })).toBeHidden()
|
|
await page.getByRole("tab", { name: /Пиры/ }).click()
|
|
await expect(rows).toHaveCount(12)
|
|
await expect(rows.last()).toContainText("10.0.0.12/32")
|
|
await page.getByRole("button", { name: "Пир", exact: true }).click()
|
|
await expect(rows.first()).toContainText("Пир 1")
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("WireGuard: пустые интерфейсы и пиры", async ({ page }) => {
|
|
await setup(page, true)
|
|
await expect(page.getByText("Нет WireGuard интерфейсов", { exact: true })).toBeVisible()
|
|
await page.getByRole("tab", { name: /Пиры/ }).click()
|
|
await expect(page.getByText("Нет пиров", { exact: true })).toBeVisible()
|
|
})
|
|
|
|
for (const view of ["details", "peers"] as const) test("WireGuard traffic: observed zero differs from missing/" + view, async ({ page }) => {
|
|
await setup(page)
|
|
const interfaces = fixture.interfaces.map((row, i) => ({ ...row, peers: row.peers.map(peer => {
|
|
const { transferRx, transferTx, ...config } = peer
|
|
return i === 0 ? { ...config, transferRx: 0, transferTx: 0 } : i === 1 ? config : { ...config, transferRx, transferTx }
|
|
}) }))
|
|
await page.route("**/api/wireguard", route => route.fulfill({ json: wgListResponseSchema.parse({ interfaces }) }))
|
|
await page.reload()
|
|
const rows = page.locator("tr[data-row-id]")
|
|
if (view === "peers") await page.getByRole("tab", { name: /Пиры/ }).click()
|
|
for (const [index, value] of [[0, "0 Б"], [1, "—"], [2, "3 Б"]] as const) {
|
|
const row = rows.nth(index)
|
|
if (view === "details") await row.click()
|
|
const target = view === "details" ? row.locator("xpath=following-sibling::tr[1]") : row
|
|
await expect(target.getByLabel("RX", { exact: true })).toHaveText(value)
|
|
await expect(target.getByLabel("TX", { exact: true })).toHaveText(value)
|
|
if (view === "details") await row.click()
|
|
}
|
|
})
|
|
|
|
test("WireGuard handshake: old observation never proves online, missing remains unknown", async ({ page }, info) => {
|
|
await setup(page)
|
|
const interfaces = fixture.interfaces.slice(0, 1).map(row => ({ ...row, peers: Array.from({length:4}, (_, i) => ({ ...row.peers[0], id: "h"+i, rosId: "*H"+i, name: "Handshake "+i, latestHandshake: [undefined, "", "1h", "0s"][i] })) }))
|
|
await page.route("**/api/wireguard", route => route.fulfill({json:wgListResponseSchema.parse({interfaces})}))
|
|
await page.reload()
|
|
await expect(page.getByText("Пиров онлайн",{exact:true})).toHaveCount(0)
|
|
const label=page.getByText("Данные рукопожатия",{exact:true})
|
|
await expect(label.locator("..").locator("..")).toContainText("2/4")
|
|
await expect(page.getByText("Доступность пиров не проверена",{exact:true}).filter({visible:true})).toBeVisible()
|
|
await page.getByRole("button",{name:"Пиры: wg-test-1",exact:true}).click()
|
|
const detail=page.getByRole("region",{name:"Пиры: wg-test-1",exact:true})
|
|
await expect(detail.getByText("Нет данных",{exact:true})).toHaveCount(2)
|
|
await expect(detail.getByText("1h",{exact:true})).toBeVisible()
|
|
await page.getByRole("tab",{name:/Пиры/}).click()
|
|
const rows=page.locator("tr[data-row-id]")
|
|
await expect(rows).toHaveCount(4)
|
|
await expect(rows.nth(0)).toContainText("Нет данных");await expect(rows.nth(1)).toContainText("Нет данных")
|
|
await expect(rows.nth(2)).toContainText("1h");await expect(rows.nth(3)).toContainText("0s")
|
|
await page.setViewportSize({width:320,height:1000});expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)).toBe(true)
|
|
await page.addStyleTag({content:"nextjs-portal{display:none!important}"});await page.screenshot({path:info.outputPath("wireguard-handshake-320.png"),animations:"disabled"})
|
|
})
|