Playwright Chrome Extension with exposed internals for advanced state management and precise control. A fork of playwright-crx with all internal state accessible for library consumers who need full control over the lifecycle.
npm install playwright-crx-openA fork of playwright-crx with exposed internals for advanced state management and precise control.
This package contains the Chrome Extensions flavor of the Playwright library, with all internal state accessible for library consumers who need full control over the lifecycle.
The original playwright-crx heavily encapsulates its internal state, making it difficult to:
- Clean up stale state when used as a library
- Recover from errors without reloading the extension
- Reattach to tabs without creating new ones
- Precisely control the debugger lifecycle
This fork exposes all internal state and provides utility methods for:
- State inspection: Access internal maps, caches, and singleton references
- State manipulation: Clear cached state, reset connections, force reattachment
- Lifecycle control: Precise control over when resources are created and destroyed
``bash`
npm install playwright-crx-open
All internal state is now accessible via public properties:
`ts
import { crx } from 'playwright-crx-open';
const crxApp = await crx.start();
// Access internal state directly
console.log(crx._transport); // CrxTransport instance
console.log(crx._browserPromise); // Browser promise
console.log(crx._crxApplicationPromise); // Regular mode app promise
// Access transport internals
const transport = crxApp.getTransport();
console.log(transport._tabToTarget); // Map
console.log(transport._targetToTab); // Map
console.log(transport._sessions); // Map
`
#### On Crx class:
`ts
// Check if started without throwing
if (crx.isStarted()) {
// ...
}
// Clear cached promise without closing (use with caution)
crx.clearApplicationPromise();
// Full reset - closes everything and clears all state
await crx.reset();
`
#### On CrxApplication class:
`ts
// Force attach - clears cached state first
const page = await crxApp.forceAttach(tabId);
// Check if closed
if (crxApp.isClosed()) {
// ...
}
// Reset closed state (use with caution)
crxApp.resetClosedState();
// Clear recorder app reference
crxApp.clearRecorderApp();
// Get parent instances
const crx = crxApp.getCrx();
const transport = crxApp.getTransport();
`
#### On CrxTransport class:
`ts
const transport = crxApp.getTransport();
// Clear all cached mappings
transport.clearMappings();
// Clear specific tab
transport.clearTab(tabId);
// Get all attached tabs
const tabIds = transport.getAttachedTabIds();
// Get all targets
const targets = transport.getAllTargets();
// Check if attached
if (transport.isAttached(tabId)) {
// ...
}
// Force detach with cache clearing
await transport.forceDetach(tabId);
await transport.forceDetachAll();
`
When you need to reattach to a tab that was previously attached (e.g., after navigation or error):
`ts
// Instead of this (may return stale cached data):
const page = await crxApp.attach(tabId);
// Use this (clears cache first):
const page = await crxApp.forceAttach(tabId);
`
`ts
try {
await crxApp.recorder.run(code);
} catch (error) {
// Clear transport state
crxApp.getTransport().clearMappings();
// Or do a full reset
await crx.reset();
// Start fresh
const newApp = await crx.start();
}
`
`ts
// In your background script startup:
const cleanupOrphanedDebuggers = async () => {
const targets = await chrome.debugger.getTargets();
const attached = targets.filter(t => t.attached && t.tabId);
for (const target of attached) {
await chrome.debugger.detach({ tabId: target.tabId }).catch(() => {});
}
};
await cleanupOrphanedDebuggers();
`
This fork maintains full compatibility with the original playwright-crx API:
`ts
import { crx, expect } from 'playwright-crx-open/test';
chrome.action.onClicked.addListener(async ({ id: tabId }) => {
const crxApp = await crx.start({ slowMo: 500 });
try {
const page = await crxApp.attach(tabId!).catch(() => crxApp.newPage());
await page.goto('https://demo.playwright.dev/todomvc/#/');
await page.getByPlaceholder('What needs to be done?').click();
await page.getByPlaceholder('What needs to be done?').fill('Hello World!');
await page.getByPlaceholder('What needs to be done?').press('Enter');
await expect(page.getByTestId('todo-title')).toHaveText('Hello World!');
} finally {
await crxApp.detach(page);
await crxApp.close();
}
});
`
Playwright CRX also supports tracing, compatible with Playwright Trace Viewer.
`ts
await page.context().tracing.start({ screenshots: true, snapshots: true });
await page.goto('https://demo.playwright.dev/todomvc');
// ... perform actions ...
await page.context().tracing.stop({ path: '/tmp/trace.zip' });
const data = crx.fs.readFileSync('/tmp/trace.zip');
`
To build playwright-crx-open:
`bash``
npm ci
npm run build
This is a fork of playwright-crx by Rui Figueira.
Apache-2.0