#!/usr/bin/env bash set -euo pipefail # ----------------------------------------------------------------------------- # playwright-recorder: Playwright Codegen (fresh, repo-local workspace) # # Purpose: # - ALWAYS start fresh (no dependency on repo state) # - Do NOT use /tmp for recordings/workspace # - Use repo-local ignored workspace: recordings/.work # - Persist generated tests into repo-local ignored dir: recordings/ # - Run everything inside the official Playwright container (version pinned) # ----------------------------------------------------------------------------- PLAYWRIGHT_VERSION="${PLAYWRIGHT_VERSION:-1.58.1}" PLAYWRIGHT_IMAGE="${PLAYWRIGHT_IMAGE:-mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-jammy}" RECORDINGS_DIR="${RECORDINGS_DIR:-recordings}" OUTPUT_FILE="${OUTPUT_FILE:-codegen.spec.ts}" TARGET="${TARGET:-playwright-test}" START_URL="${1:-}" die() { echo "ERROR: $*" >&2; exit 1; } warn() { echo "WARNING: $*" >&2; } require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing command: $1" } repo_root() { git rev-parse --show-toplevel 2>/dev/null || pwd } require_cmd docker require_cmd xhost : "${DISPLAY:=:0}" ROOT="$(repo_root)" REC_DIR="${ROOT}/${RECORDINGS_DIR}" WORK_DIR="${REC_DIR}/.work" mkdir -p "${REC_DIR}" cleanup() { # revoke X11 permission xhost -local:docker >/dev/null 2>&1 || true # remove ephemeral workspace rm -rf "${WORK_DIR}" >/dev/null 2>&1 || true } trap cleanup EXIT # X11 socket sanity check (helpful hint only) if [[ "${DISPLAY}" == ":0" && ! -S /tmp/.X11-unix/X0 ]]; then warn "No /tmp/.X11-unix/X0 socket detected." warn "You might be on pure Wayland without XWayland." warn "Playwright codegen requires X11/XWayland (or a nested X server)." fi # Always fresh workspace (repo-local, ignored) rm -rf "${WORK_DIR}" mkdir -p "${WORK_DIR}/tests" # Minimal ephemeral Playwright project (workspace-local) cat > "${WORK_DIR}/package.json" < "${WORK_DIR}/playwright.config.ts" <<'EOF' import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './tests', use: { trace: 'on-first-retry', }, }); EOF # X11 access control for Docker (temporary) xhost +local:docker >/dev/null echo "Playwright image : ${PLAYWRIGHT_IMAGE}" echo "Repo root : ${ROOT}" echo "Recordings dir : ${REC_DIR}" echo "Workspace dir : ${WORK_DIR}" echo "Output file : ${OUTPUT_FILE}" echo "DISPLAY : ${DISPLAY}" if [[ -n "${START_URL}" ]]; then echo "Start URL : ${START_URL}" fi echo INSTALL_CMD="npm install --no-audit --no-fund" CODEGEN_CMD="./node_modules/.bin/playwright codegen --target=${TARGET} --output=/recordings/${OUTPUT_FILE}" if [[ -n "${START_URL}" ]]; then CODEGEN_CMD="${CODEGEN_CMD} ${START_URL}" fi docker run --rm -it \ --ipc=host \ --network host \ -e "DISPLAY=${DISPLAY}" \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -v "${WORK_DIR}:/work" \ -v "${REC_DIR}:/recordings" \ -w /work \ "${PLAYWRIGHT_IMAGE}" \ bash -lc "${INSTALL_CMD}; ${CODEGEN_CMD}" echo echo "✔ Codegen finished" echo "✔ Generated file: ${RECORDINGS_DIR}/${OUTPUT_FILE}"