Xpersona
P

Playwright (Automation + MCP + Scraper)

CLAWHUB · Unverified

Automates, tests, and debugs browsers with Playwright: locators, auto-waiting, traces, CI runs, and MCP browser control. Use when a test is flaky, times out, or fails only in CI or headless; when a locator matches multiple elements or the wrong one (strict mode violation); when clicks need force, waits become sleeps, or networkidle never settles; for storageState and login setup, request mocking and HAR replay, uploads and downloads, iframes and shadow DOM, popups and dialogs, screenshot diffs that change per machine, trace and report artifacts, sharding a slow suite, device and permission emulation, accessibility checks, driving a real browser through Playwright MCP, extracting data from JS-rendered pages, or porting a Cypress, Puppeteer, or Selenium suite to Playwright. Not for maintaining an existing Cypress or Puppeteer suite (cypress, puppeteer) or for work a plain HTTP request answers (http). Skill: Playwright (Automation + MCP + Scraper) Owner: ivangdavila Summary: Automates, tests, and debugs browsers with Playwright: locators, auto-waiting, traces, CI runs, and MCP browser control. Use when a test is flaky, times out, or fails only in CI or headless; when a locator matches multiple elements or the wrong one (strict mode violation); when clicks need force, waits become sleeps, or networkidle never settl

62
Rank
84
Safety
44k
Downloads

About

What it does, and when to use it.

Capability contract not published. No trust telemetry is available yet. 43.8K downloads reported by the source. Last updated 11/11/2026.

Avoid when

  • Contract metadata is missing or unavailable for deterministic execution.

Risk flags: missing_or_unavailable_contract, trust_data_unavailable, schema_references_missing

Install and run

Setup complexity: low.

clawhub skill install s178jdk12x4qj3gs2se3etxf3h83h7ft:playwright
  1. Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.
  2. Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.

Contract: missing

curl -s "https://www.xpersona.co/api/v1/agents/clawhub-ivangdavila-playwright-aywright-2/snapshot"

Run-check

$0.02 USD

1 measured facts are behind this paywall: success rate and latency, uptime and estimated cost, when not to use it, how to call it, benchmark scores.

Agents pay $0.02 in USDC. A card payment is $0.50, the smallest a card allows.

Documentation

CLAWHUB

143,783 characters of source documentation, loaded on request.

Extracted files

5 files captured from the source.

SKILL.md

---
name: playwright
slug: playwright
version: 1.0.4
description: >-
  Automates, tests, and debugs browsers with Playwright: locators, auto-waiting, traces, CI runs, and MCP browser control.
  Use when a test is flaky, times out, or fails only in CI or headless; when a locator matches multiple elements or the
  wrong one (strict mode violation); when clicks need force, waits become sleeps, or networkidle never settles; for
  storageState and login setup, request mocking and HAR replay, uploads and downloads, iframes and shadow DOM, popups and
  dialogs, screenshot diffs that change per machine, trace and report artifacts, sharding a slow suite, device and
  permission emulation, accessibility checks, driving a real browser through Playwright MCP, extracting data from
  JS-rendered pages, or porting a Cypress, Puppeteer, or Selenium suite to Playwright. Not for maintaining an existing
  Cypress or Puppeteer suite (cypress, puppeteer) or for work a plain HTTP request answers (http).
homepage: https://clawic.com/skills/playwright
changelog: "Full coverage pass: deeper guides, situation-named files, and per-user configuration"
metadata:
  clawdbot:
    emoji: P
    requires:
      bins:
      - node
      - npx
    os:
    - linux
    - darwin
    - win32
    install:
    - id: npm-playwright
      kind: npm
      package: playwright
      bins:
      - playwright
      label: Install Playwright
    - id: npm-playwright-mcp
      kind: npm
      package: '@playwright/mcp'
      bins:
      - playwright-mcp
      label: Install Playwright MCP (optional)
    displayName: Playwright (Automation + MCP + Scraper)
    configPaths:
    - ~/Clawic/data/playwright/
---

User preferences and memory live in `~/Clawic/data/playwright/` (see `setup.md` on first use). If you have data at an old location (`~/playwright/` or `~/clawic/playwright/`), move it to `~/Clawic/data/playwright/`. Everything a run produces — specs, traces, reports, snapshots, `storageState` files — stays inside the repository or its temp dir, never in the preferences folder: auth state is a credential and belongs in a gitignored path.

## When To Use

