Files
nxdns/website/demo/gen/shoot.mjs
T
mokhtar 93e2683e71
Gates / frontend (push) Failing after 8m6s
Gates / package (push) Skipped
Gates / container (push) Skipped
Gates / test (push) Successful in 2m38s
Gates / test-aarch64 (push) Successful in 8m52s
CI / gates (push) Failing after 11m33s
website: nxdns.sh on astro and starlight, with the docs and 0.0.24 screenshots
2026-10-21 17:03:01 +02:00

62 lines
2.2 KiB
JavaScript

// usage: node shoot.mjs OUT_DIR QUERY_ID
import { chromium } from "playwright";
const [outDir, queryId] = process.argv.slice(2);
const BASE = "http://127.0.0.1:18080";
const PAGES = [
["overview", "/overview?period=24h"],
["activity", "/activity"],
["query-detail", `/activity/queries/${queryId}`],
["clients", "/clients"],
["diagnostics", "/diagnostics"],
];
async function settle(page) {
await page.waitForLoadState("networkidle").catch(() => {});
await page.waitForFunction(
() => !document.querySelector('[aria-busy="true"], [role="progressbar"]'),
null,
{ timeout: 15000 },
).catch(() => console.log(" still busy after 15s"));
await page.waitForTimeout(2500);
}
// The phone form is 390px wide, where the admin UI switches to its drawer layout, and touch-only, so
// no hover state is drawn.
const FORMS = [
["", { viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2 }],
["-phone", { viewport: { width: 390, height: 844 }, deviceScaleFactor: 3, isMobile: true, hasTouch: true }],
];
const browser = await chromium.launch();
for (const [suffix, form] of FORMS) for (const scheme of ["light", "dark"]) {
const context = await browser.newContext({
...form,
colorScheme: scheme,
timezoneId: "Europe/Paris",
locale: "en-GB",
});
const page = await context.newPage();
page.on("console", (m) => m.type() === "error" && console.log(` console error: ${m.text()}`));
await page.goto(`${BASE}/login`);
await page.locator("#password").fill("nxdns-demo");
await page.locator('button[type="submit"]').click();
await page.waitForURL((u) => !u.pathname.startsWith("/login"));
for (const [name, path] of PAGES) {
await page.goto(BASE + path);
if (!form.hasTouch) await page.mouse.move(1430, 890);
await settle(page);
if (name === "activity") await page.waitForTimeout(8000);
// A phone stacks the health cards and filters above the episodes, so the first screen shows none.
if (name === "diagnostics" && form.hasTouch) {
await page.getByRole("heading", { name: "Active" }).evaluate((h) => h.scrollIntoView({ block: "start" }));
await page.waitForTimeout(500);
}
const file = `${outDir}/${name}-${scheme}${suffix}.png`;
await page.screenshot({ path: file });
console.log(file);
}
await context.close();
}
await browser.close();