Skip to content
Development
Skill

/playwright-harness

Drive a real browser with Playwright on any OS and gate on what you observe: write a script, launch Chromium (headless by default; a shared headed window when a human must watch or drive), drive the page, and assert on screenshots plus collected page errors. The operational

From plugin
simiancraft-skills
823 skills4 agents

Claude Code

$ npx -y skills add simiancraft/simiancraft-skills --skill playwright-harness --agent claude-code

SKILL.md

playwright-harness.SKILL.md
name: playwright-harness
description: >-
  Drive a real browser with Playwright on any OS and gate on what you observe:
  write a script, launch Chromium (headless by default; a shared headed window
  when a human must watch or drive), drive the page, and assert on screenshots
  plus collected page errors. The operational trunk for browser work;
  specializations layer on top. Use for ANY web task: "drive the UI headlessly",
  "smoke-test a screen", "screenshot a component or canvas", "reproduce a console
  error", "fill and submit a form", "test a login flow", "check responsive
  layout", "find broken links", "open a browser I can watch/drive", or "automate
  a browser flow". Open references/interactions.md and references/flows.md for
  the element vocabulary and multi-step recipes; switch to
  playwright-camera-mask-testing for a camera or person feed, or
  playwright-gif-capture for an animated GIF. Validated on Linux/WSL (headless,
  ANGLE GPU path for WebGL) and macOS (headless + interactive headed mode).

Playwright Harness

Project-agnostic kernel for driving a browser and asserting on it; the operational trunk the rest of the suite hangs off.

Map of the suite

This skill is the trunk: what to install, plus the run-and-assert pattern. Everything else hangs off it.

playwright-harness/                     <- you are here: prerequisites + run pattern + assert loop
├── references/
│   ├── interactions.md                 address elements: locators, actions, waits, assertions
│   └── flows.md                        recipes: login, forms, responsive, link-checking, network stubbing
├── scripts/
│   ├── keeper.mjs                      interactive headed mode: long-lived shared browser + CDP
│   └── observe.mjs                     interactive headed mode: attach, report URL/errors, screenshot
└── specializations (separate, discoverable skills; read this one first):
    ├── playwright-camera-mask-testing  a real person through getUserMedia; assert segmentation/mask by vision
    └── playwright-gif-capture          an animated GIF of a page, canvas, or WebGL animation

`references/` is this skill's own depth, loaded by reading the file. The specializations are separate, discoverable skills; open one when its input (a camera feed, a GIF) is what you need.

> **Runtime/package manager.** Examples use plain `node` + `npm`; substitute your > own runner (`bun`, `pnpm`, `yarn`) wherever they appear. Playwright itself is > unaffected.

Prerequisites (install once)

  • **Node 18+** and a package manager.
  • **Playwright + a browser binary.** Playwright ships no browser by default:
  npm i -D playwright          # or add to the project that already has it
  npx playwright install chromium
  • **Headless system libraries (Linux/WSL only).** A fresh box is missing the

shared libs Chromium needs (`libnss3`, `libatk`, `libgbm`, …); the symptom is a launch error listing `error while loading shared libraries`. Install them once:

  npx playwright install-deps chromium   # needs sudo; or your distro's equivalent packages

**macOS needs none of this** — the downloaded Chromium runs as-is, headless or headed. There is no `install-deps` step and no GPU shim to configure; a headed launch opens a normal window on the desktop.

  • Some specializations need extra binaries (e.g. `ffmpeg` for video/GIF encode);

each declares its own in a "Prerequisites" block.

The run pattern

1. **Write the script into a dedicated scratch dir**, never into the skill or the project: `/tmp/pw-<task>/run.mjs`, with any output alongside it (`/tmp/pw-<task>/shot.png`). A per-task dir stops parallel runs from colliding on a shared filename. Parameterize the URL as `const TARGET_URL = process.env.TARGET_URL || '<default>'` so it is never hardcoded. 2. **Make `playwright` resolvable from the script's own directory.** ESM resolves a bare import from the SCRIPT's location upward; cwd is irrelevant, so running a `/tmp` script from inside a project that has playwright does NOT work. Symlink an existing install into the scratch dir (do not reuse a shared `/tmp/node_modules`; it collides with other `/tmp` installs and then the import silently fails to resolve):

   mkdir -p /tmp/pw-<task>
   ln -sfn /path/to/an-install/node_modules /tmp/pw-<task>/node_modules  # an install that has playwright
   node /tmp/pw-<task>/run.mjs

No install handy? `cd /tmp/pw-<task> && npm i playwright` right there. Confirm it resolves before relying on it: from the scratch dir, `node -e "import('playwright').then(() => console.log('resolves'))"`. 3. **Default to headless.** It is faster and gives clean, chrome-free screenshots. Use `headless: false` only when a human must watch or drive — see "Interactive headed mode" below. (On a display-less box — CI, WSL without WSLg — headed launches fail outright; headless is not just the default there, it is the only mode.)

// /tmp/pw-task/run.mjs
import { chromium } from 'playwright';
const TARGET_URL = process.env.TARGET_URL || 'http://localhost:8080/';

const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
const errors = [];
page.on('pageerror', (e) => errors.push(`pageerror: ${e.message}`));
page.on('console', (m) => m.type() === 'error' && errors.push(`console: ${m.text()}`));

await page.goto(TARGET_URL, { waitUntil: 'load' });
await page.locator('#root').screenshot({ path: '/tmp/pw-task/shot.png' }); // element-cropped; use page.screenshot() for the full page
await browser.close();
console.log(errors.length ? `ERRORS:\n${errors.join('\n')}` : 'no page errors');

Interactive headed mode (shared browser, human + agent)

When a human must watch the agent drive — or type URLs and act while the agent observes — one browser is shared between them instead of scripting a headless one-shot. Two scripts in

Read more
@simiancraft
Ships withsimiancraft-skills

Claude Code skills for the full arc of a change: farm to table, with receipts. Curated Claude Code skills and agents from simiancraft. Most skill collections are grab bags. This one has a spine: it carries a change through its whole life.

823 skills4 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
8
Star history of simiancraft/simiancraft-skills on GitHub, a chart by star-history.com

Other skills on simiancraft-skills.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react2d252k
@facebook@facebookInstall Skill

Questions about playwright-harness.

Which coding agents can use playwright-harness?
playwright-harness installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.