Files

44 lines
6.0 KiB
TypeScript
Raw Permalink 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 { backupItemDtoSchema } from "../../packages/contracts/src/backups"
import { backup, setupBackups } from "./fixtures/backups"
import axe from "axe-core"
import { mkdirSync } from "node:fs"
test("Backups1000: весь поиск, страница при refresh, отказ и правильный файл", async ({ page }, info) => {
test.setTimeout(90000)
let catalog = Array.from({ length: 1000 }, (_, i) => backupItemDtoSchema.parse({ ...backup, id: "backup-" + (i + 1), filename: "config-" + String(i + 1).padStart(4, "0") + ".rsc", sizeBytes: (i + 1) * 1024 }))
let failed = false, calls = 0; const writes: string[] = []
await setupBackups(page)
await page.route("**/api/**", r => { if(r.request().method() !== "GET") writes.push(r.request().method() + " " + new URL(r.request().url()).pathname); return r.fallback() })
await page.route("**/api/backups", r => { calls++; return r.fulfill(failed ? { status: 503, json: { error: "История недоступна" } } : { json: catalog }) })
const start = Date.now(); await page.goto("/backups")
const rows = page.locator("tr[data-row-id]"); await expect(page.getByText("config-0001.rsc", { exact: true })).toBeVisible()
const sample = { fixtureRows: 1000, fixtureBytes: Buffer.byteLength(JSON.stringify(catalog)), renderedRows: await rows.count(), domNodes: await page.locator("*").count(), readyMs: Date.now() - start }
console.log(JSON.stringify(sample)); await info.attach("large-backups-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 refresh = page.getByRole("button", { name: "Обновить", exact: true }); const before = calls; await refresh.click(); await expect.poll(() => calls).toBeGreaterThan(before); await expect(refresh).toBeEnabled()
await expect(page.getByText("951–1000 из 1000", { exact: true })).toBeVisible()
failed = true; await refresh.click(); await expect(page.getByRole("alert", { name: "Данные резервных копий: backups", exact: true })).toContainText("Последние данные сохранены"); await expect(rows).toHaveCount(50)
failed = false; await refresh.click(); await expect(page.getByRole("alert", { name: "Данные резервных копий: backups", exact: true })).toHaveCount(0)
const search = page.getByPlaceholder("Поиск по файлу, серверу, заметке…"); await search.fill("config-1000"); await expect(rows).toHaveCount(1); await expect(page).toHaveURL(/q=config-1000/)
await page.reload(); await expect(rows).toHaveCount(1); await expect(rows.first()).toHaveAttribute("data-row-id", "backup-1000"); await search.fill(""); await expect(rows).toHaveCount(50)
await page.getByRole("button", { name: "Размер", exact: true }).click(); await expect(rows.first()).toHaveAttribute("data-row-id", "backup-1000")
await page.setViewportSize({ width: 320, height: 1000 })
const scroll = page.locator('[data-slot="data-grid"] [data-slot="scroll-area-viewport"]'); await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth })
for (const action of ["Скачать", "Восстановить", "Удалить"]) {
const button = rows.first().getByRole("button", { name: action + " config-1000.rsc", exact: true })
// ReUI buttons animate from desktop icon size to their mobile touch target.
await expect.poll(() => button.evaluate(el => { const box=el.getBoundingClientRect(), viewport=el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(), pinned=el.closest("tr")!.querySelector("td")!.getBoundingClientRect(); return box.width >= 44 && box.height >= 44 && box.left >= pinned.right-1 && box.right <= viewport.right+1 })).toBe(true)
}
const restore = rows.first().getByRole("button", { name: "Восстановить config-1000.rsc", exact: true }); await restore.focus(); await page.keyboard.press("Enter"); await expect(page.getByRole("alertdialog")).toContainText("config-1000.rsc"); await page.getByRole("alertdialog").getByRole("button", { name: "Отмена", exact: true }).click(); await expect(restore).toBeFocused()
const remove = rows.first().getByRole("button", { name: "Удалить config-1000.rsc", exact: true })
expect(await remove.evaluate(el => { const value=el.getBoundingClientRect(), viewport=el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(), pinned=el.closest("tr")!.querySelector("td")!.getBoundingClientRect(); return value.left >= pinned.right-1 && value.right <= viewport.right+1 })).toBe(true)
await remove.focus(); await page.keyboard.press("Enter"); await expect(page.getByRole("alertdialog")).toContainText("config-1000.rsc"); await page.getByRole("alertdialog").getByRole("button", { name: "Отмена", exact: true }).click(); await expect(remove).toBeFocused()
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-backups-320.png",animations:"disabled"})
await page.getByRole("button",{name:"Следующая страница",exact:true}).click(); catalog=[catalog[999]]; const previous=calls; await refresh.click(); await expect.poll(() => calls).toBeGreaterThan(previous); await expect(rows).toHaveCount(1); await expect(rows.first()).toHaveAttribute("data-row-id","backup-1000"); expect(writes).toEqual([])
})