playwright-scaffold
Skill10 starsChanged 31 days agoApache-2.0View on GitHub
Use when a web project needs its first Playwright integration case — no test
- Reads credentials
- Installs packages
In this repository21 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- commitSkill
- design-apiSkill
- design-architectureSkill
- design-erdSkill
- design-sdsSkill
- design-srsSkill
- design-tableSkill
- doc-syncSkill
- flow-initSkill
- flowSkill
- flow-uninstallSkill
- harness-authoringSkill
- harness-deploymentsSkill
- harness-initSkill
- harness-insightSkill
- integrationSkill
- performanceSkill
- prose-reviewSkill
- release-commitSkill
- wiki-initSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 32
If absent, scan the codebase (gather candidates rather than asserting):
- Very specific: line 44
If the scan comes up empty, use framework default ports as candidates: Vite=5173, Next/CRA/Nuxt=3000, Angular=4200.
- Very specific: line 91
Only when absent, write <testDir>/main.smoke.spec.<ts|js> based on examples/main.smoke.spec.ts.
- Very specific: line 110
If playwright.config.* is absent, scaffold the minimal config below.
- Very specific: line 142
When the config already exists: do not rewrite it. Report the projects[] shape a monorepo needs (one entry per app, each with its own …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
playwright-scaffold
Generates a single deterministic main-screen smoke Playwright case for a web project. It creates only the universal, deterministic check of "does the app come up?" and does not generate arbitrary user scenarios (that is the job of a human or codegen).
When: when a new/empty web project needs its first integration case. When the integration skill detects web + zero cases, it invokes this skill to create a main-screen smoke and then runs it immediately.
Interaction. Wherever this skill asks the user something, use the host's blocking question tool already in your tool list, matched by capability rather than by a host-specific name; if it is listed but not loaded, load it first with the host's tool-discovery primitive; only when no such tool is listed, or a question call errors, offer numbered options in chat and end your turn to wait for the reply — never answer the question yourself or skip it.
Step 1 — Detect baseURL (in order, with user confirmation at the end)
use.baseURLin playwright.config:ls playwright.config.* 2>/dev/null && grep -n "baseURL" playwright.config.* 2>/dev/null- If absent, scan the codebase (gather candidates rather than asserting):
# docker-compose port mapping (web service host port) grep -nE '^\s*-\s*"?[0-9]+:[0-9]+' docker-compose.y*ml compose.y*ml 2>/dev/null # PORT / BASE_URL / public URL in .env grep -nhE '^(PORT|BASE_URL|VITE_[A-Z_]*URL|NEXT_PUBLIC_[A-Z_]*URL)=' .env .env.* 2>/dev/null # framework config / dev script port grep -nE 'server\s*:|port\s*:' vite.config.* next.config.* 2>/dev/null grep -nE '"dev"\s*:.*(--port|-p )\s*[0-9]+' package.json 2>/dev/null # Dockerfile EXPOSE grep -niE '^EXPOSE\s+[0-9]+' Dockerfile* 2>/dev/null- If the scan comes up empty, use framework default ports as candidates: Vite=5173, Next/CRA/Nuxt=3000, Angular=4200.
- User confirmation (required): present the collected candidates — ask the user (structured choice) — and finalize the baseURL (offer them as choices if there are several; ask for direct input if none was found). Do not assert a guess as fact.
Step 2 — Detect testDir and Language
# testDir from playwright.config, falling back to Playwright's ./tests default
grep -hoE "testDir:[[:space:]]*['\"][^'\"]+" playwright.config.* 2>/dev/null | head -1 | sed -E "s/.*['\"]//"
# Language: any of these three means TypeScript
ls tsconfig.json playwright.config.ts 2>/dev/null; grep -E '"typescript"' package.json 2>/dev/nulltestDirunset →tests/.- TypeScript when any of
tsconfig.json,playwright.config.ts, or atypescriptdependency is present →.spec.ts; otherwise.spec.js. Aplaywright.config.tscounts on its own:@playwright/testbundles its own TypeScript, so a TS Playwright project routinely has neither atsconfig.jsonnor atypescriptdependency, and keying only on those two drops a.jsspec into a TypeScript suite. - Carry the resolved
testDirforward as a literal in Step 3 — eachbashcall is a fresh shell, so a variable set here is gone by the next command.
Step 3 — Idempotent Generation (skip if already present)
The starter is for empty projects, so an existing case means report-and-stop. Resolve
testDir and search it in one command — the same regex integration/SKILL.md and
web-playwright.md use, so all three agree on what counts as an existing case.
# POSIX find + grep -E: -regextype is GNU-only (BSD/macOS find rejects it, exits 1, and an
# `&& … || echo MISSING` chain then reports every healthy project as MISSING — conflating
# any find failure with an absent directory). `|| true`: grep exits 1 on zero matches, and
# an empty suite is an answer, not an error. MISSING comes only from the [ -d ] test.
TESTDIR=$(grep -hoE "testDir:[[:space:]]*['\"][^'\"]+" playwright.config.* 2>/dev/null | head -1 | sed -E "s/.*['\"]//")
TESTDIR="${TESTDIR:-./tests}"
if [ -d "$TESTDIR" ]; then find "$TESTDIR" -type f 2>/dev/null | grep -E '\.(spec|test)\.(c|m)?[jt]sx?$' || true; else echo "MISSING: $TESTDIR"; fi- Any case path means cases already exist → only report and do not generate (no
overwriting). The regex already matches
main.smoke.spec.ts, so a previous run's smoke counts as a hit. MISSING:for a config-declaredtestDiris a misconfiguration — report it and stop. Generating into a directory the config does not point at leaves a spec Playwright will never run.MISSING: ./testswith notestDirin the config is a new project: create the directory and generate.- Only when absent, write
<testDir>/main.smoke.spec.<ts|js>based onexamples/main.smoke.spec.ts. The spec navigates to'/'and nothing else — Playwright resolves that againstuse.baseURLin playwright.config, which is where the baseURL belongs. Step 4 puts it there.
Step 4 — Settle playwright.config (opt-in)
Three states, each with somewhere to go — a config that exists but declares no baseURL
is the common one, and the spec written in Step 3 resolves '/' against nothing until it
is handled:
| State | Action |
playwright.config.* exists with a use.baseURL | nothing to do config-wise — but if @playwright/test itself is missing, still guide the install below. Report the projects[] shape a monorepo needs (Step 5) |
playwright.config.* exists, no use.baseURL | add use: { baseURL: process.env.BASE_URL ?? '<the value confirmed in Step 1>' } to the existing config — edit it, do not replace it |
playwright.config.* absent | scaffold the minimal config below |
- If
playwright.config.*is absent, scaffold the minimal config below. If@playwright/testis not installed (config present or not), guide installation — do not force auto-install, only with consent:npm install -D @playwright/test && npx playwright install chromium// playwright.config.ts (minimal — BASE_URL overrides the value confirmed in Step 1) import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './tests', use: { baseURL: process.env.BASE_URL ?? 'http://localhost:3000', // ← Step 1's value trace: 'retain-on-failure', // a trace carries request/response bodies and session video: 'off', // tokens — this pair decides whether uploading the }, // report in CI is safe. Do not widen it casually. // One entry per app in a monorepo. They run in parallel, every failure is collected, // and one report covers all of them: // projects: [ // { name: 'web', use: { baseURL: process.env.WEB_URL ?? 'http://localhost:3000' } }, // { name: 'admin', use: { baseURL: process.env.ADMIN_URL ?? 'http://localhost:3001' } }, // ], });
Step 5 — Report + Extension Guidance
- Report the generated file path and the injected baseURL.
- State that this is a starter smoke: "This is only a 'does the app come up?' check. Add real scenarios
(login, checkout, etc.) yourself, or record them with
npx playwright codegen <baseURL>and save them undertests/." - When the config already exists: do not rewrite it. Report the
projects[]shape a monorepo needs (one entry per app, each with its ownbaseURL), thetrace/videopair, and that.github/workflows/e2e.ymlrunsnpx playwright testfrom oneworking-directory— so every app must be reachable from that one config.
Discipline
- Files only — write the spec and stop; leave running it to
npx playwright test. The one case to write is the main-screen smoke. Step 1's baseURL confirmation and Step 4's install consent both still apply — ask the user for each. - No overwriting, idempotent — do not generate if existing cases are present.
- Do not assert a guessed baseURL — gather candidates from codebase evidence and confirm with the user.
- Free OSS only — Playwright (Apache-2.0). Source: https://playwright.dev/docs/writing-tests · configuration https://playwright.dev/docs/test-configuration
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

