Run Playwright Docker containers with the current host UID/GID to avoid root-owned files in bind-mounted workspaces. - Add --user UID:GID and HOME override to codegen and replay - Harden replay workspace cleanup against leftover permission issues https://chatgpt.com/share/6984a73c-14a0-800f-a40d-778972e518b7
129 lines
3.4 KiB
Bash
Executable File
129 lines
3.4 KiB
Bash
Executable File
#!/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}"
|
|
|
|
# Run containers as the current host user to avoid root-owned files in bind mounts.
|
|
USER_ID="$(id -u)"
|
|
GROUP_ID="$(id -g)"
|
|
|
|
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" <<EOF
|
|
{
|
|
"name": "playwright-recorder-ephemeral",
|
|
"private": true,
|
|
"type": "commonjs",
|
|
"devDependencies": {
|
|
"@playwright/test": "${PLAYWRIGHT_VERSION}"
|
|
}
|
|
}
|
|
EOF
|
|
|
|
cat > "${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 \
|
|
--user "${USER_ID}:${GROUP_ID}" \
|
|
-e HOME=/tmp \
|
|
--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}"
|