npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@enekesabel/playwright-lite

v0.9.3

Published

Playwright-compatible Page and Locator operations in the current browser document

Readme

playwright-lite

npm downloads CI license GitHub stars

Use Playwright's Page and Locator APIs in the browser document you're already in. playwright-lite runs inside your application, without launching a browser or connecting to a Playwright server.

import { createPage } from "@enekesabel/playwright-lite";

const page = createPage({
  testIdAttribute: "data-test",
  actionTimeout: 5_000,
  navigationTimeout: 10_000,
});

await page.getByRole("textbox", { name: "Name" }).fill("Ada");
await page.getByRole("button", { name: "Save" }).click();

Assertions

import { createPage, expect } from "@enekesabel/playwright-lite";

const page = createPage();
await expect(page.getByRole("button", { name: "Save" })).toBeEnabled();
await expect(page.locator(".notice")).toContainText("Saved");

See Expect for the supported matchers and how a failed assertion surfaces.

Use cases

  • Automate your own application in the browser you're using.
  • Let an in-app assistant inspect and interact with the page.
  • Build guided onboarding and automation flows.
  • Run the supported parts of existing Playwright scripts inside your application.

Installation

playwright-lite is pre-1.0; APIs may change.

npm add @enekesabel/playwright-lite

Runtime boundaries

  • Current document only. No iframe traversal, Frame, or FrameLocator support.
  • Navigation ends execution. goto(), reload(), goBack() and goForward() can start navigation, but replacing the document destroys the JavaScript context running your script, so automation cannot continue across a full-page navigation or reload.
  • Synthetic input. Input events are not browser-trusted, so they grant no user activation and never apply CSS :hover or :active; native keyboard behavior such as cursor movement, deletion and focus traversal is not simulated.
  • No browser control. No browser launch, browser contexts, or browser-level control over network traffic, downloads, or other tabs.
  • Content Security Policy applies. A string expression is evaluated with eval, which the page's policy must allow; a function runs as the function it is, needing no eval and keeping its closure and its strict mode, where Playwright evaluates its source in the page as sloppy-mode code unless its body says otherwise; a function whose source does not re-parse, such as a bound or native function, runs too.
  • Closing keeps the document. close() disposes the Page object, not the document; see Closing a page.
  • Hidden tabs keep their pace. Actions and waits run at foreground speed in a background tab, with a few exceptions; see Hidden tabs.
  • Shared JavaScript globals. The library runs alongside the page's own scripts, so some changes the page makes to built-in globals reach it; see Page globals.

Page functions playwright-lite replaces

| Functions | Replaced when you first… | Put back when… | | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | window.fetch and XMLHttpRequest.prototype.open, setRequestHeader and send | add a request, response, requestfinished or requestfailed listener, call waitForRequest(), waitForResponse() or requests(), or start a networkidle wait | the last of those listeners is removed and no networkidle wait is running. After a requests() call they stay until that page is closed, so its log keeps filling. | | Every console.* method Playwright's ConsoleMessage covers | add a console listener or call consoleMessages() | the last console listener is removed. After a consoleMessages() call they stay until that page is closed, so its log keeps filling. | | window.alert, window.confirm and window.prompt | add a dialog listener | the last dialog listener is removed. | | HTMLElement.prototype.click and HTMLInputElement.prototype.showPicker | add a filechooser listener | the last filechooser listener is removed. | | Element.prototype.setPointerCapture, releasePointerCapture and hasPointerCapture, and moveBefore on Element, Document and DocumentFragment | press a mouse button or tap, with page.mouse, page.touchscreen or a pointer action | every mouse button is up, no element holds the mouse's capture and the tap has ended. |

Nothing is replaced until you subscribe, and a function the page replaced itself is never put back. Closing a page removes its listeners and waits, so the functions are put back once no open page still uses them. The network and console replacements forward every call unchanged. The dialog replacements pass each dialog to your listeners instead of showing it; see Dialog. The click() replacement forwards every call, reporting a file input it activates outside the document, and the showPicker() replacement reports a file input; see FileChooser. The pointer capture replacements forward every call and keep capture for playwright-lite's own pointers, which the browser does not know, including through a moveBefore() move; see Mouse.

