import { execFileSync } from "node:child_process"; import { Builder } from "selenium-webdriver"; import firefox from "selenium-webdriver/firefox.js"; /** * Resolve the geckodriver path from $PATH. * * @returns {string} */ function findGeckodriver() { try { return execFileSync("which", ["geckodriver"], { encoding: "utf-8" }).trim(); } catch { throw new Error( "geckodriver not found on $PATH. Install it (e.g. via Nix or your package manager).", ); } } /** * Create a Firefox WebDriver instance. * * @param {object} opts * @param {boolean} [opts.headless=false] - Run Firefox in headless mode. * @param {string} [opts.existingUrl] - Connect to an already-running * WebDriver server (e.g. "http://localhost:4444"). * @returns {Promise} */ export async function createDriver({ headless = false, existingUrl } = {}) { const options = new firefox.Options(); // Configure Headless if (headless) { options.addArguments("--headless"); } const builder = new Builder().forBrowser("firefox").setFirefoxOptions(options); // Connect to Existing Server if (existingUrl) { builder.usingServer(existingUrl); } else { // Use System Geckodriver - Bypasses the bundled selenium-manager which // is x86-64 only and doesn't work on aarch64. const service = new firefox.ServiceBuilder(findGeckodriver()); builder.setFirefoxService(service); } return builder.build(); }