- Writing or repairing Playwright specs, fixtures, `playwright.config.ts`, or one-off automation scripts
- A run fails: timeout, strict mode violation, flaky click, passes locally and fails in CI or headless
- Login, session reuse, uploads, downloads, iframes, popups, dialogs, or device emulation are in the way
- Visual snapshots, accessibility checks, trace capture, sharding, or cutting suite wall time
- Driving a live browser through Playwright MCP, or extracting data a plain fetch cannot render
- Porting a Cypress, Puppeteer, or Selenium suite to Playwright, including deciding which tests not to port
- Not for maintaining an existing Cypress or Puppeteer suite (→ `cypress`, `puppeteer`) or for anything an HTTP request already answers (→ `http`)

## Quick Reference

| Situation | Play |
|---|---|
| `strict mode violation: resolved to N eleme

_meta.json

{
  "owner": "clawic",
  "slug": "playwright",
  "displayName": "Playwright (Automation + MCP + Scraper)",
  "latest": {
    "version": "1.0.4",
    "publishedAt": 1785066064433
  },
  "history": [
    {
      "version": "1.0.3",
      "publishedAt": 1773251092810
    },
    {
      "version": "1.0.2",
      "publishedAt": 1772107672145
    },
    {
      "version": "1.0.0",
      "publishedAt": 1770982184555
    }
  ]
}

accessibility.md

# Accessibility — Automated Scans and Keyboard Paths

Automated scanning catches a minority of real barriers — Deque's own figure for axe-core is around 57% of issues found automatically. Treat the scan as the floor and keyboard plus screen-reader semantics as the actual test.

## Scanning With axe

```typescript
import AxeBuilder from '@axe-core/playwright';

test('dashboard has no critical a11y violations', async ({ page }) => {
  await page.goto('/dashboard');
  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
    .analyze();
  expect(results.violations).toEqual([]);
});
```

Scoping and triage:

```typescript
new AxeBuilder({ page })
  .include('#main')                       // scan one region
  .exclude('.third-party-widget')         // an embed you cannot fix
  .disableRules(['color-contrast'])       // temporarily, with a linked issue
```

- Scan **states**, not just routes: open the modal, expand the menu, trigger the error, then analyze. Most violations live in states a route-level scan never renders.
- Adopting on a legacy app: snapshot the current violations as a baseline and fail only on new ones (`expect(results.violations.length).toBeLessThanOrEqual(baseline)`), then ratchet the number down. A first run demanding zero gets the whole check deleted.
- Attach the violation list to the report: `testInfo.attach('axe', { body: JSON.stringify(results.violations, null, 2), contentType: 'application/json' })` — a failure that names the rule and the node is actionable; a bare count is not.

## What The Scan Cannot See

| Barrier | How to test |
|---|---|
| Focus order that jumps around the page | Tab through and assert the sequence (below) |
| Focus lost after a modal closes | Assert focus returns to the trigger |
| A keyboard trap inside a widget | Tab N times and assert you escaped |
| A label that is present but meaningless ("click here") | Human review, or a lint rule on the copy |
| Live-region announcements | Assert `role="status"`/`aria-live` content changes |
| Contrast on a background image | Human review |
| Whether the flow is usable at all with a screen reader | Manual pass; no tool substitutes |

## ARIA Snapshots — Structure As An Assertion

`toMatchAriaSnapshot` (playwright >=1.49) freezes the accessibility tree of a region as YAML: roles, accessible names, and nesting.

```typescript
await expect(page.getByRole('navigation')).toMatchAriaSnapshot(`
  - list:
    - listitem:
      - link "Home"
    - listitem:
      - link /Sign (in|out)/
`);

