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:
13
.gitignore
vendored
13
.gitignore
vendored
@@ -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/
|
||||
|
||||
22
LICENSE
22
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.
|
||||
|
||||
3
MIRRORS
Normal file
3
MIRRORS
Normal 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
21
Makefile
Normal 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
140
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 <kevin@veen.world>
|
||||
🔗 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)
|
||||
|
||||
11
flake.nix
11
flake.nix
@@ -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 ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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
0
recordings/.gitkeep
Normal file
122
scripts/codegen.sh
Executable file
122
scripts/codegen.sh
Executable 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}"
|
||||
Reference in New Issue
Block a user