Skip to main content
Version: 1.x

Browser Bind & Screencast Fixtures

Praman ships two opt-in fixtures that unlock agentic workflows — where a running test exposes its live browser to external Playwright CLI agents, and video frames stream to AI vision pipelines in real time.

Overview

The agentic workflow follows three phases:

┌──────────────────────────────────────────────────────────┐
│ 1. TEST STARTS 2. AGENT CONNECTS 3. TEST ENDS │
│ │
│ Test runs with CLI agent attaches browser. │
│ PRAMAN_BIND=1 via endpoint URL unbind() │
│ → browser.bind() → inspects live UI called in │
│ → logs endpoint → discovers controls finally block│
│ │
│ screencast records frame handlers screencast │
│ chapters + actions feed AI vision .stop() │
└──────────────────────────────────────────────────────────┘
FixtureScopeOpt-in viaPlaywright version
browserBindTestPRAMAN_BIND=1 env1.59+
screencastTestAlways available1.59+ (degrades)

Prerequisites

  • Playwright 1.59 or laterbrowser.bind() and page.screencast were introduced in 1.59.
  • PRAMAN_BIND environment variable — set to 1 or true to enable browser binding.
  • Praman installednpm install playwright-praman.
Playwright version

Both fixtures require Playwright 1.59+. On older versions, browserBind throws ERR_BIND_NOT_SUPPORTED when enabled, while screencast methods silently no-op (except onFrame, which throws ERR_SCREENCAST_NOT_STARTED).


Quick Start

import { browserBindTest } from 'playwright-praman';

// Run with: PRAMAN_BIND=1 npx playwright test
browserBindTest('agent-assisted SAP test', async ({ browserBind }) => {
if (browserBind.bound) {
// A Playwright CLI agent can now connect at browserBind.endpointUrl
// and inspect the live browser while the test runs.
}
});
Zero overhead when disabled

When PRAMAN_BIND is not set (or is '0'), the fixture returns { bound: false, endpointUrl: undefined, bindTitle: undefined } with no runtime cost.


Configuration

Environment Variables

VariableRequiredDefaultDescription
PRAMAN_BINDNo(unset)Set to 1 or true to enable browser binding
PRAMAN_BIND_TITLENo'praman-agent'Override the bind title passed to browser.bind()
# Enable binding with a custom title
PRAMAN_BIND=1 PRAMAN_BIND_TITLE=my-sap-agent npx playwright test

BrowserBindResult

The browserBind fixture provides a BrowserBindResult to the test body:

interface BrowserBindResult {
/** Whether the browser is currently bound. */
readonly bound: boolean;
/** The endpoint URL for Playwright CLI. undefined when bound is false. */
readonly endpointUrl: string | undefined;
/** The bind title used. undefined when bound is false. */
readonly bindTitle: string | undefined;
}

How It Works with CLI Agents

When PRAMAN_BIND=1, the fixture calls browser.bind(title) at the start of the test, which opens an ephemeral endpoint. The endpoint URL is logged at info level so that a Playwright CLI agent can connect without polling:

INFO  browser-bind: Browser bound — Playwright CLI agent can connect
endpointUrl: "ws://127.0.0.1:43657/xyz"
title: "praman-agent"

A CLI agent attaches to this endpoint to inspect the live UI, discover controls, or take snapshots — while the test continues running. On teardown, browser.unbind() is called in a finally block regardless of test outcome.

# Terminal 1: Run the test with binding enabled
PRAMAN_BIND=1 npx playwright test tests/e2e/purchase-order.spec.ts

# Terminal 2: CLI agent connects to the bound browser
playwright-cli attach praman-agent
playwright-cli snapshot --filename=live-state.yml

Screencast Fixture

The screencast fixture wraps page.screencast (Playwright 1.59+) to provide structured video recording with chapter markers, action annotations, and real-time frame streaming.

Chapter Markers

Use showChapter(title) inside test.step() to label logical sections of the video:

import { screencastTest } from 'playwright-praman';

screencastTest('purchase order workflow', async ({ page, screencast }) => {
await screencast.showChapter('Navigate to PO list');
await page.goto('/fiori#PurchaseOrder-manage');

await screencast.showChapter('Create new PO');
await page.getByRole('button', { name: 'Create' }).click();
});

Action Annotations

showActions(options?) enables DOM-level overlays for click, fill, and keyboard events:

