fix(ui): сохранить имя строки при прокрутке таблицы

This commit is contained in:
Denozordec committed 2026-10-04 04:38:23 +07:00
1 parent 5fbfc752fb
commit e0f83bdf42
15 files changed
+59 -12

No files matched your search

+4 -4
View File
@@ -1,7 +1,7 @@
import { test, expect } from "@playwright/test"
import { certificateRoutes, openIssue } from "./fixtures/certificate-issue"
import { certificate, certificateState } from "./fixtures/certificates"
for (const [name, width] of [["desktop", 1440], ["mobile", 390], ["narrow", 320]] as const) test("Сертификаты: клавиатура и адаптивность " + name, async ({ page }) => {
for (const [name, width] of [["desktop", 1440], ["mobile", 390], ["narrow", 320]] as const) test("Сертификаты: клавиатура и адаптивность " + name, async ({ page }, info) => {
await page.setViewportSize({ width, height: 900 }); await certificateRoutes(page)
const long = { ...certificate, name: "certificate-with-a-very-long-name-for-narrow-screens", commonName: "very-long-subdomain-for-responsive-layout.example.test", sans: ["very-long-alternative-domain-for-responsive-layout.example.test"] }
await page.route("**/api/certificates/state", r => r.fulfill({ json: certificateState([long]) }))
@@ -10,15 +10,15 @@ for (const [name, width] of [["desktop", 1440], ["mobile", 390], ["narrow", 320]
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth + 1)).toBe(true)
const detail = page.getByRole("button", { name: "Детали сертификата " + long.name, exact: true }); await detail.focus(); await page.keyboard.press("Enter")
await expect(detail).toHaveAttribute("aria-expanded", "true"); await expect(page.getByText("Доверие", { exact: true })).toBeVisible()
await page.screenshot({ path: "docs/ux-ui/screens/certificates-details-" + name + ".png", fullPage: true })
await page.screenshot({ path: info.outputPath("certificates-details-" + name + ".png"), fullPage: true })
await page.evaluate(() => { for (const element of document.querySelectorAll<HTMLElement>("*")) if (element.scrollTop > 0) element.scrollTop = 0 })
await page.screenshot({ path: "docs/ux-ui/screens/certificates-overview-" + name + ".png", fullPage: true })
await page.screenshot({ path: info.outputPath("certificates-overview-" + name + ".png"), fullPage: true })
await page.keyboard.press("Enter"); await expect(detail).toHaveAttribute("aria-expanded", "false")
const search = page.getByRole("textbox", { name: "Поиск по имени, CN, эмитенту…" }); await search.fill("нет-совпадений"); await expect(page.getByText("Нет совпадений", { exact: true })).toBeVisible(); await search.fill("")
const dialog = await openIssue(page)
await expect.poll(async () => { const box = await dialog.boundingBox(); return !!box && box.x >= 0 && box.x + box.width <= width + 1 && (width >= 640 || box.width >= width - 2) }).toBe(true)
expect(await dialog.evaluate(element => element.scrollWidth <= element.clientWidth + 1)).toBe(true)
await page.screenshot({ path: "docs/ux-ui/screens/certificates-issue-" + name + ".png", fullPage: true })
await page.screenshot({ path: info.outputPath("certificates-issue-" + name + ".png"), fullPage: true })
await page.keyboard.press("Escape"); await expect(dialog).toHaveCount(0)
await expect(page.getByRole("button", { name: "Выпустить сертификат", exact: true })).toBeFocused()
})
+6 -1
View File
@@ -44,12 +44,17 @@ test("Certificates1000: DOM, страницы, детали, поиск, refresh
await expect(scroll).toHaveCount(1)
expect(await scroll.evaluate(el => el.scrollWidth > el.clientWidth)).toBe(true)
await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth })
await expect.poll(() => scroll.evaluate(el => el.scrollLeft)).toBeGreaterThan(0)
const pinned = rows.first().getByRole("cell").first()
expect(await pinned.evaluate(el => { const cell = el.getBoundingClientRect(), viewport = el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(); return cell.left >= viewport.left - 1 && cell.right <= viewport.right + 1 })).toBe(true)
const statusValue = rows.first().getByText("Действителен", { exact: true })
expect(await statusValue.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)
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("table").getByRole("button", { name: "Сертификат", exact: true }).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)
+1
View File
@@ -42,6 +42,7 @@ test("Speed history200: DOM, сортировка, refresh, уменьшение
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.getByText("История тестов", { exact: true }).scrollIntoViewIfNeeded()
await page.screenshot({ path: "docs/ux-ui/screens/large-speed-history-320.png", animations: "disabled" })
runs = [runs[199]]; const previous = calls; await page.getByRole("button", { name: "Обновить", exact: true }).click()
await expect.poll(() => calls).toBeGreaterThan(previous)
+6 -1
View File
@@ -36,6 +36,9 @@ for (const width of [1440, 320]) test("Pivot51×16: границы, сортир
expect(await scroll.evaluate(el => el.scrollWidth > el.clientWidth)).toBe(true)
await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth })
await expect.poll(() => scroll.evaluate(el => el.scrollLeft)).toBeGreaterThan(0)
const pinned = rendered.first().getByRole("cell").first()
expect(await pinned.evaluate(el => { const cell = el.getBoundingClientRect(), viewport = el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(); return cell.left >= viewport.left - 1 && cell.right <= viewport.right + 1 })).toBe(true)
expect(await rendered.first().getByRole("cell").last().evaluate(el => { const total = el.getBoundingClientRect(), viewport = el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(), pinned = el.closest("tr")!.querySelector("td")!.getBoundingClientRect(); return total.left >= pinned.right - 1 && total.right <= viewport.right + 1 })).toBe(true)
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
await expect(rendered.first().getByRole("button")).toHaveCount(0)
await expect(rendered.nth(1).getByRole("cell").nth(16).getByRole("button")).toHaveCount(0)
@@ -46,7 +49,9 @@ for (const width of [1440, 320]) test("Pivot51×16: границы, сортир
mkdirSync("docs/ux-ui/screens", { recursive: true })
await page.screenshot({ path: "docs/ux-ui/screens/wide-statistics-pivot-" + width + ".png", animations: "disabled" })
const lastCell = rendered.nth(1).getByRole("cell").nth(15).getByRole("button")
await lastCell.focus(); await page.keyboard.press("Enter")
await lastCell.focus()
expect(await lastCell.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 page.keyboard.press("Enter")
await expect(page).toHaveURL(/view=explore/)
const selected = new URL(page.url()); expect(selected.searchParams.get("userId")).toBe("50"); expect(selected.searchParams.get("service")).toBe("service-15")
expect(reads.some(url => url.pathname === "/api/statistics" && url.searchParams.get("userId") === "50" && url.searchParams.get("service") === "service-15")).toBe(true)