192 lines · 8.2 KB
/**
 * Browser-level cookie isolation, driven over the Chrome DevTools Protocol with a throwaway headless profile.
 *
 *   SITES_E2E_URL=http://localhost:3317 bun run e2e/sites-browser.e2e.ts
 *
 * Chrome resolves `*.localhost` to loopback, so site hosts work without hosts-file entries.
 */
import { spawn } from "node:child_process";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createScratchRepo, d1, deployScratch, FORGE, gitPush, log, waitForSite } from "./helpers";

const CHROME = process.env.CHROME_PATH ?? "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
const START_ATTEMPTS = 50;
const PORT = 9400 + Math.floor(Math.random() * 500);

const profile = mkdtempSync(join(tmpdir(), "sites-e2e-"));
const chrome = spawn(
  CHROME,
  ["--headless=new", `--remote-debugging-port=${PORT}`, `--user-data-dir=${profile}`, "--no-first-run", "about:blank"],
  { stdio: "ignore" },
);

async function waitForChrome(): Promise<string> {
  for (let attempt = 0; attempt < START_ATTEMPTS; attempt++) {
    try {
      const targets = (await (await fetch(`http://127.0.0.1:${PORT}/json/list`)).json()) as {
        type: string;
        webSocketDebuggerUrl: string;
      }[];
      const target = targets.find((item) => item.type === "page");
      if (target) return target.webSocketDebuggerUrl;
    } catch {
      // Chrome is still starting.
    }
    await Bun.sleep(200);
  }
  throw new Error("Chrome did not start");
}