fix(ui): показывать достоверный снимок контейнера
This commit is contained in:
1 parent
c419a46955
commit
3ceb8c038c
14 files changed
+117
-141
No files matched your search
@@ -25,7 +25,7 @@ test("Контейнеры: частичный отказ устройства
|
||||
let fail=false;await page.route("**/api/containers/state",r=>r.fulfill({json:fail?state([],{availability:"error",failures:[{resource:"containers",error:"УСТРОЙСТВО ОТКАЗАЛО"}]}):state()}));await page.goto("/containers");await expect(page.getByText(container.name,{exact:true})).toBeVisible();fail=true;await refresh(page).click();await expect(page.getByRole("alert",{name:"Контейнеры сервера 1",exact:true})).toContainText("Последние контейнеры сохранены");await expect(page.getByText(container.name,{exact:true})).toBeVisible();await page.getByRole("button",{name:"Действия контейнера "+container.name}).click();await expect(page.getByRole("menuitem",{name:"Остановить",exact:true})).toBeDisabled()
|
||||
})
|
||||
test("Контейнеры: неизвестный статус и partial зависимости видимы",async({page})=>{
|
||||
await page.route("**/api/containers/state",r=>r.fulfill({json:state([{...container,status:"unknown",startOnBoot:null,image:"",tag:""}],{failures:[{resource:"envs",error:"ENVS ОТКАЗ"}]})}));await page.goto("/containers");await expect(page.getByText(container.name,{exact:true})).toBeVisible();await expect(page.getByText("Неизвестно",{exact:true})).toBeVisible();await expect(page.getByRole("alert",{name:"Контейнеры сервера 1"})).toContainText("ENVS ОТКАЗ")
|
||||
await page.route("**/api/containers/state",r=>r.fulfill({json:state([{...container,status:"unknown",startOnBoot:null,image:"",tag:""}],{failures:[{resource:"envs",error:"ENVS ОТКАЗ"}]})}));await page.goto("/containers");await expect(page.getByText(container.name,{exact:true})).toBeVisible();await expect(page.getByText("Неизвестно",{exact:true}).first()).toBeVisible();await expect(page.getByRole("alert",{name:"Контейнеры сервера 1"})).toContainText("ENVS ОТКАЗ")
|
||||
})
|
||||
test("Контейнеры: медленный каталог серверов не задерживает контейнеры",async({page})=>{
|
||||
let release!:()=>void;const gate=new Promise<void>(r=>release=r);await page.route("**/api/servers",async r=>{await gate;await r.fulfill({json:[server]}).catch(()=>{})});await page.goto("/containers");await expect(page.getByText(container.name,{exact:true})).toBeVisible();release();await expect(refresh(page)).toBeEnabled()
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import {test,expect} from "@playwright/test"
|
||||
import {container,server,state} from "./fixtures/containers"
|
||||
for(const [name,width] of [["desktop",1440],["mobile",390],["narrow",320]] as const)test("Контейнеры: клавиатура и адаптивность "+name,async({page})=>{
|
||||
await page.setViewportSize({width,height:900})
|
||||
const long={...container,name:"container-with-a-very-long-name-for-narrow-screens",image:"registry.example.test/project/long-container-image",comment:"Длинный комментарий для проверки переноса текста в карточке"}
|
||||
await page.route("**/health",r=>r.fulfill({json:{ok:true}}));await page.route("**/api/**",r=>r.fulfill({json:new URL(r.request().url()).pathname==="/api/auth/config"?{required:false}:new URL(r.request().url()).pathname==="/api/servers"?[{...server,name:"Очень длинное имя сервера контейнеров"}]:state([long])}))
|
||||
await page.goto("/containers");await expect(page.getByText(long.name,{exact:true})).toBeVisible();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth+1)).toBe(true)
|
||||
const search=page.getByRole("textbox",{name:"Поиск контейнеров"});await search.fill("нет-совпадений");await expect(page.getByText("Измените фильтр или поиск",{exact:true})).toBeVisible();await search.fill("")
|
||||
const stopped=page.getByRole("group",{name:"Статус контейнеров"}).getByRole("button",{name:"Остановлен",exact:true});await stopped.focus();await page.keyboard.press("Enter");await expect(stopped).toHaveAttribute("aria-pressed","true");const all=page.getByRole("group",{name:"Статус контейнеров"}).getByRole("button",{name:"Все",exact:true});await all.click();await expect(all).toHaveAttribute("aria-pressed","true")
|
||||
await page.screenshot({path:"docs/ux-ui/screens/containers-overview-"+name+".png",fullPage:true})
|
||||
const menu=page.getByRole("button",{name:"Действия контейнера "+long.name});await menu.focus();await page.keyboard.press("Enter");await page.getByRole("menuitem",{name:"Снимок JSON",exact:true}).click();const dialog=page.getByRole("dialog");await expect(dialog).toContainText("конфигурация устройства и резервная копия");await expect.poll(async()=>{const bounds=await dialog.boundingBox();return !!bounds&&bounds.x>=0&&bounds.x+bounds.width<=width+1&&(width>=640||bounds.width>=width-2)}).toBe(true);expect(await dialog.evaluate(el=>el.scrollWidth<=el.clientWidth+1)).toBe(true)
|
||||
const download=page.waitForEvent("download");await dialog.getByRole("button",{name:"Файл",exact:true}).click();const file=await download;expect(file.suggestedFilename()).toMatch(/\.json$/);const stream=await file.createReadStream();const chunks:Buffer[]=[];for await(const chunk of stream!)chunks.push(Buffer.from(chunk));const json=JSON.parse(Buffer.concat(chunks).toString("utf8"));expect(json.container.name).toBe(long.name);expect(json.collectedAt).toBe("2026-10-01T00:00:00Z");expect(json.source).toBe("live");expect(JSON.stringify(json)).not.toContain("172.17.0.2")
|
||||
await page.screenshot({path:"docs/ux-ui/screens/containers-export-"+name+".png",fullPage:true});await dialog.getByRole("button",{name:"Закрыть",exact:true}).first().click();await expect(dialog).toHaveCount(0)
|
||||
})
|
||||
test("Контейнеры: неизвестный статус не предлагает запуск",async({page})=>{
|
||||
await page.route("**/health",r=>r.fulfill({json:{ok:true}}));await page.route("**/api/**",r=>r.fulfill({json:new URL(r.request().url()).pathname==="/api/auth/config"?{required:false}:new URL(r.request().url()).pathname==="/api/servers"?[server]:state([{...container,status:"unknown"}])}));await page.goto("/containers");await page.getByRole("button",{name:"Действия контейнера "+container.name}).click();await expect(page.getByRole("menuitem",{name:"Запустить",exact:true})).toBeDisabled();await expect(page.getByRole("menuitem",{name:"Перезапустить",exact:true})).toBeDisabled()
|
||||
})
|
||||
@@ -16,7 +16,7 @@ test("Удаление контейнера: lock, Escape, один запрос
|
||||
for(const [name,path] of [["Остановить","stop"],["Запустить","start"],["Перезапустить","restart"]] as const)test("Команда контейнера: подтверждение отдельно от состояния "+path,async({page})=>{
|
||||
const initial={...container,status:path==="start"?"stopped":"running"}
|
||||
await page.route("**/api/containers/state",r=>r.fulfill({json:state([initial])}));let payload:unknown
|
||||
await page.route("**/api/servers/1/containers/"+path,r=>{payload=r.request().postDataJSON();return r.fulfill({json:{ok:true}})});await page.goto("/containers");await action(page,name);await expect(page.getByRole("status").filter({hasText:"API подтвердил команду"})).toBeVisible();expect(payload).toEqual({rosId:"*A"});await expect(page.getByText(path==="start"?"Stopped":"Running",{exact:true}).first()).toBeVisible()
|
||||
await page.route("**/api/servers/1/containers/"+path,r=>{payload=r.request().postDataJSON();return r.fulfill({json:{ok:true}})});await page.goto("/containers");await action(page,name);await expect(page.getByRole("status").filter({hasText:"API подтвердил команду"})).toBeVisible();expect(payload).toEqual({rosId:"*A"});await expect(page.getByText(path==="start"?"Остановлен":"Работает",{exact:true}).first()).toBeVisible()
|
||||
})
|
||||
for(const bad of [{ok:false},{},{ok:"true"}])test("Команда контейнера: неверное подтверждение "+JSON.stringify(bad),async({page})=>{
|
||||
await page.route("**/api/servers/1/containers/stop",r=>r.fulfill({json:bad}));await page.goto("/containers");await action(page,"Остановить");await expect(page.getByRole("alert",{name:"Команда контейнера"})).toContainText("Результат команды не подтверждён");await expect(page.getByRole("status").filter({hasText:"API подтвердил команду"})).toHaveCount(0);await page.getByRole("button",{name:"Действия контейнера "+container.name}).click();await expect(page.getByRole("menuitem",{name:"Остановить",exact:true})).toBeDisabled()
|
||||
|
||||
Reference in new issue
Block a user