import fs from "node:fs/promises"; import path from "node:path"; import { execFile } from "node:child_process"; import { promisify } from "node:util"; const execFileAsync = promisify(execFile); const devPort = Number(process.env.PLAYWRIGHT_DEV_PORT || 5173); const runtimeNamespace = String(process.env.PLAYWRIGHT_ARTIFACT_NAMESPACE || `port-${devPort}`) .trim() .replace(/[^a-zA-Z0-9._-]+/g, "-"); const pidFile = path.resolve(process.cwd(), "output/playwright", `dev-server-${runtimeNamespace}.json`); async function killProcessTree(pid) { if (!pid) { return; } if (process.platform === "win32") { await execFileAsync("taskkill", ["/PID", String(pid), "/T", "/F"], { cwd: process.cwd() }).catch(() => {}); return; } try { process.kill(-pid, "SIGTERM"); } catch { try { process.kill(pid, "SIGTERM"); } catch { // ignore } } } export default async function globalTeardown() { if (process.env.PLAYWRIGHT_BASE_URL) { return; } try { const file = await fs.readFile(pidFile, "utf8"); const { pid } = JSON.parse(file); await killProcessTree(pid); } catch { // ignore missing or malformed state } await fs.rm(pidFile, { force: true }).catch(() => {}); }