Files

95 lines
5.2 KiB
TypeScript

import { existsSync, readdirSync } from "node:fs"
import { join } from "node:path"
import { test, expect, type Page } from "@playwright/test"
import { navigationItems } from "../../lib/navigation"
async function setup(page: Page) {
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/servers" ? []
: path === "/api/recursive-routes" ? { routes: [] }
: path === "/api/recursive-routes/gateways" ? { gateways: [] }
: path === "/api/auth/config" ? { required: false }
: path === "/api/evobgp/settings" ? { enabled: false, baseUrl: "", secretConfigured: false } : {} })
})
await page.goto("/recursive-routes")
await expect(page.getByRole("navigation", { name: "Путь страницы" })).toBeVisible()
}
test("каталог навигации покрывает существующие разделы без повторов и мёртвых ссылок", () => {
const root = join(process.cwd(), "app/(main)")
const pages = readdirSync(root).filter(name => existsSync(join(root, name, "page.tsx"))).map(name => `/${name}`)
expect(navigationItems.map(item => item.url).sort()).toEqual(pages.sort())
expect(new Set(navigationItems.map(item => item.id)).size).toBe(navigationItems.length)
expect(new Set(navigationItems.map(item => item.title)).size).toBe(navigationItems.length)
})
test("поиск страниц: одинаковые названия, синонимы, клавиатура и переход", async ({ page }) => {
await setup(page)
const sidebar = page.getByRole("navigation", { name: "Основная навигация" })
for (const item of navigationItems) {
await expect(sidebar.locator(`a[href="${item.url}"]`)).toContainText(item.title)
}
const opener = page.getByRole("button", { name: "Приложения", exact: true })
await opener.focus()
await page.keyboard.press("Control+k")
const dialog = page.getByRole("dialog", { name: "Поиск страниц", exact: true })
const input = dialog.getByRole("combobox", { name: "Поиск страниц", exact: true })
await expect(input).toBeFocused()
await expect(dialog.getByRole("option")).toHaveCount(navigationItems.length)
await input.press("ArrowDown")
await expect(dialog.getByRole("option", { name: "Трафик", exact: true })).toHaveAttribute("data-selected", "true")
await input.press("ArrowUp")
await expect(dialog.getByRole("option", { name: "Дашборд", exact: true })).toHaveAttribute("data-selected", "true")
await input.fill("uptime")
await expect(dialog.getByRole("option", { name: "Мониторинг", exact: true })).toBeVisible()
await input.fill("Несуществующийраздел999")
await expect(dialog.getByRole("status")).toContainText("Ничего не найдено")
await input.press("ArrowDown")
await input.press("Enter")
await expect(dialog).toBeVisible()
await page.keyboard.press("Tab")
await expect.poll(() => dialog.evaluate(element => element.contains(document.activeElement))).toBe(true)
await page.keyboard.press("Escape")
await expect(dialog).toBeHidden()
await expect(opener).toBeFocused()
await page.keyboard.press("Control+k")
await expect(input).toHaveValue("")
await input.fill("mikrotik")
await expect(dialog.getByRole("option", { name: "Серверы", exact: true })).toBeVisible()
await input.press("Enter")
await expect(page).toHaveURL(/\/servers$/)
await expect(dialog).toBeHidden()
await expect(sidebar.locator('a[href="/servers"]')).toHaveAttribute("aria-current", "page")
await page.goBack()
await expect(sidebar.locator('a[href="/recursive-routes"]')).toHaveAttribute("aria-current", "page")
})
for (const theme of ["dark", "light"]) {
test(`мобильное меню и поиск: тема ${theme}, низкий экран`, async ({ page }) => {
await page.addInitScript(value => localStorage.setItem("rl-theme", value), theme)
await page.setViewportSize({ width: 390, height: 600 })
await setup(page)
const menu = page.getByRole("button", { name: "Боковое меню", exact: true })
await menu.click()
const sidebar = page.getByRole("navigation", { name: "Основная навигация" })
await sidebar.locator('a[href="/servers"]').click()
await expect(page).toHaveURL(/\/servers$/)
await expect(page.getByRole("dialog")).toBeHidden()
await menu.click()
await expect(sidebar.locator('a[href="/servers"]')).toHaveAttribute("aria-current", "page")
await sidebar.locator('a[href="/servers"]').click()
await expect(page.getByRole("dialog")).toBeHidden()
await page.keyboard.press("Control+k")
const search = page.getByRole("dialog", { name: "Поиск страниц", exact: true })
await expect(search).toBeVisible()
const bounds = await search.boundingBox()
expect(bounds!.x).toBeGreaterThanOrEqual(0)
expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(390)
expect(bounds!.y).toBeGreaterThanOrEqual(0)
expect(bounds!.y + bounds!.height).toBeLessThanOrEqual(600)
await page.screenshot({ path: `test-results/navigation-mobile-${theme}.png`, animations: "disabled" })
})
}