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"}) })