Files
MikrotikManager/tests/e2e/large-certificates.spec.ts
T

59 lines
5.2 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 } from "@playwright/test"
import { certificatesStateSchema } from "../../packages/contracts/src/certificates"
import { certificate, certificateState, server } from "./fixtures/certificates"
import axe from "axe-core"
import { mkdirSync } from "node:fs"
test("Certificates1000: DOM, страницы, детали, поиск, refresh и320px", async ({ page }, info) => {
test.setTimeout(90000)
let certificates = Array.from({ length: 1000 }, (_, i) => ({ ...certificate, id: "1:*" + (i + 1), rosId: "*" + (i + 1), name: "cert-" + (i + 1), sans: ["alt" + (i + 1) + ".example.test"], daysLeft: 300 + i, validFrom: "2026-09-01T00:00:00Z", validUntil: new Date(Date.parse("2026-10-01T00:00:00Z") + (300 + i) * 86400000).toISOString(), trusted: true, status: "valid", keySize: 2048 }))
let calls = 0; const writes: string[] = []
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", r => {
const path = new URL(r.request().url()).pathname
if (r.request().method() !== "GET") writes.push(path)
if (path === "/api/certificates/state") calls++
return r.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : path === "/api/certificates/state" ? certificatesStateSchema.parse(certificateState(certificates)) : path === "/api/certificates/acme-settings" ? { directoryUrl: "https://acme.example.test/directory", tokenConfigured: false } : path === "/api/certificates/renew-settings" ? { enabled: false, intervalSec: 300, renewBeforeDays: 30 } : {} })
})
const start = Date.now(); await page.goto("/certificates?server=1")
const rows = page.locator("tr[data-row-id]")
await expect(page.getByText("cert-1", { exact: true })).toBeVisible()
const sample = { fixtureRows: 1000, fixtureBytes: Buffer.byteLength(JSON.stringify(certificateState(certificates))), renderedRows: await rows.count(), domNodes: await page.locator("*").count(), readyMs: Date.now() - start }
console.log(JSON.stringify(sample)); await info.attach("large-certificates-metrics", { body: JSON.stringify(sample), contentType: "application/json" })
expect(sample.renderedRows).toBe(50); expect(sample.domNodes).toBeLessThan(5000)
for (let i = 0; i < 3; i++) await page.getByRole("button", { name: "…", exact: true }).last().click()
await page.getByRole("button", { name: "Перейти на страницу 20", exact: true }).click()
const detail = page.getByRole("button", { name: "Детали сертификата cert-1000", exact: true })
await detail.focus(); await page.keyboard.press("Enter")
await expect(detail).toHaveAttribute("aria-expanded", "true")
await expect(page.getByText("alt1000.example.test", { exact: true })).toBeVisible()
const before = calls; await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect.poll(() => calls).toBeGreaterThan(before)
await expect(page.getByRole("button", { name: "Обновить", exact: true })).toBeEnabled()
await expect(page.getByText("951–1000 из 1000", { exact: true })).toBeVisible()
await expect(detail).toHaveAttribute("aria-expanded", "true")
const search = page.getByRole("textbox", { name: "Поиск по имени, CN, эмитенту…" })
await search.fill("cert-1000"); await expect(rows).toHaveCount(1)
await expect(page).toHaveURL(url => url.searchParams.get("q") === "cert-1000" && url.searchParams.get("server") === "1")
await page.reload(); await expect(rows).toHaveCount(1); await expect(search).toHaveValue("cert-1000")
await search.fill(""); await expect(rows).toHaveCount(50)
await page.getByRole("table").getByRole("button", { name: "Срок", exact: true }).click()
await expect(rows.first()).toHaveAttribute("data-row-id", "1:*1000")
await page.setViewportSize({ width: 320, height: 1000 })
const scroll = page.locator('[data-slot="data-grid"] [data-slot="scroll-area-viewport"]')
await expect(scroll).toHaveCount(1)
expect(await scroll.evaluate(el => el.scrollWidth > el.clientWidth)).toBe(true)
await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth })
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
await page.addScriptTag({ content: axe.source })
const audit = await page.evaluate(async () => (window as unknown as { axe: typeof axe }).axe.run(document.querySelector('[data-slot="data-grid"]')!, { runOnly: { type: "tag", values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"] } }))
expect(audit.violations).toEqual([])
await page.addStyleTag({ content: "nextjs-portal { display: none !important; }" }); mkdirSync("docs/ux-ui/screens", { recursive: true })
await page.getByRole("table").scrollIntoViewIfNeeded(); await page.screenshot({ path: "docs/ux-ui/screens/large-certificates-320.png", animations: "disabled" })
await page.getByRole("button", { name: "Следующая страница", exact: true }).click()
certificates = [certificates[999]]; const previous = calls; await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect.poll(() => calls).toBeGreaterThan(previous); await expect(rows).toHaveCount(1)
await expect(rows.first()).toHaveAttribute("data-row-id", "1:*1000")
expect(writes).toEqual([])
})