await expect(page.getByRole('dialog')).toMatchAriaSnapshot({ name: 'checkout-dialog.aria.yml' });
```

- It fails on the regressions a scan and a screenshot both miss: a heading demoted to a `div`, a button that lost its accessible name, a menu item that appeared, an order that changed. It passes through a pure restyle.
- Scope it to the smallest meaningful region — nav, dialog, menu, table, a design-system component. A whole-page t

auth.md

# Auth — Sessions, Roles, and Parallel-Safe Accounts

Logging in through the UI in every test is the most expensive line in most suites: sign in once, reuse the state, and give every worker an account it owns.

Contents: [The Default Shape](#the-default-shape) · [What storageState Actually Captures](#what-storagestate-actually-captures) · [Faster: Skip The UI Entirely](#faster-skip-the-ui-entirely) · [Multiple Roles](#multiple-roles) · [Parallel-Safe Accounts](#parallel-safe-accounts) · [SSO, 2FA, And Magic Links](#sso-2fa-and-magic-links) · [Expiry And Rotation](#expiry-and-rotation) · [Handling Credentials](#handling-credentials)

## The Default Shape

A setup project signs in once and writes the storage state; every other project starts already authenticated.

```typescript
// global.setup.ts
import { test as setup, expect } from '@playwright/test';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(process.env.E2E_USER!);
  await page.getByLabel('Password').fill(process.env.E2E_PASS!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
  await page.context().storageState({ path: '.auth/user.json' });
});
```

```typescript
// playwright.config.ts
projects: [
  { name: 'setup', testMatch: /global\.setup\.ts/ },
  { name: 'chromium', dependencies: ['setup'], use: { storageState: '.auth/user.json' } },
]
```

`.auth/` goes in `.gitignore`. A committed storage state is a committed live session.

## What storageState Actually Captures

| Captured | Not captured |
|---|---|
| Cookies (including httpOnly) | `sessionStorage` — per tab, never serialized by default |
| `localStorage` per origin | IndexedDB, unless the Playwright version supports opting it in |
| | Service-worker caches |
| | Anything the server holds against a device fingerprint |

If the app keeps its token in `sessionStorage`, reuse fails silently: the test lands on a login page and the first assertion times out. Workarounds: copy the value in through an init script, or ask the app to accept the cookie path in test builds.

```typescript
await context.addInitScript(([k, v]) => sessionStorage.setItem(k, v), ['token', token]);
```

## Faster: Skip The UI Entirely

The login form is a product feature that deserves **one** test. Everywhere else, mint the session through the API:

```typescript
const res = await request.post('/api/login', { data: { email, password } });
const { token } = await res.json();
await context.addInitScript(t => localStorage.setItem('token', t), token);
// or: await context.addCookies([{ name: 'session', value: token, domain: 'localhost', path: '/' }]);
```

Saves the whole login round trip per worker and removes the login page from the failure surface of 400 unrelated tests.

## Multiple Roles

One storage-state file per role, one project per role:

```typescript
projects: [
  { name: 'setup', testMatch: /auth\.

browsers.md

# Browsers — Engines, Channels, and Installs

Playwright ships its own browser builds, pinned to the package version. Most "works on my machine" browser problems are a version or channel mismatch, not a bug.

## Engines

| Engine | What it really is | Test it when |
|---|---|---|
| `chromium` | Playwright's Chromium build | Default; matches Chrome and Edge behavior closely enough for almost everything |
| `firefox` | Playwright's Gecko build | You support Firefox; also catches spec-correct behavior Chromium tolerates |
| `webkit` | WebKit engine, **not Safari** | Closest available proxy for Safari and iOS; shares the engine, not the browser |
| `channel: 'chrome'` / `'msedge'` | Your installed branded browser | Widevine DRM, proprietary codecs, Chrome-specific APIs, or a bug reported only in real Chrome |

WebKit on Linux differs from Safari on macOS in fonts, codecs, and media support. A WebKit-only failure is worth investigating, but "passes in WebKit" is not proof it works in Safari — for release-critical Safari behavior, run a real device or a hosted Safari.

Engine differences that actually bite: date and number formatting via Intl, `input[type=date]` widgets, clipboard permissions (Chromium-only), `isMobile` (unsupported in Firefox), download handling, and font fallback affecting layout.

Exclude the affected case, not the engine: `test.skip(browserName === 'firefox', 'isMobile unsupported')` keeps the rest of the file running on Firefox and states why in the report (annotations: `testing.md`). Dropping the whole project to dodge one case is how cross-browser coverage quietly ends.

## Headless

Chromium has two headless implementations: the old separate headless shell (fast, small) and the browser's own headless mode, which behaves like headed and supports extensions. Playwright >=1.49 exposes the browser-native one as `channel: 'chromium'`. When a bug reproduces headed but not headless, switching to the browser-native mode is the first thing to try — before rewriting the test.

Headless differences to expect regardless: no window manager (so window-size APIs report the configured viewport), a different default UA in older builds, no GPU by default, and no extensions in the old shell.

## Install And Version Locking

```bash
npx playwright install                      # all configured browsers
npx playwright install chromium --with-deps # one browser plus Linux system libraries (needs root)
npx playwright install-deps                 # libraries only
npx playwright --version                    # the number the CI image tag must match
```

- Browser builds are tied to the package version: upgrading `@playwright/test` without re-running `install` gives `Executable doesn't exist at ...`.
- The Docker image tag must match exactly: `mcr.microsoft.com/playwright:v1.XX.Y-noble` with `@playwright/test@1.XX.Y`. A mismatched image either fails to find browsers or runs different builds than developers do.
- Cache location: `~/.cache/ms-playwright` (L

Sponsored

Ads related to Playwright (Automation + MCP + Scraper) and adjacent AI workflows.