schmelczer-dev/scripts/lib/browser.mjs
2026-06-11 21:35:45 +01:00

89 lines
2.4 KiB
JavaScript

import { mkdir, rm } from 'node:fs/promises';
import { chromium } from 'playwright';
export const CLOSE_TIMEOUT_MS = 3000;
export const LAUNCH_TIMEOUT_MS = 10000;
export const CONTEXT_TIMEOUT_MS = 8000;
export const PAGE_TIMEOUT_MS = 15000;
// Chromium puts profiles and internal files in the process temp directory.
// Some CI/dev containers mount /tmp as a very small tmpfs, so the checks point
// it at an already-ignored directory under .astro/ instead.
export async function setupBrowserTmp(browserTmp) {
await rm(browserTmp, { recursive: true, force: true });
await mkdir(browserTmp, { recursive: true });
process.env.TMPDIR = browserTmp;
process.env.TMP = browserTmp;
process.env.TEMP = browserTmp;
}
export async function cleanupBrowserTmp(browserTmp) {
await rm(browserTmp, { recursive: true, force: true }).catch(() => {});
}
export async function withTimeout(promise, timeoutMs, label) {
let timeout;
try {
return await Promise.race([
promise,
new Promise((_, reject) => {
timeout = setTimeout(() => reject(new Error(label)), timeoutMs);
}),
]);
} finally {
clearTimeout(timeout);
}
}
export async function safeClosePage(page) {
await withTimeout(
page.close(),
CLOSE_TIMEOUT_MS,
'Timed out while closing Playwright page'
).catch(() => {});
}
export async function safeCloseContext(context) {
await withTimeout(
context.close(),
CLOSE_TIMEOUT_MS,
'Timed out while closing Playwright context'
).catch(() => {});
}
export async function safeCloseBrowser(browser) {
const childProcess = browser.process?.();
try {
await withTimeout(
browser.close(),
CLOSE_TIMEOUT_MS,
'Timed out while closing Chromium'
);
} catch {
childProcess?.kill('SIGKILL');
}
}
export function openBrowser(browserTmp) {
return withTimeout(
chromium.launch({
headless: true,
env: {
...process.env,
TMPDIR: browserTmp,
TMP: browserTmp,
TEMP: browserTmp,
},
args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'],
}),
LAUNCH_TIMEOUT_MS,
'Timed out while launching Chromium'
);
}
export function shouldRetryNavigation(error) {
const message = error instanceof Error ? error.message : String(error);
return /ERR_INSUFFICIENT_RESOURCES|Execution context was destroyed|Target.*closed|has been closed|Timed out while|navigation/i.test(
message
);
}