Browser

PreviousNext

Use the first-party browser proof harness for editor behavior tests.

@platejs/browser is the first-party proof harness for browser-visible editor behavior: model state, rendered DOM, native selection, focus, screenshots, traces, clipboard, and replayable scenarios. It is test infrastructure, not the product editing API; application code builds editors with Plate and Plite packages. Read Editing Behavior for the runtime pipeline, Selection And DOM for caret proof, Clipboard And Paste for payload proof, and Projection And Overlays for visible highlight and overlay proof.

Install

pnpm add -D @platejs/browser @playwright/test
pnpm add -D @platejs/browser @playwright/test

Imports

The package is subpath-only:

  • @platejs/browser/playwright for Playwright editor harnesses.
  • @platejs/browser/core for pure proof contracts, release-proof artifacts, classifiers, and selection serialization helpers.
  • @platejs/browser/browser for DOM selection snapshots and zero-width placeholder inspection in browser-capable test environments.
  • @platejs/browser/transports for device/browser proof-scope descriptors.

Do not import from @platejs/browser directly.

First Test

import { expect, test } from "@playwright/test";
import { openExample } from "@platejs/browser/playwright";
 
test("types through the Browser path", async ({ page }) => {
  const editor = await openExample(page, "plaintext", {
    ready: { editor: "visible" },
  });
 
  await editor.focus();
  await editor.type("Hello from @platejs/browser");
 
  await editor.assert.text("Hello from @platejs/browser");
  await editor.assert.noDoubleSelectionHighlight();
  expect(await editor.get.selectedText()).toBe("");
});
import { expect, test } from "@playwright/test";
import { openExample } from "@platejs/browser/playwright";
 
test("types through the Browser path", async ({ page }) => {
  const editor = await openExample(page, "plaintext", {
    ready: { editor: "visible" },
  });
 
  await editor.focus();
  await editor.type("Hello from @platejs/browser");
 
  await editor.assert.text("Hello from @platejs/browser");
  await editor.assert.noDoubleSelectionHighlight();
  expect(await editor.get.selectedText()).toBe("");
});

openExample waits for the mounted editor-ready contract before actions run. Prefer editor.type(...), semantic selection helpers, clipboard helpers, and native event traces over raw Playwright DOM shortcuts when the claim is editor behavior.

Do not use locator.fill() for contenteditable behavior. It can bypass the editor path you are trying to prove. Use keyboard input, clipboard helpers, or the Browser harness action that matches the claim.

Proof Contracts

Browser proof should usually assert more than model state:

ClaimUseful proof
Model state changed correctlymodel text, block text, operations, or commit metadata
Browser caret is correctDOM caret, DOM selection, or native selection snapshot
Visible selection is sanedisplayed selection snapshot and no double-highlight
Editor stayed activefocus ownership
Native input path is the bugnative event trace for input, paste, selection, or IME
Visual evidence mattersscreenshot or JSON artifact
The editor still works afterwardfollow-up typing after navigation, paste, undo, selection, or DOM repair

Feature contracts group browser behavior families by the owning Plite feature area. Use them to keep example coverage honest without turning one manual route check into a fake global guarantee.

Low-Level Helpers

Use low-level helpers when a test needs to locate the editable, inspect a rendered node by path, or call the mounted browser handle directly.

import {
  evaluatePliteBrowserHandle,
  getPliteBrowserEditable,
  locatePliteBrowserBlock,
  locatePliteBrowserText,
} from "@platejs/browser/playwright";
import {
  evaluatePliteBrowserHandle,
  getPliteBrowserEditable,
  locatePliteBrowserBlock,
  locatePliteBrowserText,
} from "@platejs/browser/playwright";
HelperUse
getPliteBrowserEditableLocate the first editor root in a page, frame, or scoped area.
locatePliteBrowserBlockLocate a rendered block by Plite path.
locatePliteBrowserTextLocate a rendered text node by Plite path.
evaluatePliteBrowserHandleCall a method exposed by the mounted browser handle.

Prefer the harness methods when they already express the behavior. They keep model, DOM, native-selection, and screenshot proof in one place instead of spreading selectors through tests.

Transport Claims

@platejs/browser/transports classifies proof scope. A Playwright mobile viewport does not prove raw-device behavior. Appium descriptors close raw-device lanes only when the device gate runs. Proxy browser lanes are useful evidence, but they do not claim native mobile clipboard, human soft-keyboard, glide typing, or voice input.

Commands

pnpm --filter plite test:plite-browser
pnpm --filter plite test:plite-browser:chromium
pnpm --filter @platejs/browser test
pnpm --filter plite test:plite-browser
pnpm --filter plite test:plite-browser:chromium
pnpm --filter @platejs/browser test

Use focused Playwright specs for behavior routes and generated stress replay for portable editing failures.