fix(ui): завершить локальную приёмку администрирования
No files matched your search
@@ -2577,10 +2577,10 @@ function AlertsContent() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── main layout ── */}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_300px] gap-5 items-start">
|
||||
|
||||
{/* ── rules card ── */}
|
||||
</>:null}
|
||||
<div className={cn("grid gap-5 items-start",known?"grid-cols-1 xl:grid-cols-[minmax(0,1fr)_300px]":"grid-cols-1")}>
|
||||
<div className="min-w-0 flex flex-col gap-5">
|
||||
{known?<>
|
||||
<OpsPanel
|
||||
title={
|
||||
<span className="flex items-center gap-2">
|
||||
@@ -2629,14 +2629,20 @@ function AlertsContent() {
|
||||
</div>
|
||||
</OpsPanel>
|
||||
|
||||
{/* ── right sidebar ── */}
|
||||
</>:null}
|
||||
{isLive?<AlertsOutboxPanel base={backendUrl} available={backendStatus===true} operationsBusy={operationBusy} beginOperation={beginOperation} endOperation={endOperation}/>:null}
|
||||
{isLive?<AlertsTargetsStatus catalogs={catalogs}/>:null}
|
||||
</div>
|
||||
{known?
|
||||
<div className="flex flex-col gap-5">
|
||||
<AlertsTelegramForm initial={tg} tokenConfigured={tokenConfigured} base={backendUrl} live={isLive} available={backendStatus===true&&!operationBusy}
|
||||
onBegin={beginOperation} onEnd={endOperation}
|
||||
onSaved={(value,configured)=>{setTg(value);setTokenConfigured(configured)}}/>
|
||||
<HistoryCard entries={history} />
|
||||
</div>
|
||||
:null}
|
||||
</div>
|
||||
{known?<>
|
||||
{/* ── presets + groups (свёрнуто по умолчанию) ── */}
|
||||
<Collapsible open={extrasExpanded} onOpenChange={setExtrasExpanded} className="rounded-lg border border-border bg-card shadow-sm">
|
||||
<CollapsibleTrigger
|
||||
@@ -2765,8 +2771,6 @@ function AlertsContent() {
|
||||
</Collapsible>
|
||||
|
||||
</>:null}
|
||||
{isLive?<AlertsTargetsStatus catalogs={catalogs}/>:null}
|
||||
{isLive?<AlertsOutboxPanel base={backendUrl} available={backendStatus===true} operationsBusy={operationBusy} beginOperation={beginOperation} endOperation={endOperation}/>:null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-03
|
||||
|
||||
Этап 11Б в работе; последний проверенный блок 11Б.6; Releases/probe schedule приняты локально. Следующий блок 11Б.7: сводная локальная регрессия оповещений, scheduler/integrations/settings/DB/releases/probe schedule, итоговый список внешних ограничений и production build; затем начать этап 12. Processing recovery без доказуемой остановки всех отправителей остаётся недоступен.
|
||||
Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. Следующий блок 12.1: общий shell — автоматический аудит доступности/клавиатура/фокус на ПК и320px в обеих темах, согласовать health popover с shared health; затем strict/partial источники dashboard, производительность и сквозная регрессия. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
|
||||
|
||||
Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md).
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
| 9 | VPN, Firewall и Filters | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
|
||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | В работе: 11Б.1–11Б.6; scheduler и GeoIP приняты локально; NetFlow принят локально; Evolution принят локально; далее общие Settings |
|
||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
|
||||
|
||||
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
|
||||
|
||||
## Блок 11Б.7 — сводная локальная приёмка администрирования (2026-10-03)
|
||||
|
||||
- 189 browser, 68 context/source, 61 unit/contracts/API и7 named backend profiles прошли. После финальной композиции Alerts дополнительно16 reader/targets/queue и25 form/preview/layout,14 Alerts source прошли. Frontend/contracts production build и backend build прошли; финальная frontend build после композиции тоже прошла. Lint/typecheck профильных изменений прошли.
|
||||
- Очередь и каталоги теперь идут сразу под правилами в основной колонке, до Telegram на телефоне; перестройка не зависит от known основной загрузки. Новый delayed-primary тест доказывает один GET очереди при unknown→known без remount. Desktop/mobile screenshots просмотрены.
|
||||
- Добавлен единый administration-context профиль;39 снимков сохранены/обновлены в репозитории. Таблица результатов/референсы/схемы в docs/ux-ui-stage-11b.md; подготовлен план приёмки12. Установленные ReUI primitives/base-nova сохранены, checklist применён; полного WCAG соответствия не заявляем.
|
||||
- Локальная приёмка11Б завершена с явными исключениями: BGP-prefix evaluator/live GRE schedule/processing recovery не реализованы, UI не выдаёт их за работающие. CAS retry разрешён толькоunknown с принятием риска; processing удерживается. Реальные migrations0008/0009, PG isolation/rollback/CAS, restore/UDP workers, RouterOS/Telegram/MaxMind/Portal/Evolution/CI требуют внешней приёмки. Backend legacy speed DTO normalization не перепринята.
|
||||
- Следующий блок 12.1: общий shell — автоматический аудит доступности/клавиатура/фокус на ПК и320px в обеих темах, согласовать health popover с shared health; затем strict/partial источники dashboard, производительность и сквозная регрессия. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
|
||||
|
||||
## Блок 11Б.6 — достоверное расписание проб скорости (2026-10-03)
|
||||
|
||||
- Live schedule reader выделен из диагностики, ждёт auth config и проверяет uptime:read до запроса/публикации. Strict required DTO/unique IDs/nullable finite metrics, no-store, 30s deadline, abort/lifetime/revision и source-key parent. Первоначальный сбой остаётся unknown, повтор явный; фоновая ошибка сохраняет подтверждённый список/время.
|
||||
|
||||
@@ -332,3 +332,24 @@ Releases strict metadata/unknown/local/безопасные ссылки и curr
|
||||
### Продолжение 2026-10-03 — 11Б.6
|
||||
|
||||
Live probe schedule strict read/own permissions/last good/retry/deadline/source и unknown TX/RX принят локально; demo tunnel selection исправлен. Unit2/browser36+8/context8/typecheck/lint/ReUI audit прошли, screenshot320 просмотрен. Реальный collector/legacy backend normalization не переприняты. Следующий блок 11Б.7: сводная локальная регрессия оповещений, scheduler/integrations/settings/DB/releases/probe schedule, итоговый список внешних ограничений и production build; затем начать этап 12. Processing recovery без доказуемой остановки всех отправителей остаётся недоступен.
|
||||
|
||||
## Сводная локальная приёмка — 11Б.7 (2026-10-03)
|
||||
|
||||
| Группа | Локальный результат | Осталось вне этой проверки |
|
||||
| --- | --- | --- |
|
||||
| Scheduler / сбор данных | Независимые known/error/time, dirty/selective save, общий lock, receipt partial/fatal, source isolation | Реальное выполнение collectors, PG journal/rollback и UDP lifecycle |
|
||||
| GeoIP / NetFlow / Evolution | Reader/permissions, формы и секреты, unknown checkpoints, подтверждённый результат | MaxMind/RIPE, IPFIX/WireGuard export, Portal и upstream provider |
|
||||
| System DB | Выбор файла отделён от restore, backup bytes/metadata, один запрос, предупреждения и неизвестный результат | Реальные pg_dump/pg_restore, rollback и остановка всех workers |
|
||||
| Alerts | Rules/groups revision/If-Match, форма/права, независимые каталоги/очередь, Telegram API acceptance, CAS retry только unknown | PG migrations 0008/0009, isolation/CAS/rollback, реальные Telegram; processing recovery и BGP-prefix не реализованы |
|
||||
| Releases | Strict manifest, unknown/local/mismatch, безопасные ссылки, только current production announcement | Реальная публикация CI/Gitea |
|
||||
| Probe schedule | Strict read, uptime:read, retry/time/source, nullable TX/RX | Реальное выполнение uptime speed worker; backend legacy normalization не перепринята |
|
||||
|
||||
Схема финального Alerts: сводка → правила → очередь → каталоги; справа Telegram/журнал, затем пресеты/подсказки. На телефоне очередь идёт перед Telegram; независимые readers остаются смонтированы при unknown → known основной загрузки.
|
||||
|
||||
| Экран | ПК | Телефон | Референс |
|
||||
| --- | --- | --- | --- |
|
||||
| Alerts | [Экран](ux-ui/screens/alerts-overview-1440.png) | [Экран](ux-ui/screens/alerts-overview-320.png) | [List 9](https://reui.io/preview/base/list-9?ref=mcp), [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp) |
|
||||
| Releases | [Экран](ux-ui/screens/releases-local-1440.png) | [Экран](ux-ui/screens/releases-local-320.png) | [List 9](https://reui.io/preview/base/list-9?ref=mcp) |
|
||||
| Probe schedule | [Экран](ux-ui/screens/probes-speed-schedule-1440.png) | [Экран](ux-ui/screens/probes-speed-schedule-320.png) | [Data Grid](https://reui.io/components/data-grid?ref=mcp) |
|
||||
|
||||
Сводная регрессия: 189 browser, 68 source/context, 61 unit/contracts/API и 7 named backend profiles прошли. После заключительной компоновки Alerts дополнительные16 reader/targets/queue,25 forms/layout/preview,14 source и финальная production build прошли. Backend build тоже прошла.39 снимков сохранены в репозитории; итог фиксируется в начале журнала. Браузерные тесты подменяют HTTP; backend DI/HTTP используют тестовые зависимости. Это не доказательство работы внешних систем или полного соответствия WCAG. SQL миграции локально не применялись, push/deploy не выполнялись.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
| Блок | Проверка и результат | Критерий остановки |
|
||||
| --- | --- | --- |
|
||||
| 12.1 | Общая оболочка, автоматический аудит доступности, клавиатура/фокус, 320px/ПК и обе темы | Исправлены доказанные нарушения, непроверенные состояния перечислены |
|
||||
| 12.2 | Достоверность источников дашборда: неполный BGP, nullable counters/traffic, неверные DTO | Unknown/partial не становятся zero/down/empty; last good сохраняется |
|
||||
| 12.3 | Производительность больших списков и таблиц на фиксированных локальных данных | Записаны размер fixture, измерения и практические ограничения |
|
||||
| 12.4 | Сквозная регрессия интерфейса, права, context; production/contracts/backend builds и ReUI checklist | Итоговая матрица с результатами и точными исключениями |
|
||||
| 12.5 | Внешняя приёмка PG/RouterOS/Telegram/интеграций | Протокол тестового окружения; локальные моки не заменяют эту проверку |
|
||||
|
||||
Сначала воспроизвести предполагаемые проблемы общей оболочки: health popover принимает только status:ok, тогда как shared health допускает подтверждённый legacy ok:true; проверить согласованность. Проверить реальные accessible names header triggers и skip link focus. Использовать установленный axe-core для автоматической части; отсутствие violations не означает полного соответствия или замену screen reader/manual проверки.
|
||||
|
||||
Клавиатурный сценарий должен предоставлять эквивалент действий мышью ([W3C SC 2.1.1](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html)); программные имена/роли/состояния проверяются отдельно ([W3C SC 4.1.2](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html)). Проверка reflow включает 320 CSS px; широкие таблицы проверяются как отдельные области прокрутки, а не как разрешение переполнения страницы ([W3C SC 1.4.10](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html)).
|
||||
|
||||
Внешние ограничения 11Б сохраняются: migrations0008/0009, PG isolation/CAS/rollback, реальный restore/UDP workers, RouterOS, Telegram, MaxMind/RIPE, Portal/Evolution, CI/Gitea. Processing не разрешается повторять без доказуемой остановки всех отправителей; timeout или checkbox не являются таким доказательством. BGP-prefix evaluator отсутствует и честно обозначен UI; отдельного live GRE расписания нет. Производственный выпуск не разрешён одним успешным browser/DI прогоном.
|
||||
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,5 @@
|
||||
import {defineConfig} from "@playwright/test"
|
||||
import base from "./playwright.config"
|
||||
const server=base.webServer
|
||||
if(!server||Array.isArray(server))throw new Error("Ожидается один локальный сервер")
|
||||
export default defineConfig({...base,use:{...base.use,baseURL:"http://127.0.0.1:3101"},testIgnore:[],testMatch:["alerts-context.spec.ts","data-collection-context.spec.ts","evobgp-context.spec.ts","geoip-context.spec.ts","netflow-context.spec.ts","settings-context.spec.ts","system-database-context.spec.ts","probes-context.spec.ts"],webServer:{...server,command:"node node_modules/next/dist/bin/next dev --hostname 127.0.0.1 --port 3101",url:"http://127.0.0.1:3101",env:{...server.env,NEXT_PUBLIC_BACKEND_URL:"local"}}})
|
||||
@@ -15,7 +15,14 @@ for(const width of [320,1440])test("Alerts rules priority, accessible filters an
|
||||
const name=page.getByText("Fixture rule",{exact:true});await expect(name).toBeVisible();expect((await name.boundingBox())!.width).toBeGreaterThan(100)
|
||||
const position=await search.boundingBox();const catalogs=await page.getByText("Каталоги целей",{exact:true}).boundingBox();const queue=await page.getByRole("region",{name:"Очередь Telegram"}).boundingBox()
|
||||
expect(position!.y).toBeLessThan(catalogs!.y);expect(position!.y).toBeLessThan(queue!.y)
|
||||
if(width===320){const telegram=await page.getByRole("region",{name:"Параметры Telegram"}).boundingBox();expect(queue!.y).toBeLessThan(telegram!.y)}else expect(queue!.y).toBeLessThan(900)
|
||||
await search.scrollIntoViewIfNeeded();await expect(search).toBeInViewport()
|
||||
expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true)
|
||||
await page.screenshot({path:"test-results/alerts-layout-"+width+".png",fullPage:true})
|
||||
await page.screenshot({path:"docs/ux-ui/screens/alerts-overview-"+width+".png",fullPage:true})
|
||||
})
|
||||
|
||||
test("Alerts queue remains mounted when delayed primary snapshot becomes known",async({page})=>{
|
||||
let started=false,calls=0,release!:()=>void;const gate=new Promise<void>(resolve=>release=resolve)
|
||||
await page.route("**/health",r=>r.fulfill({json:{status:"ok"}}));await page.route("**/api/**",async r=>{const path=new URL(r.request().url()).pathname;if(path==="/api/alerts"){started=true;await gate;return r.fulfill({json:alertsWithRule})}if(path==="/api/alerts/outbox")calls++;return r.fulfill({json:path==="/api/auth/config"?{required:false}:path==="/api/alerts/outbox"?emptyOutbox:path==="/api/filters/gre-tunnels"?{tunnels:[],failures:[]}:[]})})
|
||||
try{await page.goto("/alerts");await expect.poll(()=>started).toBe(true);await expect(page.getByRole("region",{name:"Очередь Telegram"})).toBeVisible();await expect.poll(()=>calls).toBe(1);release();await expect(page.getByRole("textbox",{name:"Поиск правил",exact:true})).toBeVisible();expect(calls).toBe(1)}finally{release()}
|
||||
})
|
||||
@@ -7,6 +7,6 @@ test("Probe schedule refresh preserves confirmed rows and missing RX does not be
|
||||
test("Probe schedule timeout is retryable without automatic request",async({page})=>{await page.clock.install();await setup(page);let calls=0;await page.route("**/api/uptime/speed-probes",()=>{calls++});const panel=await open(page);await expect.poll(()=>calls).toBe(1);await page.clock.fastForward(30100);await expect(panel.getByRole("alert")).toContainText("Время ожидания");await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeEnabled();expect(calls).toBe(1)})
|
||||
test("Probe schedule respects its own uptime permission",async({page})=>{await setup(page);const claims={sub:"fixture",apps:["mm"],permissions:["mm:servers:read"],exp:Math.floor(Date.now()/1000)+3600};const token="e30."+Buffer.from(JSON.stringify(claims)).toString("base64url")+".fixture";await page.addInitScript(value=>localStorage.setItem("mmapp_token",value),token);await page.route("**/api/auth/config",r=>r.fulfill({json:{required:true}}));let calls=0;await page.route("**/api/uptime/speed-probes",r=>{calls++;return r.fulfill({json:{probes:[]}})});const panel=await open(page);await expect(panel.getByRole("alert")).toContainText("Нет права читать пробы скорости");expect(calls).toBe(0)})
|
||||
|
||||
for(const width of [320,1440])test("Probe schedule known rows fit/"+width,async({page})=>{await setup(page);await page.setViewportSize({width,height:900});await page.route("**/api/uptime/speed-probes",r=>r.fulfill({json:{probes:[{...probe,lastRunAt:"2026-10-03T00:00:00Z"}]}}));const panel=await open(page);await expect(panel.getByText(/RX: неизвестно/)).toBeVisible();await panel.scrollIntoViewIfNeeded();await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeInViewport();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true);await panel.screenshot({path:"test-results/probes-schedule-"+width+".png"})})
|
||||
for(const width of [320,1440])test("Probe schedule known rows fit/"+width,async({page})=>{await setup(page);await page.setViewportSize({width,height:900});await page.route("**/api/uptime/speed-probes",r=>r.fulfill({json:{probes:[{...probe,lastRunAt:"2026-10-03T00:00:00Z"}]}}));const panel=await open(page);await expect(panel.getByText(/RX: неизвестно/)).toBeVisible();await panel.scrollIntoViewIfNeeded();await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeInViewport();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true);await panel.screenshot({path:"docs/ux-ui/screens/probes-speed-schedule-"+width+".png"})})
|
||||
|
||||
test("Demo schedule clears a tunnel from another device and selects a valid one",async({page})=>{await setup(page);await page.addInitScript(()=>localStorage.setItem("routerlists:data-source","mock"));await page.goto("/probes?server=srv1");await page.getByRole("button",{name:"Расписание",exact:true}).click();await page.getByRole("button",{name:"Добавить правило",exact:true}).click();const server=page.getByRole("combobox",{name:"Устройство расписания"}),tunnel=page.getByRole("combobox",{name:"Туннель расписания"});await expect(tunnel).toHaveValue("gre1");await server.selectOption("srv2");await expect(tunnel).toHaveValue("");await expect(page.getByRole("button",{name:"Добавить",exact:true})).toBeDisabled();await server.selectOption("srv7");await expect(tunnel).toHaveValue("gre5");await expect(page.getByRole("button",{name:"Добавить",exact:true})).toBeEnabled()})
|
||||
@@ -9,7 +9,7 @@ for(const width of [320,1440])test("Releases local build is not presented as pub
|
||||
await expect(page.getByText("Сводка коммитов",{exact:true})).toBeVisible()
|
||||
await expect(page.getByRole("link",{name:"Открыть релиз",exact:true})).toHaveCount(0)
|
||||
expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true)
|
||||
await page.screenshot({path:"test-results/releases-local-"+width+".png",fullPage:true})
|
||||
await page.screenshot({path:"docs/ux-ui/screens/releases-local-"+width+".png",fullPage:true})
|
||||
})
|
||||
|
||||
// Server component reads a local manifest. Restore the original bytes even on assertion failure.
|
||||
|
||||