@healflow/playwright
v0.1.17
Published
Runtime auto-healing Playwright plugin for HealFlow
Readme
@healflow/playwright
Runtime auto-healing Playwright plugin — detect failures, heal at runtime, and write local artifacts.
Overview
Wraps Playwright's page and locator APIs to automatically retry failed actions (selectors, timing, overlays, iframes, auth, and more). Writes run summaries to .healflow/ after each test run.
Works local-first — no backend or dashboard required.
Installation
npm install @healflow/playwright @healflow/cli @playwright/[email protected]
# Large suites: config scaffold only (no bulk codemod)
npx healflow init --config-onlyOr one line:
npm install @healflow/setup @playwright/[email protected]Playwright version: Peer
>=1.40.0 <1.59.0, tested on 1.58.2. Always pin@playwright/[email protected]— bare^1.40.0or1.6can resolve to untested releases. Runnpx healflow doctorto verify.
Quick start
npx playwright test
npx healflow report # opens .healflow/report.html
npx healflow doctor # adoption ratio + wiring checksManual config
// playwright.config.ts
import { defineConfig } from '@playwright/test';
import { withHealFlow } from '@healflow/playwright/auto';
export default withHealFlow(
defineConfig({
testDir: './tests',
reporter: [['html'], ['@healflow/playwright']],
}),
);Healing fixtures
Import from generated fixtures (created by healflow init):
import { test, expect } from './healflow.fixtures';Or wire manually:
import { test as base } from '@playwright/test';
import { healflowFixture } from '@healflow/playwright';
export const test = base.extend(healflowFixture());Custom fixtures (compose helper)
When extending Playwright fixtures, healing page must win:
import { test as base } from '@playwright/test';
import { composeHealFlowFixtures } from '@healflow/playwright';
export const test = composeHealFlowFixtures(base, {
myFixture: async ({}, use) => use('value'),
});healflow doctor warns if a custom page fixture overrides healing.
Page Object Model (POM)
Pass the wrapped { page } from the fixture into page objects — do not call browser.newPage():
import { test } from './healflow.fixtures';
import { LoginPage } from './pages/login.page';
test('login', async ({ page }) => {
const login = new LoginPage(page); // wrapped page heals actions
await login.submit();
});Pages created via browser.newPage() bypass healing.
Path alias (healflow init --alias)
Avoid editing every spec import:
npx healflow init --config-only --aliasThis adds tsconfig.json paths:
{
"compilerOptions": {
"paths": {
"@playwright/test": ["./healflow.fixtures.ts"]
}
}
}Requires alignment: TypeScript, Playwright test runner, and your bundler must resolve @playwright/test to the fixture file. See docs/product/ZERO_TOUCH_SPIKE.md.
Healable actions
Runtime healing wraps these APIs (others pass through unchanged):
| Target | Methods |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Locator | click, dblclick, fill, press, check, uncheck, selectOption, tap, hover, setInputFiles, clear, waitFor |
| Page | goto, reload, goBack, goForward, click, dblclick, fill, waitForURL |
Not wrapped: expect, getters, keyboard shortcuts, browser.newPage(). Assertions are never auto-modified.
Local artifacts
After each run, .healflow/ contains:
| File | Purpose |
| ------------- | ------------------------------------ |
| report.html | Human-readable heal summary |
| heals.json | Runtime heals applied during the run |
| fixes.json | AST fix proposals (dry-run) |
| run.json | Full run metadata |
Preview permanent fixes:
npx healflow apply # dry-run diff (monorepo: full AST preview)
npx healflow apply --apply # write when @healflow/ast-fix availableConfiguration
Set options in healflow.yml (parsed with yaml + schema validation):
mode: local
output: verbose
healing:
selector: true
timing: true
overlay: true
iframe: true
shadowDom: true
auth: true
network: true
navigation: true
mobile: true
i18n: true
upload: true
multiTab: true
# Optional cloud sync
backend:
url: https://api.healflow.example
organizationId: my-org
repositoryId: my-repo
token: hf_...Environment variables: HEALFLOW_API_URL, HEALFLOW_ORG_ID, HEALFLOW_REPO_ID, HEALFLOW_TOKEN, HEALFLOW_CONFIG.
Exports
| Subpath | Purpose |
| ----------------------------------- | -------------------------------------------------------- |
| @healflow/playwright | healflowFixture, wrapPage, composeHealFlowFixtures |
| @healflow/playwright/auto | withHealFlow() config wrapper |
| @healflow/playwright/reporter | Custom Playwright reporter |
| @healflow/playwright/setup-global | Global setup hook |
Runtime healing categories
HealFlow walks the T0→T5 runtime ladder on every healable locator/page action:
| Technique | Purpose |
| -------------- | ---------------------------------------------------------------- |
| T0 Retry | Condition-based waits (visibility, network idle, spinner hidden) |
| T1 Scope | Parent-chain scoping |
| T2 Normalize | Role / label / text strategy migration |
| T3 Fingerprint | DOM attribute & aria similarity |
| T4 Trace | Frame/shadow/navigation hints from Playwright error context |
| T5 History | Reuse prior heals from .healflow/heals.json |
Categories enabled by default: selector, timing, overlay, iframe, shadow DOM, auth/session, network, navigation, mobile, i18n, upload, multi-tab.
Each runtime heal records matrixEntryId, succeededTechnique, and healMode in .healflow/heals.json.
Product bugs and assertion values are never auto-fixed.
Cloud sync (optional)
When backend is configured, the reporter syncs heals to the HealFlow API after each run. See @healflow/cli for healflow ingest.
Development
pnpm --filter @healflow/playwright build
pnpm --filter @healflow/playwright typecheck
pnpm --filter @healflow/playwright testRelated packages
- @healflow/cli —
healflow init,doctor,report,apply - @healflow/setup — one-line install meta-package
docs/product/ADOPTION.md— rollout patterns and catches
License
MIT
