Ctrl K
ComunidadGuías…

playwright.config.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { execSync } from "node:child_process";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { defineConfig } from "@playwright/test";

// any-console の E2E スモーク設定。CI(.github/workflows/ci.yml の e2e ジョブ)と
// ローカル手動実行の両方で使う。
//
// サーバは 2 モード:
// - ANY_CONSOLE_URL 指定時: 起動済みの外部サーバに対して実行する。
//   認証トークンは ANY_CONSOLE_TOKEN env、もしくは data/auth.json から読む。
// - 未指定時(既定): 一時ディレクトリを data 領域にした使い捨てサーバを
//   ランごとに割り当てた空きポートで自動起動する(ANY_CONSOLE_DATA_DIR 隔離モード)。
//   実運用の data/・config.json には一切触れないため、後始末漏れがサーバ状態を
//   汚す心配がない。サーバ実行には `server/target/release/any-console-server`
//   (事前に `cargo build --release` が必要)と tmux が必要。バイナリパスは
//   ANY_CONSOLE_E2E_BIN で上書き可能。

const E2E_TOKEN = "e2e-ephemeral-token";
const E2E_DATA_DIR_PREFIX = "any-console-e2e-";

// ランごとに OS から空きポートを割り当てる(固定ポートだと並行ランや既存プロセスと
// 衝突し、reuseExistingServer: false の webServer が起動前に失敗するため)。
// bind→close 後に他プロセスへ取られる僅かな競合窓は許容する(その場合も
// サーバ起動エラーとして顕在化するだけで、誤った対象へのテストにはならない)。
function allocateFreePort() {
  const script =
    "const s=require('net').createServer();" +
    "s.listen(0,'127.0.0.1',()=>{console.log(s.address().port);s.close()})";
  return Number(execSync(`node -e "${script}"`, { encoding: "utf8" }).trim());
}

// 使い捨てサーバモードのセットアップ。この config はワーカープロセスでも再評価されるが、
// ワーカーは main プロセスが設定した ANY_CONSOLE_URL を env 継承するため、
// このブロックは main プロセスで一度しか走らない(一時ディレクトリの二重作成を防ぐ)。
// --list(エディタ拡張等のテスト discovery)は globalTeardown が走らないため、
// 使い捨て領域を作るとそのまま溜まり続ける。discovery ではサーバ不要なので作らない。
const LIST_ONLY = process.argv.includes("--list");

let webServer;
if (!process.env.ANY_CONSOLE_URL && !LIST_ONLY) {
  // 掃除は global-teardown.js が「この実行が作ったディレクトリ」だけを対象に行う。
  // プレフィックス一致での一括削除はしない(並行実行中の別ランの data 領域や、
  // spec が作る any-console-e2e-ws-* / any-console-e2e-git-* を巻き込むため)。
  const port = allocateFreePort();
  const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), E2E_DATA_DIR_PREFIX));
  // tmux セッション名前空間もランごとに分離する(既定の "ac-" のままだと
  // ホスト tmux を共有する並行ランや実運用のセッションを列挙・巻き込みうるため)。
  // 実運用サーバはセッション名が "ac-" で始まるかどうかで自分のものと判定する
  // (server/src/tmux.rs の list_session_ids)ため、"ac-" で始まらない値にする
  // ("ac-e2e..." のように "ac-" を含めると、実運用サーバから見て前方一致してしまい
  // 同一ホストで実運用サーバが動いている時にE2E用の一時セッションが本番のセッション
  // 一覧に混入する)。
  const tmuxPrefix = `e2e${crypto.randomBytes(3).toString("hex")}-`;
  fs.writeFileSync(path.join(dataDir, "auth.json"), JSON.stringify({ token: E2E_TOKEN }));
  // bind 先とポートは隔離側 config.json で指定する(実運用の config.json は読まれない)
  fs.writeFileSync(
    path.join(dataDir, "config.json"),
    JSON.stringify({ __global__: { config_version: 1, host: "127.0.0.1", port } }),
  );
  process.env.ANY_CONSOLE_URL = `http://127.0.0.1:${port}`;
  process.env.ANY_CONSOLE_TOKEN = E2E_TOKEN;
  process.env.ANY_CONSOLE_E2E_DATA_DIR = dataDir; // global-teardown.js が削除する
  process.env.ANY_CONSOLE_E2E_TMUX_PREFIX = tmuxPrefix; // global-teardown.js が残セッションを掃除する
  const rustBin =
    process.env.ANY_CONSOLE_E2E_BIN ||
    path.join(process.cwd(), "server", "target", "release", "any-console-server");
  webServer = {
    command: rustBin,
    url: `http://127.0.0.1:${port}/`,
    reuseExistingServer: false,
    timeout: 60_000,
    stdout: "pipe",
    stderr: "pipe",
    env: {
      ...process.env,
      ANY_CONSOLE_DATA_DIR: dataDir,
      ANY_CONSOLE_TMUX_PREFIX: tmuxPrefix,
      // E2E は短時間に多数のリクエストを送るため、レート制限(既定 1000req/60s)を引き上げる
      ANY_CONSOLE_RATE_LIMIT: "2000",
    },
  };
}

export default defineConfig({
  testDir: "./tests/e2e",
  globalTeardown: "./tests/e2e/global-teardown.js",
  webServer,
  // ヘッドレス、Chromium のみ(個人ツール用途で十分)
  use: {
    baseURL: process.env.ANY_CONSOLE_URL,
    headless: true,
    ignoreHTTPSErrors: true,
    screenshot: "only-on-failure",
    trace: "retain-on-failure",
    // Playwright 管理外の Chromium を使う環境(プリインストール済みバイナリ等)向けの上書き。
    // 未設定なら通常どおり playwright install した Chromium を使う。
    launchOptions: process.env.ANY_CONSOLE_E2E_CHROMIUM
      ? { executablePath: process.env.ANY_CONSOLE_E2E_CHROMIUM }
      : {},
  },
  reporter: [["list"]],
  // 並列度は控えめ(tmux セッション共有なので衝突回避)。
  workers: 1,
  retries: 0,
  timeout: 30_000,
});