Files
MikrotikManager/tests/e2e/gre-links.spec.ts
T

111 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect, type Page } from "@playwright/test"
async function setup(page: Page, url: string, failed = 0) {
const control = { partial: false, failed, posts: [] as { path: string; body: unknown }[] }
const servers = [{ id: 1, name: "Источник", host: "192.0.2.1", type: "exit-node", enabled: true, country: "RU", site: "TEST", asn: "64512", status: "online", latency: 1, os: "7", model: "CHR", sessions:0, wanUplinks: [] }]
const tunnels = ["1", "2"].flatMap(serverId => ["*/2", "other"].map(id => ({ id, serverId, name: "gre-same", localAddress: "192.0.2.1", remoteAddress: "192.0.2." + (serverId === "1" ? "11" : "22"), localInnerIp: "10.0.0.1/30", remoteInnerIp: "10.0.0.2/30", poolId: "live", ipsec: null, mtu: 1400, keepaliveInterval: 10, keepaliveRetries: 3, dscp: "inherit", clampTcpMss: true, allowFastPath: true, comment: "", enabled: true, status: "down" })));
servers.push({ ...servers[0], id: 2, name: "Второй сервер", host: "192.0.2.2" });
const probes = ["p1", "p/2"].map(id => ({ id, srcServerId: "1", name: "Проверка сети", target: "192.0.2.10", filter: "main", rtt: null, loss: 100, status: "down", series: [0], enabled: true, showOnDashboard: false }))
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
await page.route("**/api/**", route => {
const request = route.request()
const path = new URL(request.url()).pathname
if (request.method() === "POST") control.posts.push({ path, body: request.postDataJSON() })
if (path === "/api/gre/tunnels" && control.failed) return route.fulfill({ status: control.failed, json: { error: "Мониторинг недоступен" } })
const json = path === "/api/auth/config" ? { required: false }
: path === "/api/evobgp/settings" ? { enabled: false, baseUrl: "", secretConfigured: false }
: path === "/api/servers" ? servers
: path === "/api/uptime/overview" ? { probes:probes.map(p=>({...p,observations:{samples:[{sampledAt:"2026-09-20T00:00:00Z",rtt:null,loss:100,status:"down"}]}})),rangeStartAt:"2026-09-19T23:00:00Z",rangeEndAt:"2026-09-20T00:00:00Z",resources: [] }
: path === "/api/uptime/speed-probes" ? { probes: [] }
: path === "/api/uptime/speed-test/runs" ? { runs: [] }
: path === "/api/bgp/catalog" ? {sessions:[],failures:[]}
: path === "/api/gre/tunnels" || path === "/api/filters/gre-tunnels" ? { tunnels: control.partial ? tunnels.filter(t => t.serverId !== "2") : tunnels, failures: control.partial ? [{ serverId: "2", error: "Unavailable" }] : [] }
: path === "/api/vxlan" ? { tunnels: [],failures:[] }
: path === "/api/wireguard" ? { interfaces: [], peers: [],failures:[] }
: path === "/api/traffic/servers" ? { servers: [] }
: path === "/api/events" ? { events: [] }
: path === "/api/internet-path/latest" ? { snapshot: { collectionComplete:true,sampledAt: "2026-09-20T00:00:00Z", servers, greTunnels: [], filtersRulesets: [], speedProbes: [], routeLookupByServerId: {}, wanRuntimeByHomeId: {} } }
: {}
return route.fulfill({ json })
})
await page.goto(url)
return control
}
test("GRE: переход из очереди выбирает сервер и точный ID без записи", async ({ page }) => {
const control = await setup(page, "/dashboard")
const link = page.getByRole("region", { name: "Требует внимания", exact: true }).locator('a[href="/gre?server=2&tunnel=*%2F2"]')
await expect(link).toBeVisible()
await link.click()
const context = page.getByRole("status", { name: "GRE-туннель по ссылке" })
await expect(context).toContainText("Второй сервер")
await expect(page.locator("tr[data-row-id]")).toHaveCount(1)
await expect(page.locator("tr[data-row-id]")).toContainText("192.0.2.22")
expect(control.posts).toEqual([])
await context.getByRole("link", { name: "К дашборду", exact: true }).click()
await expect(link).toBeVisible()
})
test("GRE: прямая ссылка, сброс, назад, reload и ошибка обновления", async ({ page }) => {
const control = await setup(page, "/gre?server=2&tunnel=*%2F2&keep=1")
const context = page.getByRole("status", { name: "GRE-туннель по ссылке" })
const rows = page.locator("tr[data-row-id]")
await expect(rows).toHaveCount(1)
await context.getByRole("link", { name: "Все туннели сервера", exact: true }).click()
await expect(page).toHaveURL(/server=2&keep=1$/)
await expect(rows).toHaveCount(2)
await page.goBack()
await expect(rows).toHaveCount(1)
await page.reload()
await expect(context).toContainText("Второй сервер")
control.failed = 503
await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect(context).toContainText("сохранённые данные могут быть устаревшими")
await expect(rows).toHaveCount(1)
control.failed = 0
await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect(context).toContainText("Список ограничен")
control.partial = true
await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect(context).toContainText("Не удалось получить данные выбранного сервера")
await expect(rows).toHaveCount(1)
await expect(rows).toContainText("Неизвестно")
expect(control.posts).toEqual([])
await page.setViewportSize({ width: 390, height: 844 })
await context.scrollIntoViewIfNeeded()
const box = await context.boundingBox()
expect(box!.x + box!.width).toBeLessThanOrEqual(390)
await page.screenshot({ path: "test-results/gre-link-mobile.png", animations: "disabled" })
})
test("GRE: ручной выбор сервера снимает выбор туннеля и сохраняет query", async ({ page }) => {
const control = await setup(page, "/gre?server=2&tunnel=*%2F2&keep=1")
await expect(page.locator("tr[data-row-id]")).toHaveCount(1)
await page.getByRole("option").filter({ hasText: "Источник" }).click()
await expect(page).toHaveURL(/server=1&keep=1$/)
await expect(page.locator("tr[data-row-id]")).toHaveCount(2)
await expect(page.getByRole("status", { name: "GRE-туннель по ссылке" })).toHaveCount(0)
await page.goBack()
await expect(page.locator("tr[data-row-id]")).toHaveCount(1)
await expect(page.locator("tr[data-row-id]")).toContainText("192.0.2.22")
expect(control.posts).toEqual([])
})
for (const query of ["server=missing&tunnel=*%2F2", "server=2&tunnel=missing", "tunnel=*%2F2"]) {
test("GRE: нет подмены объекта " + query, async ({ page }) => {
const control = await setup(page, "/gre?" + query)
await expect(page.getByRole("status", { name: "GRE-туннель по ссылке" })).toContainText("Туннель не найден или недоступен")
await expect(page.locator("tr[data-row-id]")).toHaveCount(0)
expect(control.posts).toEqual([])
})
}
for (const status of [403, 500]) {
test("GRE: ошибка API " + status, async ({ page }) => {
const control = await setup(page, "/gre?server=2&tunnel=*%2F2", status)
await expect(page.getByRole("status", { name: "GRE-туннель по ссылке" })).toContainText("Не удалось получить данные выбранного сервера")
await expect(page.locator("tr[data-row-id]")).toHaveCount(0)
expect(control.posts).toEqual([])
})
}