import { existsSync } from "fs"; import type { Browser, BrowserContext, Page } from "playwright"; /** Options for launching a Playwright browser session. */ export interface PwLaunchOptions { /** Use headless mode. Default: true */ headless?: boolean; /** Base URL to navigate to after opening the page. Default: "http://localhost:5180" */ baseUrl?: string; /** Viewport size. Default: 1280x800 */ viewport?: { width: number; height: number }; /** Optional path to a Playwright storageState JSON for pre-auth. Loaded only if the file exists. */ storageStatePath?: string; /** Slow down operations by the given ms. Default: 0 */ slowMo?: number; } /** Playwright handles returned after launching the browser. */ export interface PwHandles { browser: Browser; context: BrowserContext; page: Page; /** Closes context then browser. */ close: () => Promise; } /** * pw_launch_browser — launches chromium and returns a Page navigated to baseUrl. * * Optionally pre-authenticates via storageState (loaded only if the file exists). * Returns handles including a convenience close() that tears down context and browser. */ export async function pw_launch_browser(opts: PwLaunchOptions = {}): Promise { const { chromium } = await import("playwright"); const headless = opts.headless ?? true; const slowMo = opts.slowMo ?? 0; const baseUrl = opts.baseUrl ?? "http://localhost:5180"; const viewport = opts.viewport ?? { width: 1280, height: 800 }; const browser = await chromium.launch({ headless, slowMo }); const contextOptions: Parameters[0] = { viewport }; if (opts.storageStatePath && existsSync(opts.storageStatePath)) { contextOptions.storageState = opts.storageStatePath; } const context = await browser.newContext(contextOptions); const page = await context.newPage(); await page.goto(baseUrl); const close = async (): Promise => { await context.close(); await browser.close(); }; return { browser, context, page, close }; }