Новый сервис pcp-tgu-ui-service: ТГУ-фронт на headless-auth nstart + платформенный CI/деплой

This commit is contained in:
Дмитрий Соловьев
2026-06-09 13:35:13 +03:00
parent 0b617594fd
commit 505bf1f31c
129 changed files with 21640 additions and 0 deletions
@@ -0,0 +1,60 @@
import { chromium } from "playwright";
const BASE = "http://localhost:5174/";
const results = [];
const pass = (n, d = "") => { results.push(["PASS", n, d]); console.log("PASS ::", n, d); };
const fail = (n, d = "") => { results.push(["FAIL", n, d]); console.log("FAIL ::", n, d); };
const b = await chromium.launch({ headless: true });
const p = await (await b.newContext({ viewport: { width: 1600, height: 900 } })).newPage();
const consoleErrors = [];
p.on("console", (m) => { if (m.type() === "error") consoleErrors.push(m.text()); });
p.on("pageerror", (e) => consoleErrors.push("PAGEERROR: " + e.message));
try {
await p.goto(BASE, { waitUntil: "networkidle", timeout: 30000 });
await p.waitForTimeout(800);
// выбрать КА 56756 и открыть редактор
await p.getByText("NORAD 56756", { exact: false }).first().click();
await p.waitForTimeout(500);
await p.getByRole("tab", { name: "Редактор", exact: true }).click();
await p.waitForTimeout(700);
// контролы редактора
const shoot = p.getByRole("button", { name: "+ Съёмка", exact: true });
const drop = p.getByRole("button", { name: "+ Сброс", exact: true });
(await shoot.count()) > 0 && (await drop.count()) > 0
? pass("editor:controls", "+ Съёмка / + Сброс присутствуют")
: fail("editor:controls");
// режим «Сброс» -> ЗРВ реальных станций
await drop.click();
const rva = await p.waitForResponse((r) => /\/api\/satellites\/\d+\/rva/.test(r.url()), { timeout: 15000 }).catch(() => null);
await p.waitForTimeout(1000);
rva && rva.status() === 200
? pass("editor:drop-fetches-rva", `GET rva ${rva.status()}`)
: fail("editor:drop-fetches-rva", rva ? `status ${rva.status()}` : "не вызван");
const panelText = (await p.locator("aside, [class*='panel']").allInnerTexts().catch(() => [])).join(" ").replace(/\n+/g, " ");
const stationNames = ["Шпицберген", "Отрадное", "Байконур", "Ханты-Мансийск"];
const found = stationNames.filter((s) => panelText.includes(s));
found.length >= 2
? pass("editor:drop-real-stations", `зоны по станциям: ${found.join(", ")}`)
: fail("editor:drop-real-stations", `найдено станций: ${JSON.stringify(found)}`);
// зоны содержат виток + время (UTC-окно)
/виток\s*\d+/i.test(panelText) && /\d{2}:\d{2}[-]\d{2}:\d{2}/.test(panelText)
? pass("editor:drop-zone-format", "виток + временное окно показаны")
: fail("editor:drop-zone-format", panelText.slice(0, 200));
consoleErrors.length === 0 ? pass("no-console-errors") : fail("no-console-errors", JSON.stringify(consoleErrors.slice(0, 8)));
} catch (e) {
fail("SCRIPT", e.message);
console.log(e.stack);
} finally {
const npass = results.filter((r) => r[0] === "PASS").length;
const nfail = results.filter((r) => r[0] === "FAIL").length;
console.log(`\n=== EDITOR SUMMARY: ${npass} PASS / ${nfail} FAIL ===`);
await b.close();
process.exit(nfail > 0 ? 1 : 0);
}