Network idle

waitForLoadState("networkidle") and waitUntil: "networkidle" resolve once no fetch() or XMLHttpRequest call of the current document has been in flight for 500 ms.

  • Only fetch() and XMLHttpRequest calls count as in flight. An image, script, stylesheet or other resource that finishes loading restarts the 500 ms, but one still loading never holds it.
  • /favicon.ico requests are excluded, as in Playwright.
  • A call started before you subscribed is not seen, so a wait started while such a call is in flight can resolve before it ends.
  • Calls from iframes, workers and other realms are not seen.
  • Playwright documents networkidle as "DISCOURAGED consider operation to be finished when there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead."
  • The end of each call and resource is noticed a few milliseconds late, so a wait can resolve slightly more than 500 ms after it.

Closing a page

close() and [Symbol.asyncDispose]() dispose the Page object createPage() returned, where Playwright closes the browser page. The document stays open, and another createPage() can still automate it.

  • close fires with the page, and isClosed() returns true from then on.
  • Every pending call of the page, its locators, handles, keyboard, mouse, touchscreen, localStorage and sessionStorage rejects with Target page, context or browser has been closed, or with the reason passed to close(). Every later async call rejects with the default message; sync members such as url() and locator() keep working, as in Playwright.
  • The functions the page exposed with exposeFunction() or exposeBinding() are removed.
  • runBeforeUnload: true is rejected, since nothing is unloaded; false closes as usual.
  • waitForEvent() called after close() rejects at once, where Playwright waits until its timeout.
  • An assertion started after close() fails with the closed error in its call log, where Playwright rejects with the closed error.
  • A call with an invalid argument after close() rejects with the closed error, where Playwright reports the invalid argument.
  • A pending request.response() or response.finished() is not interrupted by close(), where Playwright rejects it.
  • Highlights added with locator.highlight() stay in the document, where Playwright's go with the closed page.
  • The closed error has no call log, where Playwright appends the log of the interrupted call.

Page globals

Playwright runs its page scripts in an isolated world, which no change the page makes to a global reaches. playwright-lite shares the page's globals and keeps its own reference to Node, Element, NodeFilter, HTMLElement, Document, ShadowRoot, MutationObserver, Event, CustomEvent, EventTarget, Map, Set, WeakMap, WeakSet, Promise, Symbol, Error, TypeError, RegExp, Array, Object, URL, Date, JSON and Math. When you call createPage(), each is the page's current global while that is still a function (an object, for JSON and Math), and otherwise the one playwright-lite took when it loaded, as in Playwright's fallback for browsers without an isolated world. A page that deletes or replaces one of them after that does not affect playwright-lite.

  • A global the page deleted before playwright-lite loaded stays missing: with Node deleted, click() throws Cannot read properties of undefined (reading 'ELEMENT_NODE').
  • A change to a built-in's methods or prototype reaches playwright-lite: after Array.prototype.map = null or JSON.stringify = null, click() throws a TypeError.
  • Every other global, such as MouseEvent, KeyboardEvent, InputEvent, DataTransfer or getComputedStyle, is read from the page when used: with MouseEvent deleted, click() throws a TypeError.
  • setTimeout is read from the page too, since Playwright's fallback does not keep it either: with it deleted, click(), fill() and waitForTimeout() throw a TypeError.
  • A failing expect assertion builds its message, and toMatchAriaSnapshot() reads its template, with the page's current globals, so after the page deletes Object, Array or Math they can throw that ReferenceError instead.

Hidden tabs

