78 lines
3.9 KiB
JavaScript
78 lines
3.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import { mkdir } from "node:fs/promises";
|
|
import process from "node:process";
|
|
import playwright from "../frontend/node_modules/@playwright/test/index.js";
|
|
|
|
const { chromium } = playwright;
|
|
|
|
const chunks = [];
|
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
const password = Buffer.concat(chunks).toString("utf8").trim();
|
|
if (!password) throw new Error("password is required on stdin");
|
|
const baseURL = String(process.argv[2] || "").replace(/\/$/, "");
|
|
if (!baseURL) throw new Error("base URL is required");
|
|
const output = new URL("../.playwright-results/live-0516/", import.meta.url).pathname;
|
|
await mkdir(output, { recursive: true });
|
|
|
|
const browser = await chromium.launch({ headless: true });
|
|
const reports = [];
|
|
try {
|
|
for (const viewport of [{ name: "desktop", width: 1440, height: 900 }, { name: "mobile", width: 390, height: 844 }]) {
|
|
const context = await browser.newContext({ viewport });
|
|
const page = await context.newPage();
|
|
await page.goto(baseURL, { waitUntil: "domcontentloaded" });
|
|
const passwordInput = page.getByLabel("管理员密码");
|
|
if (await passwordInput.isVisible().catch(() => false)) {
|
|
await passwordInput.fill(password);
|
|
const remember = page.locator('.remember-device input[type="checkbox"]');
|
|
if (await remember.isChecked()) await remember.uncheck();
|
|
await page.getByRole("button", { name: "登录", exact: true }).click();
|
|
}
|
|
try {
|
|
await page.locator(".app-shell").waitFor({ state: "visible", timeout: 30_000 });
|
|
await page.locator(".video-card,.home-empty").first().waitFor({ state: "visible", timeout: 30_000 });
|
|
} catch (error) {
|
|
const message = (await page.locator("body").innerText()).replace(/\s+/g, " ").slice(0, 500);
|
|
throw new Error(`${viewport.name} app shell did not become ready: ${message}`, { cause: error });
|
|
}
|
|
await page.locator(".nav-item-2").click();
|
|
await page.locator(".search-coverage").waitFor({ state: "visible", timeout: 15_000 });
|
|
await page.waitForFunction(
|
|
() => !document.querySelector(".search-coverage")?.textContent?.includes("正在读取"),
|
|
undefined,
|
|
{ timeout: 30_000 },
|
|
);
|
|
const coverage = (await page.locator(".search-coverage").innerText()).replace(/\s+/g, " ").trim();
|
|
const searchGeometry = await page.evaluate(() => ({
|
|
viewport: innerWidth,
|
|
document: document.documentElement.scrollWidth,
|
|
content: document.querySelector(".content")?.scrollWidth || 0,
|
|
}));
|
|
if (searchGeometry.document > searchGeometry.viewport + 1 || searchGeometry.content > searchGeometry.viewport + 1) {
|
|
throw new Error(`${viewport.name} search page overflows horizontally: ${JSON.stringify(searchGeometry)}`);
|
|
}
|
|
await page.screenshot({ path: `${output}/${viewport.name}-search.png`, fullPage: true });
|
|
await page.locator(".nav-item-1").click();
|
|
await page.locator(".video-card").first().click();
|
|
await page.locator(".transcript-panel").waitFor({ state: "visible", timeout: 15_000 });
|
|
await page.locator(".transcript-toggle").click();
|
|
await page.waitForFunction(
|
|
() => !document.querySelector(".transcript-toggle")?.textContent?.includes("正在读取"),
|
|
undefined,
|
|
{ timeout: 30_000 },
|
|
);
|
|
const transcriptStatus = (await page.locator(".transcript-toggle").innerText()).replace(/\s+/g, " ").trim();
|
|
const transcriptItems = await page.locator(".transcript-list>button").count();
|
|
await page.screenshot({ path: `${output}/${viewport.name}-player.png`, fullPage: true });
|
|
reports.push({ viewport: viewport.name, coverage, transcriptStatus, transcriptItems, searchGeometry });
|
|
await page.evaluate(async () => {
|
|
const csrf = sessionStorage.getItem("imagefind:csrf") || "";
|
|
await fetch("/api/v1/auth/logout", { method: "POST", headers: { "X-CSRF-Token": csrf } });
|
|
});
|
|
await context.close();
|
|
}
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
console.log(JSON.stringify(reports, null, 2));
|