84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
|
|
import { chromium, type Page, type Locator } from 'playwright';
|
||
|
|
import { mkdir } from 'node:fs/promises';
|
||
|
|
import { resolve, dirname } from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
import { DEFAULT_MASK, shots, type Shot } from './shots.config.js';
|
||
|
|
|
||
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
|
|
const OUT_DIR = resolve(__dirname, '../../src/assets/screenshots/whp');
|
||
|
|
|
||
|
|
function envOrDie(name: string): string {
|
||
|
|
const v = process.env[name];
|
||
|
|
if (!v) {
|
||
|
|
throw new Error(
|
||
|
|
`Missing env var: ${name}. Put it in tools/screenshots/.env (gitignored).`,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
const WHP_BASE = envOrDie('WHP_BASE'); // e.g., https://whp01.cloud-hosting.io:8443
|
||
|
|
const WHP_USER = envOrDie('WHP_USER');
|
||
|
|
const WHP_PASS = envOrDie('WHP_PASS');
|
||
|
|
|
||
|
|
async function login(page: Page): Promise<void> {
|
||
|
|
await page.goto(`${WHP_BASE}/login`);
|
||
|
|
await page.fill('input[name="username"]', WHP_USER);
|
||
|
|
await page.fill('input[name="password"]', WHP_PASS);
|
||
|
|
await page.click('button[type="submit"]');
|
||
|
|
await page.waitForLoadState('networkidle');
|
||
|
|
}
|
||
|
|
|
||
|
|
async function captureShot(page: Page, shot: Shot): Promise<void> {
|
||
|
|
const viewport = shot.viewport ?? { width: 1440, height: 900 };
|
||
|
|
await page.setViewportSize(viewport);
|
||
|
|
|
||
|
|
await page.goto(`${WHP_BASE}${shot.path}`);
|
||
|
|
await page.waitForLoadState('networkidle');
|
||
|
|
if (shot.waitFor) await page.waitForSelector(shot.waitFor);
|
||
|
|
|
||
|
|
const maskSelectors = [...DEFAULT_MASK, ...(shot.mask ?? [])];
|
||
|
|
const maskLocators: Locator[] = maskSelectors.map((sel) => page.locator(sel));
|
||
|
|
const outPath = resolve(OUT_DIR, `${shot.id}.png`);
|
||
|
|
|
||
|
|
if (shot.selector) {
|
||
|
|
await page.locator(shot.selector).screenshot({
|
||
|
|
path: outPath,
|
||
|
|
mask: maskLocators,
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
// Viewport-only — Playwright never includes browser chrome
|
||
|
|
await page.screenshot({
|
||
|
|
path: outPath,
|
||
|
|
fullPage: false,
|
||
|
|
mask: maskLocators,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
console.log(`captured ${shot.id} -> ${outPath}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main(): Promise<void> {
|
||
|
|
await mkdir(OUT_DIR, { recursive: true });
|
||
|
|
const browser = await chromium.launch({ headless: true });
|
||
|
|
const ctx = await browser.newContext({
|
||
|
|
ignoreHTTPSErrors: true,
|
||
|
|
viewport: { width: 1440, height: 900 },
|
||
|
|
deviceScaleFactor: 2,
|
||
|
|
});
|
||
|
|
const page = await ctx.newPage();
|
||
|
|
|
||
|
|
try {
|
||
|
|
await login(page);
|
||
|
|
for (const shot of shots) {
|
||
|
|
await captureShot(page, shot);
|
||
|
|
}
|
||
|
|
} finally {
|
||
|
|
await browser.close();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((err) => {
|
||
|
|
console.error(err);
|
||
|
|
process.exit(1);
|
||
|
|
});
|