await screencast.showActions({
position: 'bottom-right',
duration: 800,
fontSize: 20,
});

// Subsequent actions are annotated in the video
await page.getByRole('button', { name: 'Save' }).click();
OptionTypeDefaultDescription
durationnumber500How long each annotation displays (ms)
fontSizenumber24Font size of the action title (px)
positionstring'top-right'Overlay position on the video frame

UI5 Control Tree Overlay

Toggle a visual overlay of the current UI5 control tree on video frames:

screencast.showUI5ControlTree(true);
// Frame handlers can now use the enabled flag for annotation
Phase 1

The UI5 overlay is currently state-only — it sets a flag that downstream frame handlers or a bridge extension can use to annotate each frame. Visual overlay injection will be added in a future release.

Frame Streaming

Register handlers for every raw video frame with onFrame(handler). Frames are JPEG buffers with a monotonic timestamp. The screencast starts lazily when the first handler is registered.

screencast.onFrame(async ({ buffer, timestamp }) => {
// Send frame to an AI vision pipeline for anomaly detection
const analysis = await aiVision.analyze(buffer);
if (analysis.anomaly) {
throw new Error(analysis.reason);
}
});
Multiple handlers

You can register multiple frame handlers. They are called in registration order. Errors from handlers are caught and logged at debug level (non-fatal to the test).


Fixture Composition with mergeTests

Both fixtures can be composed with coreTest and each other using Playwright's mergeTests():

import { mergeTests } from '@playwright/test';
import { coreTest } from 'playwright-praman';
import { browserBindTest } from 'playwright-praman';
import { screencastTest } from 'playwright-praman';

const test = mergeTests(coreTest, browserBindTest, screencastTest);

test('full agentic workflow', async ({ browserBind, screencast, page }) => {
// browserBind: CLI agent connects to the live browser
if (browserBind.bound) {
console.info('Agent endpoint:', browserBind.endpointUrl);
}

// screencast: structured video with chapter markers
await screencast.showChapter('Navigate to app');
await page.goto('/fiori#PurchaseOrder-manage');

await screencast.showActions({ position: 'bottom' });

screencast.onFrame(async ({ buffer }) => {
// Real-time AI vision analysis
});
});
Cross-fixture dependencies

The screencast fixture declares rootLogger as a { option: true } placeholder (PW-MERGE-1 pattern). When composed with coreTest via mergeTests(), it receives the shared pino logger. Without coreTest, it falls back to its own logger instance.


Error Handling

Both fixtures throw structured PramanError instances with error codes, suggestions, and retry information:

browserBind Errors

Error CodeWhenRetryable
ERR_BIND_NOT_SUPPORTEDbrowser.bind() missing (Playwright < 1.59)No
ERR_BIND_FAILEDbrowser.bind() rejects at runtimeNo
// Example error shape
PramanError {
code: 'ERR_BIND_NOT_SUPPORTED',
message: 'browser.bind() is not available — requires Playwright 1.59 or later',
attempted: 'Bind browser for Playwright CLI agent access (PRAMAN_BIND=1)',
retryable: false,
suggestions: [
'Upgrade Playwright to 1.59 or later: npm install -D @playwright/test@latest',
'Remove PRAMAN_BIND=1 to disable browser binding',
],
}

screencast Errors

Error CodeWhenRetryable
ERR_SCREENCAST_CHAPTER_FAILEDshowChapter() rejectsNo
ERR_SCREENCAST_NOT_STARTEDonFrame() called on Playwright < 1.59No
ERR_SCREENCAST_FRAME_HANDLERpage.screencast.start() rejectsNo

Troubleshooting

ProblemSolution
ERR_BIND_NOT_SUPPORTED thrownUpgrade Playwright to 1.59+: npm install -D @playwright/test@latest
ERR_BIND_FAILED thrownCheck that no other process has already bound this browser instance
browserBind.bound is always falseSet PRAMAN_BIND=1 in the environment before running the test
Endpoint URL not visible in logsSet log level to info or lower in your Praman config
showChapter() has no effectVerify Playwright 1.59+ and that video recording is enabled in config
onFrame() throws on registrationpage.screencast is unavailable — upgrade Playwright to 1.59+
Frame handlers never fireEnsure the screencast has time to start — avoid immediate test teardown
unbind() warning in teardown logsNon-fatal — the browser may have already been closed by the test
Custom bind title not appliedSet PRAMAN_BIND_TITLE env var before the test process starts

Next Steps