diff --git a/.gitignore b/.gitignore index cb54ccd..0dc859e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,16 @@ +# Playwright recorder outputs (generated artifacts) +recordings/* +!recordings/.gitkeep + +# Ephemeral workspace used by recorder +recordings/.work/ + +# Optional: if you later add node/npm files here +node_modules/ +npm-debug.log* +pnpm-debug.log* +yarn-error.log* + .venv/ dist/ build/ diff --git a/LICENSE b/LICENSE index c30e6e6..7d80bdb 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -All rights reserved by Kevin Veen-Birkenbach +MIT License + +Copyright (c) 2026 Kevin Veen-Birkenbach + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MIRRORS b/MIRRORS new file mode 100644 index 0000000..59e9a24 --- /dev/null +++ b/MIRRORS @@ -0,0 +1,3 @@ +git@github.com:kevinveenbirkenbach/playwright-recorder.git +ssh://git@code.infinito.nexus:2201/kevinveenbirkenbach/playwright-recorder.git +ssh://git@git.veen.world:2201/kevinveenbirkenbach/playwright-recorder.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8cbeea5 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +.PHONY: help install codegen + +## ๐Ÿ“– Show help +help: + @echo "" + @echo "๐ŸŽญ playwright-recorder" + @echo "" + @echo "Targets:" + @echo " make install ๐Ÿ”ง Prepare the recorder (chmod +x)" + @echo " make codegen ๐ŸŽฅ Record Playwright tests via GUI" + @echo " make help ๐Ÿ“– Show this help" + @echo "" + +## ๐Ÿ”ง One-time setup +install: + @chmod +x scripts/codegen.sh + @echo "โœ” scripts/codegen.sh is now executable" + +## ๐ŸŽฅ Run Playwright Codegen (GUI recording) +codegen: + bash scripts/codegen.sh diff --git a/README.md b/README.md index f74fc29..d76f386 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,138 @@ -# playwright-recorder +# ๐ŸŽญ playwright-recorder -Homepage: https://github.com/kevinveenbirkenbach/playwright-recorder +> A small, reproducible Playwright **recording / codegen tool** +> built around **Docker**, **X11/XWayland**, and **ephemeral workspaces** -## Author -Kevin Veen-Birkenbach +๐Ÿ”— Homepage: https://github.com/kevinveenbirkenbach/playwright-recorder + +--- + +## โœจ What is this? + +`playwright-recorder` is a **developer tool** for recording Playwright tests via +the official Playwright **codegen** feature โ€” without polluting your project: + +- ๐ŸŽฅ **GUI-based recording** (Playwright Inspector) +- ๐Ÿงผ **Always fresh** (no reused state, no lockfile pain) +- ๐Ÿณ **Runs fully in Docker** +- ๐Ÿ—‚๏ธ **Repo-local, git-ignored workspace** +- ๐Ÿ“„ **Only generated tests are persisted** +- ๐Ÿšซ **No `/tmp` usage** + +Perfect for: +- recording login flows +- capturing UI regressions +- generating first test drafts +- infra-heavy projects where Playwright does *not* belong in the main repo + +--- + +* `recordings/` is **ignored by git** +* `.gitkeep` ensures the folder exists +* ephemeral workspace lives in `recordings/.work/` and is auto-cleaned + +--- + +## ๐Ÿš€ Usage + +### 1๏ธโƒฃ Requirements + +* Docker +* X11 or XWayland (Wayland-only will NOT work) +* `xhost` + +On Arch Linux: + +## โš™๏ธ Installation (one-time) + +Prepare the recorder script: + +```bash +make install +``` + +This makes `scripts/codegen.sh` executable. + +--- + +## ๐ŸŽฅ Start recording + +```bash +make codegen +``` + +Or with a start URL: + +```bash +./scripts/codegen.sh https://example.com/login +``` + +--- + +## ๐Ÿ“ค Output + +* ๐Ÿ“„ Generated test: + + ```text + recordings/codegen.spec.ts + ``` + +* ๐Ÿงผ Ephemeral workspace (auto-deleted): + + ```text + recordings/.work/ + ``` + +Nothing else touches your repo. + +--- + +## โš™๏ธ Configuration (optional) + +Environment variables: + +| Variable | Default | Description | +| -------------------- | ----------------- | ------------------- | +| `PLAYWRIGHT_VERSION` | `1.58.1` | Playwright version | +| `PLAYWRIGHT_IMAGE` | auto | Docker image tag | +| `RECORDINGS_DIR` | `recordings` | Output directory | +| `OUTPUT_FILE` | `codegen.spec.ts` | Generated file name | +| `TARGET` | `playwright-test` | Codegen target | +| `DISPLAY` | `:0` | X11 display | + +Example: + +```bash +OUTPUT_FILE=login.spec.ts make codegen +``` + +--- + +## ๐Ÿง  Design philosophy + +* โŒ Not a test runner +* โŒ Not CI tooling +* โŒ Not framework glue +* โœ… A **focused recording utility** +* โœ… One job, done well + +--- + +## ๐Ÿ” Security note + +`xhost +local:docker` is used **temporarily** to allow GUI access. +Access is **revoked automatically** when the script exits. + +--- + +## ๐Ÿง‘โ€๐Ÿ’ป Author + +Kevin Veen-Birkenbach +๐Ÿ“ง [kevin@veen.world](mailto:kevin@veen.world) +๐Ÿก [www.veen.world](https://www.veen.world) + +--- + +## ๐Ÿ“œ License + +MIT License โ€“ see [LICENSE](LICENSE) diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 962823d..0000000 --- a/flake.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - description = "playwright-recorder"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - outputs = { self, nixpkgs }: - let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; - in { - devShells.${system}.default = pkgs.mkShell { - packages = with pkgs; [ python312 python312Packages.pytest python312Packages.ruff ]; - }; - }; -} diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 29790fb..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,21 +0,0 @@ -[build-system] -requires = ["setuptools>=68", "wheel"] -build-backend = "setuptools.build_meta" - -[project] -name = "playwright-recorder" -version = "0.1.0" -description = "" -readme = "README.md" -requires-python = ">=3.10" -authors = [{ name = "Kevin Veen-Birkenbach", email = "kevin@veen.world" }] -license = { text = "All rights reserved by Kevin Veen-Birkenbach" } -urls = { Homepage = "https://github.com/kevinveenbirkenbach/playwright-recorder" } - -dependencies = [] - -[tool.setuptools] -package-dir = {"" = "src"} - -[tool.setuptools.packages.find] -where = ["src"] diff --git a/recordings/.gitkeep b/recordings/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/codegen.sh b/scripts/codegen.sh new file mode 100755 index 0000000..fda423c --- /dev/null +++ b/scripts/codegen.sh @@ -0,0 +1,122 @@ +#!/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}"