Browsers stop animation frames and slow timers down in a background tab. Playwright's browser runs with that turned off, and playwright-lite keeps actions, waits and assertions at their foreground pace while the document is hidden.

  • When the page's Content Security Policy blocks blob: workers, each timed wait, such as a delay option, waitForTimeout(), a polling interval or the stability check before an action, takes about a second while the tab is hidden.
  • When other programs keep the CPU busy, the operating system can give a hidden tab almost no CPU time, as macOS does, so an action, a wait or its timeout can run tens of seconds late until the tab gets time again. Playwright's browser keeps a hidden tab at foreground priority, so it competes for the CPU like a visible one.
  • While the tab is hidden, toBeInViewport() measures the element against the viewport and the ancestors that clip its overflow, and ignores clipping by CSS transforms, clip-path and contain: paint, or inside a closed shadow root the element is slotted into.

Navigation timeouts

waitForNavigation(), waitForURL(), waitForLoadState(), goBack(), goForward() and reload() time out with only page.<method>: Timeout <n>ms exceeded., where Playwright appends the navigation steps it logged, such as waiting for navigation until "load".

Compatibility

Targets Playwright 1.62.1. Statuses describe API compatibility within the runtime boundaries above. API links open Playwright's current documentation.

✅ Compatible · ⚠️ Partially compatible · ❌ Not implemented · 🚫 Intentionally excluded

Page

