feat: add standalone Playwright recorder tool with Docker-based codegen

- introduce repo-local, ephemeral Playwright codegen workflow
- add executable codegen script using official Playwright Docker image
- persist generated recordings under recordings/ (git-ignored, .gitkeep)
- add minimal Makefile with install and codegen targets
- switch project license to MIT
- improve README with clear usage, requirements, and design rationale
- add MIRRORS file for multi-remote setup
- clean up gitignore for generated artifacts and node tooling
This commit is contained in:
2026-02-05 14:56:46 +01:00
parent c4587ad238
commit df66e3547e
9 changed files with 316 additions and 37 deletions

13
.gitignore vendored
View File

@@ -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/ .venv/
dist/ dist/
build/ build/

22
LICENSE
View File

@@ -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.

3
MIRRORS Normal file
View File

@@ -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

21
Makefile Normal file
View File

@@ -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

140
README.md
View File

@@ -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 🔗 Homepage: https://github.com/kevinveenbirkenbach/playwright-recorder
Kevin Veen-Birkenbach <kevin@veen.world>
---
## ✨ 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)

View File

@@ -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 ];
};
};
}

View File

@@ -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"]

0
recordings/.gitkeep Normal file
View File

122
scripts/codegen.sh Executable file
View File

@@ -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" <<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 \
--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}"