import {test,expect} from "@playwright/test" import {certificate as container,server,certificateState as state} from "./fixtures/certificates" import {openIssue,issueJob} from "./fixtures/certificate-issue" const headers={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,OPTIONS","access-control-allow-headers":"Content-Type,Authorization"} for(const change of ["backend","mode"])for(const fails of [false,true])test("Сертификаты: позднее чтение/"+change+"/"+fails,async({page})=>{ let started=false,completed=false,release!:()=>void;const gate=new Promise(r=>release=r) await page.route("**/health",r=>r.fulfill({headers,json:{ok:true}}));await page.route("**/api/**",r=>{const p=new URL(r.request().url()).pathname;return r.fulfill({headers,json:p==="/api/auth/config"?{required:false}:p==="/api/servers"?[server]:p==="/api/certificates/state"?state():{directoryUrl:"https://acme.example.test/directory",tokenConfigured:false,enabled:false,intervalSec:300,renewBeforeDays:30}})}) await page.route("**/api/certificates/state",async r=>{if(new URL(r.request().url()).port!=="8000")return r.fallback();started=true;await gate;try{await r.fulfill(fails?{headers,status:503,json:{error:"СТАРАЯ ОШИБКА сертификатов"}}:{headers,json:state([{...container,name:"СТАРЫЙ СЕРТИФИКАТ"}])})}catch{}finally{completed=true}}) await page.goto("/certificates");await expect.poll(()=>started).toBe(true);await page.goto("/settings") if(change==="backend"){const input=page.getByPlaceholder("http://localhost:8000");await input.fill("http://localhost:8101");await input.press("Enter")}else await page.getByRole("button",{name:"Моковые",exact:true}).click() await page.goto("/certificates");release();await expect.poll(()=>completed).toBe(true) if(change==="backend")await expect(page.getByText(container.name,{exact:true})).toBeVisible();else await expect(page.getByText("Моковые данные",{exact:true})).toBeVisible() await expect(page.getByText("СТАРЫЙ СЕРТИФИКАТ",{exact:true})).toHaveCount(0);await expect(page.getByText(/СТАРАЯ ОШИБКА сертификатов/)).toHaveCount(0) }) for (const fails of [false, true]) test("Сертификаты: позднее сохранение renew/" + fails, async ({ page }) => { let started = false, completed = false, release!: () => void; const gate = new Promise(r => release = r) await page.route("**/health", r => r.fulfill({ headers, json: { ok: true } })) await page.route("**/api/**", r => { const path = new URL(r.request().url()).pathname return r.fulfill({ headers, json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : path === "/api/certificates/state" ? state() : path === "/api/certificates/renew-settings" ? { enabled: true, intervalSec: 21600, renewBeforeDays: 30 } : { directoryUrl: "https://acme.example.test/directory", tokenConfigured: false } }) }) await page.route("**/api/certificates/renew-settings", async r => { if (r.request().method() !== "PUT") return r.fallback() started = true; await gate try { await r.fulfill(fails ? { headers, status: 503, json: { error: "СТАРОЕ СОХРАНЕНИЕ ОТКАЗ" } } : { headers, json: { enabled: false, intervalSec: 21600, renewBeforeDays: 30 } }) } catch {} finally { completed = true } }) await page.goto("/certificates"); const toggle = page.getByRole("switch", { name: "Автообновление сертификатов", exact: true }) await expect(toggle).toBeChecked(); await toggle.click(); await expect.poll(() => started).toBe(true) await page.goto("/settings"); const input = page.getByPlaceholder("http://localhost:8000"); await input.fill("http://localhost:8101"); await input.press("Enter") await page.goto("/certificates"); await expect(toggle).toBeChecked(); release(); await expect.poll(() => completed).toBe(true) await expect(toggle).toBeChecked(); await expect(page.getByText("СТАРОЕ СОХРАНЕНИЕ ОТКАЗ", { exact: true })).toHaveCount(0) await expect(page.getByText("Автообновление выключено", { exact: true })).toHaveCount(0) }) for (const fails of [false, true]) test("Сертификаты: позднее сохранение ACME/" + fails, async ({ page }) => { let started = false, completed = false, release!: () => void; const gate = new Promise(r => release = r) await page.route("**/health", r => r.fulfill({ headers, json: { ok: true } })) await page.route("**/api/**", r => { const path = new URL(r.request().url()).pathname return r.fulfill({ headers, json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : path === "/api/certificates/state" ? state() : path === "/api/certificates/renew-settings" ? { enabled: true, intervalSec: 21600, renewBeforeDays: 30 } : { directoryUrl: "https://acme.example.test/directory", tokenConfigured: false } }) }) await page.route("**/api/certificates/acme-settings", async r => { if (r.request().method() !== "PUT") return r.fallback() started = true; await gate try { await r.fulfill(fails ? { headers, status: 503, json: { error: "СТАРОЕ СОХРАНЕНИЕ ACME ОТКАЗ" } } : { headers, json: { directoryUrl: "https://old.example.test/directory", tokenConfigured: true } }) } catch {} finally { completed = true } }) await page.goto("/certificates"); const directory = page.getByRole("textbox", { name: "ACME directory URL", exact: true }) await expect(directory).toHaveValue("https://acme.example.test/directory"); await directory.fill("https://old.example.test/directory"); await page.getByRole("button", { name: "Сохранить настройки", exact: true }).click(); await expect.poll(() => started).toBe(true) await page.goto("/settings"); const input = page.getByPlaceholder("http://localhost:8000"); await input.fill("http://localhost:8101"); await input.press("Enter") await page.goto("/certificates"); await expect(directory).toHaveValue("https://acme.example.test/directory"); release(); await expect.poll(() => completed).toBe(true) await expect(directory).toHaveValue("https://acme.example.test/directory"); await expect(page.getByText("СТАРОЕ СОХРАНЕНИЕ ACME ОТКАЗ", { exact: true })).toHaveCount(0) await expect(page.getByText("Настройки ACME сохранены", { exact: true })).toHaveCount(0) }) for (const change of ["backend", "mode"]) for (const stage of ["POST", "poll"]) for (const fails of [false, true]) test("Сертификаты: поздний выпуск/" + change + "/" + stage + "/" + fails, async ({ page }) => { let request: Record = {}, started = false, completed = false, release!: () => void; const gate = new Promise(r => release = r) await page.route("**/health", r => r.fulfill({ headers, json: { ok: true } })) await page.route("**/api/**", r => { const path = new URL(r.request().url()).pathname return r.fulfill({ headers, json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : path === "/api/certificates/state" ? state() : path === "/api/certificates/renew-settings" ? { enabled: true, intervalSec: 21600, renewBeforeDays: 30 } : { directoryUrl: "https://acme.example.test/directory", tokenConfigured: true } }) }) await page.route("**/api/certificates/issue", async r => { request = r.request().postDataJSON() if (stage !== "POST") return r.fulfill({ headers, json: { jobId: request.requestId } }) started = true; await gate try { await r.fulfill(fails ? { headers, status: 503, json: { error: "СТАРЫЙ ВЫПУСК ОТКАЗ" } } : { headers, json: { jobId: request.requestId } }) } catch {} finally { completed = true } }) await page.route("**/api/certificates/issue/*", async r => { if (stage !== "poll") return r.fulfill({ headers, json: issueJob(request) }) started = true; await gate try { await r.fulfill(fails ? { headers, status: 503, json: { error: "СТАРЫЙ ВЫПУСК ОТКАЗ" } } : { headers, json: issueJob(request) }) } catch {} finally { completed = true } }) const dialog = await openIssue(page); await dialog.getByRole("button", { name: "Выпустить", exact: true }).click(); await expect.poll(() => started).toBe(true) await page.goto("/settings") if (change === "backend") { const input = page.getByPlaceholder("http://localhost:8000"); await input.fill("http://localhost:8101"); await input.press("Enter") } else await page.getByRole("button", { name: "Моковые", exact: true }).click() await page.goto("/certificates"); release(); await expect.poll(() => completed).toBe(true) await expect(page.getByRole("button", { name: "Задача выпуска", exact: true })).toHaveCount(0) await expect(page.getByText("API подтвердил завершение задачи выпуска", { exact: true })).toHaveCount(0) await expect(page.getByText(/СТАРЫЙ ВЫПУСК ОТКАЗ/)).toHaveCount(0) })