| API | Status | Notes | | --------------------------------------------------------------------------------------------------------------- | :----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | $ | ⚠️ | Returned ElementHandle methods and options differ; see ElementHandle and JSHandle. | | $$ | ⚠️ | Returned ElementHandle methods and options differ; see ElementHandle and JSHandle. | | $$eval | ✅ | | | $eval | ✅ | | | [Symbol.asyncDispose]() | ⚠️ | Closes as close() does, disposing only the Page object; see Closing a page. | | addInitScript | 🚫 | Registers a script to run before the document's own scripts, which have already run by the time this adapter attaches. | | addListener | ⚠️ | Fires only the supported events; other names never fire. | | addLocatorHandler | ⚠️ | A handler that throws or rejects is logged instead of raised; see Events. | | addScriptTag | ⚠️ | Rejects path, which reads the script from disk. Returned ElementHandle methods and options differ; see ElementHandle and JSHandle. | | addStyleTag | ⚠️ | Rejects path, which reads the stylesheet from disk. Returned ElementHandle methods and options differ; see ElementHandle and JSHandle. | | ariaSnapshot | ✅ | | | bringToFront | 🚫 | Browser tab focus control is excluded. | | cancelPickLocator | ❌ | | | check | ✅ | | | clearConsoleMessages | ✅ | | | clearPageErrors | ✅ | | | click | ⚠️ | The action does not wait for navigation. | | clock | ❌ | | | close | ⚠️ | Disposes the Page object, not the document, and rejects runBeforeUnload: true; see Closing a page. | | consoleMessages | ⚠️ | filter: "all" and the default "since-navigation" return the same messages; see ConsoleMessage. | | content | ✅ | | | context | 🚫 | Refers to the owning browser context, which does not exist in this adapter. | | coverage | 🚫 | Collecting code coverage requires the browser process. | | dblclick | ✅ | | | dispatchEvent | ✅ | | | dragAndDrop | ⚠️ | Emulates HTML drag and drop in the document, without the browser's default drop handling; see Drag and drop. | | emulateMedia | 🚫 | A document cannot change its own media type or prefers-color-scheme. | | evaluate | ✅ | | | evaluateHandle | ⚠️ | The returned handle previews differently; see ElementHandle and JSHandle. | | exposeBinding | ⚠️ | Differs as exposeFunction does. The callback's source is { page, frame: page }, with no context, since this package has no BrowserContext. | | exposeFunction | ⚠️ | dispose() leaves a value the page itself assigned to the property on window, where Playwright deletes it. Arguments and the result skip JSON.stringify(), so a page overriding Array.prototype.toJSON() does not make the call reject, as it does in Playwright. | | fill | ✅ | | | focus | ✅ | | | frame | 🚫 | Iframe realms are outside the single-document boundary. | | frameLocator | 🚫 | Iframe realms are outside the single-document boundary. | | frames | 🚫 | Iframe realms are outside the single-document boundary. | | getAttribute | ✅ | | | getByAltText | ✅ | | | getByLabel | ✅ | | | getByPlaceholder | ✅ | | | getByRole | ✅ | | | getByTestId | ✅ | | | getByText | ✅ | | | getByTitle | ✅ | | | goBack | ⚠️ | Needs the browser's Navigation API and rejects without it; returns no Response; resolves to null without navigating when the Navigation API does not list the adjacent entry (an entry of another origin, an entry beyond one, or any entry in an opaque-origin document such as a sandboxed frame), where Playwright navigates to it; networkidle resolves no sooner than 500 ms after the call, even when already idle. | | goForward | ⚠️ | Needs the browser's Navigation API and rejects without it; returns no Response; resolves to null without navigating when the Navigation API does not list the adjacent entry (an entry of another origin, an entry beyond one, or any entry in an opaque-origin document such as a sandboxed frame), where Playwright navigates to it; networkidle resolves no sooner than 500 ms after the call, even when already idle. | | goto | ⚠️ | Returns no Response (null only for same-document navigation, including one the page's own navigate listener intercepts where Playwright loads a new document; a navigation that listener cancels times out instead); relative URLs resolve against document.baseURI, with no baseURL; rejects referer and signal; networkidle resolves no sooner than 500 ms after the call, even when already idle. | | hideHighlight | ✅ | | | hover | ✅ | | | innerHTML | ✅ | | | innerText | ✅ | | | inputValue | ✅ | | | isChecked | ✅ | | | isClosed | ⚠️ | Reports whether this Page object was closed; the document stays open; see Closing a page. | | isDisabled | ✅ | | | isEditable | ✅ | | | isEnabled | ✅ | | | isHidden | ✅ | | | isVisible | ✅ | | | keyboard | ✅ | | | localStorage | ✅ | | | locator | ✅ | | | mainFrame | ⚠️ | Returns the same Page object, not a Frame. | | mouse | ⚠️ | No text selection or context menu starts, and HTML drags are emulated; see Mouse. | | off | ⚠️ | Only the supported events ever fire; other names are accepted. | | on | ⚠️ | Fires only the supported events; other names never fire. | | once | ⚠️ | Fires only the supported events; other names never fire. | | opener | 🚫 | Refers to another page, outside the single-document boundary. | | pageErrors | ⚠️ | filter: "all" and the default "since-navigation" return the same errors: this single-document adapter never crosses documents within one page's lifetime, so nothing ever marks the buffer at a navigation. | | pause | 🚫 | Pausing for the Playwright Inspector requires the browser process. | | pdf | 🚫 | Generating a PDF requires the browser process. | | pickLocator | ❌ | | | prependListener | ⚠️ | Fires only the supported events; other names never fire. | | press | ✅ | | | reload | ⚠️ | Does not resolve in the old document, which the reload destroys, and returns no Response, since the reload ends execution; rejects with a timeout only if the document is not replaced. | | removeAllListeners | ⚠️ | Only the supported events ever fire; other names are accepted. | | removeListener | ⚠️ | Only the supported events ever fire; other names are accepted. | | removeLocatorHandler | ✅ | | | request | 🚫 | Returns Playwright's Node-side API request context, which has no in-document counterpart. | | requestGC | 🚫 | Forcing garbage collection requires the browser process. | | requests | ⚠️ | fetch() and XMLHttpRequest calls of the current document only; see Request and Response. | | route | 🚫 | Browser-level network interception is excluded. | | routeFromHAR | 🚫 | Browser-level network interception is excluded. | | routeWebSocket | 🚫 | Browser-level network interception is excluded. | | screencast | 🚫 | Capturing a screencast requires the browser process. | | screenshot | ⚠️ | Returns a Uint8Array rendered from the DOM, and rejects path and animations: "disabled"; see Screenshots. | | selectOption | ✅ | | | sessionStorage | ✅ | | | setChecked | ✅ | | | setContent | 🚫 | Document replacement is excluded.