From 586da55c2431a10b5227564e86696b01e2c358b0 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 4 Oct 2026 10:48:11 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BE=D0=B3=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D1=8C=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B0=20OSPF-=D0=BC=D0=B0=D1=80=D1=88=D1=80=D1=83?= =?UTF-8?q?=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data-grids/ospf-routes-data-grid.tsx | 30 ++++++++-- docs/ux-ui-performance.md | 2 + docs/ux-ui-plan.md | 2 +- docs/ux-ui-progress.md | 8 +++ docs/ux-ui-stage-12.md | 9 +++ docs/ux-ui/screens/large-ospf-routes-320.png | Bin 0 -> 62070 bytes tests/e2e/large-ospf-routes.spec.ts | 54 ++++++++++++++++++ 7 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 docs/ux-ui/screens/large-ospf-routes-320.png create mode 100644 tests/e2e/large-ospf-routes.spec.ts diff --git a/components/data-grids/ospf-routes-data-grid.tsx b/components/data-grids/ospf-routes-data-grid.tsx index bfa8670f..154334ea 100644 --- a/components/data-grids/ospf-routes-data-grid.tsx +++ b/components/data-grids/ospf-routes-data-grid.tsx @@ -1,8 +1,8 @@ "use client" -import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" +import { DataGridContainer, DataGridScrollArea, DataGridTable, dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" -import { useMemo } from "react" +import { useEffect, useMemo } from "react" import { type ColumnDef, useTable, @@ -49,11 +49,12 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { () => [ { id: "destination", + size: 150, accessorKey: "destination", header: ({ column }) => ( ), - cell: ({ row }) => {row.original.destination}, + cell: ({ row }) => {row.original.destination}, meta: { headerTitle: "Назначение", headerClassName: DATA_GRID_CELL_PAD_FIRST, @@ -62,6 +63,7 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { }, { id: "type", + size: 116, accessorKey: "type", header: ({ column }) => , cell: ({ row }) => ( @@ -78,6 +80,7 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { }, { id: "cost", + size: 80, accessorKey: "cost", header: ({ column }) => , cell: ({ row }) => ( @@ -104,6 +107,7 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { }, { id: "via", + size: 120, accessorKey: "via", header: ({ column }) => , cell: ({ row }) => ( @@ -128,6 +132,7 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { }, { id: "area", + size: 120, accessorKey: "area", header: ({ column }) => , cell: ({ row }) => ( @@ -145,12 +150,20 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) { const table = useTable({ features: dataGridFeatures, - manualPagination: true, + manualPagination: false, + autoResetPageIndex: false, + initialState: { pagination: { pageIndex: 0, pageSize: 50 }, columnPinning: { start: ["destination"], end: [] } }, data: routes, columns, getRowId: (row) => row.id, }) + const { pageIndex, pageSize } = table.state.pagination + useEffect(() => { + const lastPage = Math.max(0, Math.ceil(routes.length / pageSize) - 1) + if (pageIndex > lastPage) table.setPageIndex(lastPage) + }, [routes.length, pageIndex, pageSize, table]) + if (routes.length === 0) { return ( 50 || pageSize !== 50} tableClassNames={{ headerRow: "border-b border-border", bodyRow: "group/row hover:bg-muted/30" }} - tableLayout={{ dense: true }} - /> + tableLayout={{ dense: true, columnsPinnable: true }} + > + + + + ) } diff --git a/docs/ux-ui-performance.md b/docs/ux-ui-performance.md index 9e8fcf1d..5907a5fa 100644 --- a/docs/ux-ui-performance.md +++ b/docs/ux-ui-performance.md @@ -74,3 +74,5 @@ Statistics pivot в backend/src/services/statistics-aggregate.ts огранич 12.3.19:backups1000/171812 JSON bytes —1000→50 rows/43580→2462 DOM nodes/898ms dev ready. Whole-catalog search/Filters/URL/reload/page20/refresh/503 cache/1000→1/правильный filename/возврат focus/320px/axe приняты;39+4 browser/type/lint/build. Полный DB список ещё загружается, производительность PG не измерялась. 12.3.21: history200 остаётся50 DOM rows/2367 nodes/1150ms dev ready. Strict DTO и null rates приняты от pure DB mapper до grid/KPI/card;60+5 browser и unit4/builds. Это не проверка реального PostgreSQL/RouterOS. + +12.3.24:OSPF routes1000/200347 JSON bytes —50 DOM rows/1356 page nodes/930ms dev ready. Источник /ospf/catalog объединяет полный RouterOS ipRoutes без page/limit. Whole-catalog search/URL/reload/global Cost sort/page20/refresh/503 cache/1000→1/320px/видимость области/axe приняты;22+1 browser/type/lint/build. Полный DTO остаётся в памяти; скорость RouterOS не измерена. Осталось20 manualPagination:true specialized grids, включая demo/bounded источники; это не20 доказанных дефектов. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 171490d9..241b18d0 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -4,7 +4,7 @@ ## Актуальная точка продолжения — 2026-10-04 -Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. 12.3.10 принят локально:недоступные интерфейсы очищаются в обработчиках,54 browser/полный ESLint/production build прошли. 12.3.11 принят локально:ServerTileRail50 устройств/URL/поиск/клавиатура/две площадки/mobile Sheet/axe обе темы;47 browser и production build прошли. 12.3.12 принят локально:BGP ручная страница при выбранной URL сессии/refresh/reload,16 browser/build прошли. 12.4.1 записан:main1091 сценарий/1088 passed/3 устаревших fixtures; оба исправленных файла6 passed. 12.4.2 принят локально:context205/24 файла и unit28 прошли. 12.3.13 принят локально:wide pivot51×16/ScrollArea/axe/24+2 browser/builds. 12.3.14 принят локально:history200/50 DOM/54+1 browser/build. 12.3.15 принят локально:live расписание1000/page20 error cache/15 browser. 12.3.16 принят локально:certificates1000/50 DOM/refresh деталей/19+3 browser/build. 12.3.17 принят локально:pinning идентификатора/видимость значений/29 browser/build. 12.3.18 принят локально:users1000/поиск всего списка/детали и ошибка refresh/32 browser/build. 12.3.19 принят локально:backups1000/все мобильные действия/возврат focus/39+4 browser/build. 12.3.20 принят локально:независимые speed GET/cache/freshness/58+4 browser/build. 12.3.21 принят локально:strict history DTO/null rates от DB до UI/60+5 browser/unit4/builds. 12.4.3 принят локально:users/backups delta context36 на a558412. 12.3.22 принят локально:shared speed-probes DTO/context8/60+6+47 browser/unit5/builds. Следующий блок12.3.23:строгая транзакционная запись speed-probes; далее network grids и полная main/context регрессия.12.5 отдельно. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются. +Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. 12.3.10 принят локально:недоступные интерфейсы очищаются в обработчиках,54 browser/полный ESLint/production build прошли. 12.3.11 принят локально:ServerTileRail50 устройств/URL/поиск/клавиатура/две площадки/mobile Sheet/axe обе темы;47 browser и production build прошли. 12.3.12 принят локально:BGP ручная страница при выбранной URL сессии/refresh/reload,16 browser/build прошли. 12.4.1 записан:main1091 сценарий/1088 passed/3 устаревших fixtures; оба исправленных файла6 passed. 12.4.2 принят локально:context205/24 файла и unit28 прошли. 12.3.13 принят локально:wide pivot51×16/ScrollArea/axe/24+2 browser/builds. 12.3.14 принят локально:history200/50 DOM/54+1 browser/build. 12.3.15 принят локально:live расписание1000/page20 error cache/15 browser. 12.3.16 принят локально:certificates1000/50 DOM/refresh деталей/19+3 browser/build. 12.3.17 принят локально:pinning идентификатора/видимость значений/29 browser/build. 12.3.18 принят локально:users1000/поиск всего списка/детали и ошибка refresh/32 browser/build. 12.3.19 принят локально:backups1000/все мобильные действия/возврат focus/39+4 browser/build. 12.3.20 принят локально:независимые speed GET/cache/freshness/58+4 browser/build. 12.3.21 принят локально:strict history DTO/null rates от DB до UI/60+5 browser/unit4/builds. 12.4.3 принят локально:users/backups delta context36 на a558412. 12.3.22 принят локально:shared speed-probes DTO/context8/60+6+47 browser/unit5/builds. 12.3.23 принят локально:strict write DTO/atomic replacement/confirmed scheduler warning/65 browser/HTTP DI JWT/builds. 12.3.24 принят локально:OSPF routes1000/50 DOM/page20/cache/320px/22+1 browser/build. Следующий блок12.3.25:BFD sessions большого каталога; далее network grids и полная main/context регрессия.12.5 отдельно. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются. Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 3dac84b5..b1f14e04 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -36,6 +36,14 @@ +## 12.3.24 — большой каталог OSPF-маршрутов (2026-10-04) + +Аудит источника: /ospf/catalog опрашивает полный RouterOS ipRoutes и объединяет маршруты устройств без page/limit. Grid переведён на штатную TanStack v9 client pagination50; сортировка применяется ко всему отфильтрованному каталогу. Страница сохраняется при refresh и ограничивается при сокращении списка/поиске. Назначение закреплено штатным columnPinning start/end, горизонтальная прокрутка использует DataGridScrollArea. Подобраны ширины, чтобы значение области не перекрывалось на320px; длинный префикс переносится. + +1000 routes/200347 JSON bytes:50 DOM rows/1356 page nodes/930ms dev ready. Проверены page20, refresh, поиск дальнего маршрута/URL/reload, глобальная Cost сортировка,503 cache/unknown/freshness,1000→1 recovery,320px/no page overflow/полная видимость области/axe.22 профильных OSPF browser +1 после окончательной правки ширин прошли; lint/typecheck и production build прошли, мобильный снимок просмотрен. Ранние прогоны выявили неверное left API pinning (исправлено на v9 start/end) и две неверные предпосылки нового теста (ID и поле поиска); итоговые проверки прошли без ослабления assertions. Полный DTO остаётся в памяти, реальная задержка RouterOS не измерена. + +Следующий блок12.3.25: BFD sessions большого каталога OSPF,50 DOM rows/поиск/sort/cache/320px. После него оставшиеся network grids и общая матрица12.4; внешняя12.5 отдельно. Коммит локальный без push. + ## 12.3.23 — атомарная запись speed-проб (2026-10-04) Общий write DTO требует явный probes массив, уникальные ID, безопасные положительные ID устройств, разные источник/назначение, целую длительность от3 секунд, protocol/direction/enabled. Missing/null/malformed каталог отклоняется400 целиком до обращения к хранилищу; явный probes:[] сохраняет намеренное удаление последней записи. Измерения из запроса исключены и не перезаписывают подтверждённые наблюдения. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 5a4e5713..1e52f375 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -344,3 +344,12 @@ Backend заменяет каталог в одной Drizzle transaction с pg_ Следующий блок12.3.24: большой OSPF route catalog — аудит фактического источника, пагинация50, поиск/сортировка по полному списку, refresh/error/recovery и320px. Затем остальные network grids и общая матрица12.4. Коммит локальный без push. + +## 12.3.24 — большой каталог OSPF-маршрутов (2026-10-04) + +Аудит источника: /ospf/catalog опрашивает полный RouterOS ipRoutes и объединяет маршруты устройств без page/limit. Grid переведён на штатную TanStack v9 client pagination50; сортировка применяется ко всему отфильтрованному каталогу. Страница сохраняется при refresh и ограничивается при сокращении списка/поиске. Назначение закреплено штатным columnPinning start/end, горизонтальная прокрутка использует DataGridScrollArea. Подобраны ширины, чтобы значение области не перекрывалось на320px; длинный префикс переносится. + +1000 routes/200347 JSON bytes:50 DOM rows/1356 page nodes/930ms dev ready. Проверены page20, refresh, поиск дальнего маршрута/URL/reload, глобальная Cost сортировка,503 cache/unknown/freshness,1000→1 recovery,320px/no page overflow/полная видимость области/axe.22 профильных OSPF browser +1 после окончательной правки ширин прошли; lint/typecheck и production build прошли, мобильный снимок просмотрен. Ранние прогоны выявили неверное left API pinning (исправлено на v9 start/end) и две неверные предпосылки нового теста (ID и поле поиска); итоговые проверки прошли без ослабления assertions. Полный DTO остаётся в памяти, реальная задержка RouterOS не измерена. + +Следующий блок12.3.25: BFD sessions большого каталога OSPF,50 DOM rows/поиск/sort/cache/320px. После него оставшиеся network grids и общая матрица12.4; внешняя12.5 отдельно. Коммит локальный без push. + diff --git a/docs/ux-ui/screens/large-ospf-routes-320.png b/docs/ux-ui/screens/large-ospf-routes-320.png new file mode 100644 index 0000000000000000000000000000000000000000..9ba58e0abc85ee3b3df9c0c7443fcdbe7eef3cdb GIT binary patch literal 62070 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 w>o@<|a1Nf3kdU69a8sn4PR1DU<7djJ3c literal 0 HcmV?d00001 diff --git a/tests/e2e/large-ospf-routes.spec.ts b/tests/e2e/large-ospf-routes.spec.ts new file mode 100644 index 00000000..ac1db6b8 --- /dev/null +++ b/tests/e2e/large-ospf-routes.spec.ts @@ -0,0 +1,54 @@ +import { test, expect } from "@playwright/test" +import { ospfCatalogSchema } from "../../lib/ospf-response" +import axe from "axe-core" + +test("OSPF routes1000: full search/sort, page20, refresh/cache/shrink and320px", async ({ page }, info) => { + test.setTimeout(90000) + const server = { id: 1, name: "Роутер 1", host: "192.0.2.1", country: "RU", enabled: true, status: null } + let routes = Array.from({ length: 1000 }, (_, i) => ({ id: "*" + (i + 1), serverId: 1, serverName: "Роутер 1", serverSite: "", serverCountry: "RU", destination: "10." + Math.floor(i / 256) + "." + (i % 256) + ".0/24", type: "O" as const, cost: i + 1, nextHop: "192.0.2.2", via: "ether1", area: "backbone" })) + let failed = false, 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/ospf/catalog") { calls++; return r.fulfill(failed ? { status: 503, json: { error: "OSPF catalog unavailable" } } : { json: ospfCatalogSchema.parse({ neighbors: [], interfaces: [], instances: [], bfdSessions: [], routes, failures: [] }) }) } + return r.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : {} }) + }) + const started = Date.now(); await page.goto("/ospf?tab=routes&server=1&keep=1") + const rows = page.locator("tr[data-row-id]") + await expect(rows).toHaveCount(50) + const profile = { count: routes.length, jsonBytes: Buffer.byteLength(JSON.stringify(routes)), renderedRows: await rows.count(), nodes: await page.locator("*").count(), readyMs: Date.now() - started } + console.log("OSPF routes profile", JSON.stringify(profile)); await info.attach("profile", { body: JSON.stringify(profile), contentType: "application/json" }) + const next = page.getByRole("button", { name: "Следующая страница", exact: true }) + for (let i = 0; i < 19; i++) await next.click() + await expect(next).toBeDisabled(); await expect(rows.first()).toHaveAttribute("data-row-id", "1-*951") + const before = calls; await page.getByRole("button", { name: "Обновить", exact: true }).click() + await expect.poll(() => calls).toBeGreaterThan(before); await expect(rows.first()).toHaveAttribute("data-row-id", "1-*951") + const search = page.getByPlaceholder("Поиск в текущем разделе OSPF…") + await search.fill(routes[999].destination); await expect(rows).toHaveCount(1); await expect(rows.first()).toContainText(routes[999].destination) + await expect(page).toHaveURL(url => url.searchParams.get("q") === routes[999].destination && url.searchParams.get("keep") === "1") + await page.reload(); await expect(rows).toHaveCount(1) + await search.fill(""); await expect(rows).toHaveCount(50) + const costSort = page.getByRole("table").getByRole("button", { name: "Cost", exact: true }); await costSort.click() + await expect(rows.first()).toContainText(routes[999].destination) + await next.click(); const previousRow = await rows.first().getAttribute("data-row-id") + failed = true; await page.getByRole("button", { name: "Обновить", exact: true }).click() + const error = page.getByRole("alert").filter({ hasText: "Не удалось загрузить OSPF" }) + await expect(error).toContainText("Показаны последние полученные данные"); await expect(rows).toHaveCount(50); await expect(rows.first()).toHaveAttribute("data-row-id", previousRow!) + await expect(rows.first()).toContainText("Неизвестно") + 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 }); await expect.poll(() => scroll.evaluate(el => el.scrollLeft)).toBeGreaterThan(0) + expect(await rows.first().getByRole("cell").first().evaluate(el => { const a=el.getBoundingClientRect(),b=el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect();return a.left>=b.left-1&&a.right<=b.right+1 })).toBe(true) + expect(await rows.first().getByText("backbone", { exact: true }).evaluate(el => { const a=el.getBoundingClientRect(),b=el.closest('[data-slot="scroll-area-viewport"]')!.getBoundingClientRect(),p=el.closest("tr")!.querySelector("td")!.getBoundingClientRect();return a.left>=p.right-1&&a.right<=b.right+1 })).toBe(true) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) + await page.addScriptTag({ content: axe.source }) + expect((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"] } }))).violations).toEqual([]) + await page.addStyleTag({ content: "nextjs-portal { display: none !important; }" }) + await page.getByRole("table").getByRole("button", { name: "Назначение", exact: true }).scrollIntoViewIfNeeded() + await page.screenshot({ path: info.outputPath("ospf-routes-320.png"), animations: "disabled" }) + failed = false; routes = [routes[999]]; await error.getByRole("button", { name: "Повторить загрузку OSPF" }).click() + await expect(rows).toHaveCount(1); await expect(error).toHaveCount(0); await expect(rows.first()).toContainText(routes[0].destination) + expect(writes).toEqual([]) +})