import { test, expect, type Page } from "@playwright/test" import {user,server,catalogResponse} from "./fixtures/users" async function routes(page:Page){ await page.route("**/health",r=>catalogResponse(r, {json:{ok:true}})) await page.route("**/api/**",r=>{const path=new URL(r.request().url()).pathname;return catalogResponse(r, {json:path==="/api/users"?{users:[user]}:path==="/api/servers"?[server]:path==="/api/auth/config"?{required:false}:{interfaces:[]}})}) } test.beforeEach(async({page})=>routes(page)) const add=(page:Page)=>page.getByRole("button",{name:"Добавить пользователя",exact:true}) const refresh=(page:Page)=>page.getByRole("button",{name:"Обновить пользователей",exact:true}) for(const kind of ["API","malformed","duplicate"] as const)test("Пользователи: первоначальный отказ "+kind,async({page})=>{ let fail=true;await page.route("**/api/users",r=>catalogResponse(r, fail?(kind==="API"?{status:503,json:{error:"Отказ пользователей"}}:{json:{users:kind==="duplicate"?[user,user]:[{}]}}):{json:{users:[user]}})) await page.goto("/users");await expect(page.getByRole("alert",{name:"Пользователи",exact:true})).toContainText("Пользователи пока неизвестны");await expect(page.getByText("Нет пользователей",{exact:true})).toHaveCount(0);await expect(add(page)).toBeDisabled();await expect(page.getByText("Алексей Коротaев",{exact:true})).toHaveCount(0) fail=false;await refresh(page).click();await expect(page.getByText(user.name,{exact:true})).toBeVisible();await expect(add(page)).toBeEnabled();await expect(page.getByRole("alert",{name:"Пользователи",exact:true})).toHaveCount(0) }) for(const kind of ["API","malformed","duplicate"] as const)test("Пользователи: независимый отказ серверов "+kind,async({page})=>{ let fail=true;await page.route("**/api/servers",r=>catalogResponse(r, fail?(kind==="API"?{status:403,json:{error:"Серверы запрещены"}}:{json:kind==="duplicate"?[server,server]:[{}]}):{json:[server]})) await page.goto("/users");await expect(page.getByText(user.name,{exact:true})).toBeVisible();await expect(page.getByRole("alert",{name:"Серверы пользователей"})).toContainText("Каталог серверов пока неизвестен");await expect(add(page)).toBeDisabled() await page.getByText(user.name,{exact:true}).click();await expect(page.getByText("каталог неизвестен",{exact:true})).toBeVisible() fail=false;await refresh(page).click();await expect(add(page)).toBeEnabled();await expect(page.getByRole("alert",{name:"Серверы пользователей"})).toHaveCount(0) }) test("Пользователи: подтверждённый пустой список и нули",async({page})=>{ await page.route("**/api/users",r=>catalogResponse(r, {json:{users:[]}}));await page.goto("/users");await expect(page.getByText("Нет пользователей",{exact:true})).toBeVisible();await expect(add(page)).toBeEnabled();await expect(page.getByRole("alert",{name:"Пользователи",exact:true})).toHaveCount(0) }) for(const part of ["users","servers"])test("Пользователи: фоновый отказ сохраняет снимок "+part,async({page})=>{ let fail=false;await page.route("**/api/"+part,r=>catalogResponse(r, fail?{status:503,json:{error:"ФОНОВЫЙ ОТКАЗ"}}:{json:part==="users"?{users:[user]}:[server]})) await page.goto("/users");await expect(add(page)).toBeEnabled();fail=true;await refresh(page).click();await expect(page.getByText("ФОНОВЫЙ ОТКАЗ",{exact:true})).toBeVisible();await expect(page.getByText(user.name,{exact:true})).toBeVisible();await expect(add(page)).toBeDisabled();await expect(page.getByRole("button",{name:"Редактировать пользователя "+user.name})).toBeDisabled() fail=false;await refresh(page).click();await expect(add(page)).toBeEnabled();await expect(page.getByText("ФОНОВЫЙ ОТКАЗ",{exact:true})).toHaveCount(0) }) test("Пользователи: read права и отсутствие server read",async({page})=>{ await page.addInitScript(()=>localStorage.setItem("mmapp_token","header."+btoa(JSON.stringify({sub:"test",apps:["mm"],permissions:["mm:users:read"],exp:Math.floor(Date.now()/1000)+3600}))+".signature")) await page.route("**/api/auth/config",r=>catalogResponse(r, {json:{required:true}}));let servers=0;await page.route("**/api/servers",r=>{servers++;return catalogResponse(r, {json:[server]})}) await page.goto("/users");await expect(page.getByText(user.name,{exact:true})).toBeVisible();await expect(add(page)).toBeDisabled();await expect(page.getByRole("button",{name:"Удалить пользователя "+user.name})).toBeDisabled();await expect(page.getByRole("status").filter({hasText:"mm:servers:read"})).toBeVisible();expect(servers).toBe(0) }) test("Пользователи: до ответа live нет демо-профилей",async({page})=>{ let release!:()=>void;const gate=new Promise(r=>release=r);await page.route("**/api/users",async r=>{await gate;await catalogResponse(r, {json:{users:[user]}}).catch(()=>{})}) await page.goto("/users");await expect(page.getByRole("status").filter({hasText:"Загрузка пользователей…"})).toBeVisible();await expect(page.getByText(user.name,{exact:true})).toHaveCount(0);await expect(add(page)).toBeDisabled();await expect(page.getByText("Нет пользователей",{exact:true})).toHaveCount(0);release();await expect(add(page)).toBeEnabled() }) test("Пользователи: медленный серверный каталог не задерживает список",async({page})=>{ let release!:()=>void;const gate=new Promise(r=>release=r);await page.route("**/api/servers",async r=>{await gate;await catalogResponse(r, {json:[server]}).catch(()=>{})}) await page.goto("/users");await expect(page.getByText(user.name,{exact:true})).toBeVisible();await expect(add(page)).toBeDisabled();release();await expect(add(page)).toBeEnabled() })