Skip to content

Releases: padamson/playwright-rust

playwright-rs 0.14.1

Choose a tag to compare

@github-actions github-actions released this 11 Jul 10:56

Security

  • Bumped crossbeam-epoch 0.9.18 → 0.9.20 (RUSTSEC-2026-0204) and anyhow 1.0.102 → 1.0.103 (RUSTSEC-2026-0190) in the repository lockfile. Both reach this repo only through dev-dependencies (benchmarks and tests), so no consumer of playwright-rs was exposed.

Fixed

  • Driver acquisition survives the shutdown of Microsoft's playwright.azureedge.net CDN. The prebuilt playwright-<version>-<platform>.zip driver archives were discontinued with that CDN (they now 404), which broke every fresh build — cold caches, new machines, and CI failed with environment variable PLAYWRIGHT_DRIVER_VERSION not defined (issue #116). The build script (and the cli feature's playwright-rs install) now assemble the driver from two artifacts instead: the playwright-core npm tarball (registry.npmjs.org) and a pinned Node.js binary (nodejs.org, currently 24.17.0) — the same model playwright-python uses — laid out identically to the old bundle so runtime behavior is unchanged (ADR 0006). The bundled driver stays at 1.60.0; no API changes. A failed download now compiles anyway (the runtime falls back to PLAYWRIGHT_DRIVER_PATH or an npm-installed Playwright, failing at launch with ServerNotFound) instead of poisoning downstream builds with the missing-env-var compile error, and download errors name the exact URL that failed.

playwright-rs 0.14.0

Choose a tag to compare

@github-actions github-actions released this 20 Jun 01:02

Added

  • Tracing + HAR types are now re-exported at the crate rootTracing, TracingStartOptions, TracingStopOptions, StartHarOptions, HarMode, and HarContent join every other consumer-facing type at playwright_rs::* (previously reachable only via playwright_rs::protocol::*, which still works). Surfaced by dogfooding: a consumer following the obvious playwright_rs::Viewport pattern hit a compile error on playwright_rs::StartHarOptions.

  • Playwright 1.60 API polish — the remaining 1.60 surface: to_have_css_pseudo(name, value, pseudo) asserts the computed style of a ::before/::after pseudo-element; a description option on get_by_role; a boxes option on aria_snapshot (appends each element's [box=x,y,width,height], useful for AI/visual reasoning); WebError::location() returning the uncaught exception's script URL/line/column; WebSocketRoute::protocols() (the subprotocols the page requested); a no_defaults option on connect_over_cdp (attach to a running browser without Playwright's default overrides); and Page::hide_highlight(). Internally, ConsoleMessage location now reads the 1.60 line/column keys, falling back to the deprecated lineNumber/columnNumber. With this, the crate covers the full Playwright 1.60 API surface.

  • BrowserContext lifecycle events + Browser::on_context — the Playwright 1.60 context-level event surface. Browser::on_context fires when a new context is created on the browser. BrowserContext::on_download, on_frame_attached, on_frame_detached, on_frame_navigated, on_page_load, and on_page_close observe the corresponding page events across all pages of a context (forwarded from each current and future page) — the idiomatic way to write multi-tab fixtures without subscribing on every page individually.

  • Page-level to_match_aria_snapshotexpect_page(&page).to_match_aria_snapshot(...) asserts the whole document's accessibility tree (rooted at :root), the page counterpart of the existing locator assertion. Matching is partial (the expected acts as a template), so it makes a robust accessibility regression guard. New API surface in Playwright 1.60.

  • HAR recording: Tracing::start_har / Tracing::stop_har — record a HAR (HTTP Archive) of network traffic to a file. StartHarOptions controls content (omit/embed/attach), mode (full/minimal), a url_filter glob, and resources_dir. A .zip path bundles bodies as attachments; any other path extracts the .har JSON (via the new LocalUtils::har_unzip). The result opens in browser devtools or replays in tests through route_from_har. New API surface in Playwright 1.60.

  • Locator::drop — simulate external drag-and-drop of files and/or MIME-typed data onto an element (e.g. an upload drop zone), the canonical primitive for upload-zone tests. Distinct from drag_to (intra-page element drag). Pass files as FilePayloads and data as (mime_type, value) pairs via DropOptions, with optional position and timeout. New API surface in Playwright 1.60.

  • Screenshot options: animations, caret, scale, style, mask, mask_color on Page::screenshot and Locator::screenshot (via ScreenshotOptions). A pre-existing playwright-python parity gap, surfaced while dogfooding the landing site (an animated tab indicator raced an element screenshot; animations(Animations::Disabled) is the fix). Animations is now always available (previously only with the screenshot-diff feature) and shared between ScreenshotOptions and the to_have_screenshot assertions; new Caret and Scale enums are re-exported from the crate root. mask(Vec<Locator>) overpaints the given locators with a solid box (color set by mask_color) to redact dynamic or sensitive content; each locator is serialized to the protocol's { frame, selector } channel-ref shape. This completes screenshot-options parity with playwright-python.

  • Trace-level tracing spans on the internal JSON-RPC layer — Phase 2 of the observability work. Connection::send_message and inbound message dispatch, plus the pipe and websocket transport send paths, now carry #[tracing::instrument(level = "trace")] spans with structural fields only (method, guid, request id, frame bytes_len); skip_all keeps arbitrary-JSON RPC params out of the spans. Opt in with playwright_rs=trace for per-request protocol timing and event sequencing. Closes #98 (Phase 2 sub-task of #83).

Changed

  • Breaking: FilePayload::builder() replaced by FilePayload::new(name, mime_type, buffer). All three fields are required, so the builder's only failure mode was a runtime panic on a missing field; the constructor makes them required at compile time. from_path / from_file are unchanged.
  • Breaking: public option/data structs and enums are now #[non_exhaustive] (ADR 0005). Struct-literal construction (including the ..Default::default() form) no longer compiles downstream; construct via the existing builders (ScreenshotOptions::builder(), ...), the new chainable setters (GetByRoleOptions::default().name("OK").exact(true), Cookie::new(name, value).domain(...), ProxySettings::new(server), TracingStartOptions::default().screenshots(true), ...), or Default + field mutation. Matching on public enums (including Error) now needs a wildcard arm. This makes upstream Playwright option/field additions semver-minor after 1.0 instead of breaking. Geometrically closed types (Position, ScreenshotClip, PdfMargin, ScreencastSize, Viewport, DeviceViewport, Geolocation) stay exhaustive and keep literal construction.
  • Breaking: Locator::highlight() now takes Option<HighlightOptions> (previously no arguments), to carry the new 1.60 style option and to match Playwright's highlight(options) plus this crate's option-method convention. Existing calls migrate .highlight().highlight(None).
  • build.rs driver download is now relocatable and skippable via env. PLAYWRIGHT_DRIVER_CACHE_DIR downloads the driver to a stable, version-keyed path instead of $OUT_DIR so CI can cache it on its own key — necessary because Swatinem/rust-cache prunes workspace build-script output, so a driver left in $OUT_DIR is not cached by it and re-downloads (~42 MB) every run (correcting the v0.13.0 note that claimed $OUT_DIR was automatically cached). PLAYWRIGHT_SKIP_DRIVER_DOWNLOAD skips the download entirely for compile-only consumers (e.g. cargo check) that never launch a browser. Both default off; local builds are unchanged (the driver still lands in $OUT_DIR).

Fixed

  • Rustdoc examples are now actually compile-checked. The previous convention marked browser doctests ```ignore and "executed" them in CI with --ignored — but rustdoc never compiles ignore blocks at all, so that job had always been a green no-op and the examples had no drift protection. All 90+ doc examples are now ```no_run (compiled on every cargo test --doc, not executed), with hidden scaffolding so rendered docs are unchanged. The conversion surfaced and fixed ~10 silently rotted examples, including a removed method (expect_websocket), a sync→async drift (BrowserContext::tracing), and a wrong accessor (ConsoleMessage::type_).
  • Connection-layer concurrency hardening. The transport-to-dispatch message channel is now bounded (256), so a dispatch loop that falls behind exerts backpressure on the driver instead of buffering memory without limit. wait_for_object blocks on a Notify instead of polling every 10ms. dispose() unregisters objects synchronously instead of spawning a task, closing a window where a disposed object could still receive events (and removing a hidden tokio-runtime requirement from a sync path). The pending-callback map uses a sync lock (it was never held across an await), and the transport-writer mutex now documents that holding it across the send is the write-serialization mechanism.
  • Frame no longer keeps its Page alive after disposal. The frame's back-reference is cleared when the frame is disposed, breaking the PageFrame reference cycle that previously kept both objects in memory after a page closed (frame.page() returns None once the frame is disposed).
  • Page::locator() / frame_locator() can no longer panic. They previously .expect()-ed a per-call registry lookup of the main frame, which panicked if the page had been closed. The main frame is now resolved once at Page construction (matching playwright-python), making locator creation genuinely infallible; actions on a closed page still fail with a normal Error. Page::url() now always reads through the main frame too, instead of a fallback cache. The remaining flagged panics on public paths (FilePayload builder, root-object init, a CDP params invariant) were converted to errors or made unreachable.

playwright-rs 0.13.0

Choose a tag to compare

@github-actions github-actions released this 23 May 23:15

Security

  • Bumped transitive openssl from 0.10.79 to 0.10.80 to pick up the fix for GHSA-phqj-4mhp-q6mq — potential out-of-bounds write in CipherCtxRef::cipher_update_inplace for AES-KW-PAD ciphers. We don't use AES-KW-PAD anywhere; the path enters the tree transitively via tokio-tungstenitenative-tlsopenssl. Affected the workspace Cargo.lock and the fuzz target's lockfile; both now resolve to 0.10.80+. Detected by Dependabot (alerts #17 / #18).
  • Bumped transitive openssl from 0.10.78 to 0.10.79 to pick up the fix for GHSA-xp3w-r5p5-63rr / CVE-2026-42327 — undefined behaviour in X509Ref::ocsp_responders for certificates with non-UTF-8 OCSP URLs. Affected the workspace Cargo.lock and the fuzz target's lockfile; both now resolve to 0.10.79+. We pull openssl transitively via native-tls (the default TLS feature); no public-API impact. Detected by Dependabot (alerts #15 / #16); cargo audit had not yet picked up the advisory at fix time.
  • Refreshed supply-chain/imports.lock exemptions for the bumped openssl and openssl-sys versions via cargo vet regenerate exemptions. cargo vet, cargo audit, cargo deny check all green post-bump.
  • Adopted transitively-trusted publishers (cargo vet trust --all) for BurntSushi, Lokathor, epage, seanmonstar, and kennykerr (the latter three with --allow-multiple-publishers for flagship multi-maintainer crates like clap, tower, windows-*). Also added the fermyon trust import. Net effect: 215 → 168 exemptions (-47, ~22% reduction) with zero first-hand audit work — every dropped exemption is now backed by a trusted publisher already vetted by 2+ trust roots we import (Mozilla, Google, ISRG, etc.). cargo vet, cargo audit, cargo deny check all green.

Breaking changes

  • Locator::aria_snapshot() now takes Option<AriaSnapshotOptions>. The Playwright 1.59 ariaSnapshot RPC accepts mode (Ai or Default), track, depth, and timeout; we now surface those through a struct passed to aria_snapshot(...). To migrate, change locator.aria_snapshot()locator.aria_snapshot(None). The newly-added Page::aria_snapshot(options) lands in this release with the same shape, so it's not a migration concern there. See the matching entry under Added for the full motivation.
  • ScreencastFrame::data changed from Vec<u8> to bytes::Bytes. With high-FPS streams and multiple registered handlers, the previous shape allocated a fresh Vec<u8> for every handler on every frame; Bytes makes the decoded JPEG allocate exactly once per frame and lets each handler-clone be a refcount bump rather than a memcpy. Downstream sinks that pipe to axum, tonic, tokio_util::codec, or any Bytes-aware API now hand off without copying. Bytes implements Deref<Target = [u8]>, so most existing reads (frame.data.len(), &frame.data[..], tokio::fs::write(path, &frame.data)) compile unchanged; the only migration is for code that consumed the buffer by value (e.g. let v: Vec<u8> = frame.datalet v = frame.data.to_vec()). Closes #85 (sub-task of #55, v0.13.0).

Changed

  • Playwright driver upgraded to 1.60.0 (from 1.59.1) — picks up current Chromium 148 / Firefox 150 / WebKit 26.4 binaries and removes long-deprecated upstream APIs (Locator.ariaRef, the handle option on exposeBinding, the logger option on connect/connectOverCDP, and the videosPath/videoSize context options) — none of which were exposed in this crate, so the bump is source-compatible. The route.fulfill() body-transmission reverse-canary still passes against 1.60.0, so the documented limitation range is extended to 1.49.0 – 1.60.0. New 1.60 surface (HAR tracing API, Locator::drop, expanded BrowserContext lifecycle events, description on get_by_role, pseudo on to_have_css, etc.) is tracked separately under the v1.0 gap analysis for incremental rollout pre-1.0.
  • build.rs writes the Playwright driver into Cargo's $OUT_DIR instead of <repo>/drivers/. The previous strategy walked up from CARGO_MANIFEST_DIR looking for a workspace Cargo.toml, which misbehaved when playwright-rs was consumed as a git dependency: the walk wandered into $CARGO_HOME/git/checkouts/..., and the resolved drivers/ directory did not survive Cargo's CI cache restore (the embedded driver path in the cached .rlib pointed at a directory that no longer existed; runtime fell through to Error::ServerNotFound). $OUT_DIR is the idiomatic Rust location for build-script artifacts and is automatically cached by any target/-cache CI configuration. Dropped the dirs build-dependency. Runtime resolution is unchanged for library consumers — option_env!() picks up wherever build.rs writes — so this is a behaviour change for shell scripts / CI configs that hardcoded <repo>/drivers/, not a Rust API break.
  • CI workflows no longer cache <repo>/drivers/. Cache Playwright Drivers steps in .github/workflows/test.yml and .github/workflows/release.yml are removed; the existing target/ cache covers $OUT_DIR. The three OS-conditional hardcoded drivers/playwright-<version>-<platform>/node ... cli.js install shell invocations are replaced with a single cross-platform cargo run --release --bin playwright-rs --features cli -- install chromium firefox webkit step.
  • Integration tests use the public get_driver_executable() API. Three tests in crates/playwright/tests/integration/connection.rs previously hardcoded env!("CARGO_MANIFEST_DIR").join("drivers") and probed the filesystem; they now call crate::common::playwright_package_dir() which wraps the public driver-resolution API. Removes implicit dependence on the legacy <repo>/drivers/ layout.
  • build.rs: replaced reqwest with ureq for the one blocking driver download from Azure CDN. reqwest pulled in hyper, tower, h2, and ~220 lines of transitive build-time dependencies for a single GET; ureq is a thin synchronous client that covers the use case directly. Cuts our total cargo tree size from ~619 → ~507 lines (~18%). Build-only change, zero user-facing impact. Closes #63 (sub-task of #62).
  • Narrowed tokio features from "full" to the explicit subset we use (fs, io-util, macros, net, process, rt, rt-multi-thread, signal, sync, time). Drops the unused parking_lot, tracing, and io-std features. No public API change; this just documents the runtime surface we depend on. Closes #64 (sub-task of #62).
  • Replaced mime_guess with a small hand-rolled extension-to-MIME map. mime_guess ships a compile-time lookup table for hundreds of MIME types we'd never encounter for browser-automation file uploads. The new helper covers the ~40 extensions actually relevant (images, documents, archives, common text/data formats) and falls back to application/octet-stream. Internal-use only; SemVer-compatible. Closes #65 (sub-task of #62).

Added

  • playwright-rs binary (feature cli). clap-based CLI shipped behind the new cli feature. Initial subcommand: playwright-rs install [BROWSERS]... [--with-deps] [--driver-only]. The binary downloads the Playwright driver into a stable user-cache directory (~/Library/Caches/playwright-rust/<version>/ on macOS, ~/.cache/playwright-rust/<version>/ on Linux, %LOCALAPPDATA%\playwright-rust\<version>\ on Windows) and then invokes the browser installer. Discoverable via cargo install playwright-rs --features cli. Future-proofed for playwright-rs driver path / driver version subcommands.
  • get_driver_executable() runtime resolution adds a user-cache lookup. Between the compile-time bundled lookup and the existing env-var/npm fallbacks, the resolver now probes dirs::cache_dir()/playwright-rust/<version>/playwright-<version>-<platform>/. This is the location that playwright-rs install populates, so downstream binaries distributed via cargo install can rely on a stable runtime driver path after the user runs the installer once.
  • Page::aria_snapshot(options) — page-level shorthand for page.locator("body").aria_snapshot(options). Returns the ARIA accessibility tree for the entire page as a YAML string. Closes #70 (sub-task of #55, v0.13.0).
  • AriaSnapshotOptions on both Locator::aria_snapshot and Page::aria_snapshot — surfaces the Playwright 1.59 mode, track, depth, and timeout parameters. The headline knob is mode: AriaSnapshotMode::Ai for AI-friendly snapshots intended for LLM/codegen consumption (the default mode is the human-readable form). Re-exported as AriaSnapshotMode and AriaSnapshotOptions from the crate root. Breaking: the Locator::aria_snapshot() no-arg signature is gone; the new shape is aria_snapshot(options: Option<AriaSnapshotOptions>). Migration is one character per call site — pass None to keep the prior behaviour.
  • TracingStartOptions::live — new field; when Some(true), enables Playwright's live-trace mode so a viewer can attach to an in-progress recording. Forwarded as {"live": true} to the tracingStart RPC. Closes #71 (sub-task of #55, v0.13.0).
  • **`Locator:...
Read more

playwright-rs-trace 0.1.0

Choose a tag to compare

@github-actions github-actions released this 23 May 22:59

Added

  • TraceReader — open a Playwright trace zip, stream events, reassemble actions.

    • TraceReader::open(reader) parses the context-options event
      eagerly so callers can read reader.context() before iterating.
    • TraceReader::raw_events() — lossless iterator over every JSONL
      line in trace.trace, yielding RawEvent (the full JSON object).
      Forward-compat escape hatch for callers dispatching on event kinds
      the parser doesn't model yet.
    • TraceReader::events() — typed iterator yielding TraceEvent.
      Known kinds become typed variants; anything else surfaces as
      TraceEvent::Unknown(RawEvent) so nothing is silently dropped.
    • TraceReader::actions() — reassembles before + optional input
      • zero-or-more log + after events into a logical Action.
        Truncated actions are emitted at end-of-stream rather than
        discarded.
    • Free function playwright_rs_trace::open(path) for the
      file-on-disk case.
  • TraceReader::network()trace.network parsing → NetworkEntry iterator.

    • One entry per recorded HTTP request/response pair (HAR-like
      resource snapshot). Empty trace.network (typical for traces
      driven against data: URLs) yields zero items.
    • HAR -1 "unknown" sentinels are mapped to None at parse time —
      the public types use Option<u64> / Option<u16> / Option<f64>
      on time, headers_size, body_size, status, content.size,
      so callers don't have to know the convention. Empty redirectURL
      likewise → None.
    • HAR fields not modelled individually (cookies, timings,
      cache, queryString, _transferSize, …) are preserved on
      NetworkEntry::raw_snapshot: serde_json::Value.
    • Unknown event kinds in trace.network yield an error rather than
      being silently skipped — the stream is single-purpose.
  • xtask workspace member with regenerate-trace-fixture
    subcommand.
    Drives a real Chromium session through
    playwright-rs::Tracing — including a localhost axum server so
    the navigation produces a real resource-snapshot — to refresh
    the deterministic test fixture under tests/fixtures/. New
    .cargo/config.toml aliases cargo xtask.

playwright-rs-macros 0.1.0

Choose a tag to compare

@github-actions github-actions released this 23 May 18:26

Added

  • locator!() macro — compile-time-validated Playwright selector.
    Takes a string literal, validates it at compile time (rejects empty
    or whitespace-only input, unbalanced []/()/{}, and unknown
    engine prefixes — css=, xpath=, text=, role=, id=,
    data-testid=, nth=, and the internal:*= namespace are
    recognized), and expands to the validated &'static str so calls
    like page.locator(locator!("#submit")) carry zero runtime cost
    versus page.locator("#submit"). Brackets inside quoted attribute
    values ([aria-label='go [back]']) are correctly skipped during the
    balance check.

    Compile-fail tests under tests/ui/ pin both the diagnostic message
    and source-span highlighting via trybuild
    — see tests/ui/README.md for the workflow when extending coverage.

    Closes #81.

v0.12.3

Choose a tag to compare

@github-actions github-actions released this 30 Apr 10:29

Fixed

  • Ctrl-C no longer breaks the user's shell terminal (Unix) — running a Playwright program and hitting Ctrl-C used to leave the shell with arrow keys echoing as raw ^[[A instead of recalling history; recovering required stty sane or reset. Two layers fix it: (1) the Node driver is now spawned in its own process group via process_group(0), so SIGINT only signals our Rust process and Node runs gracefullyProcessExitDoNotHang instead of crashing on EPIPE while chromium events are in flight; (2) the driver's stderr is piped and drained into tracing::debug! on target playwright_rs::driver_stderr instead of being inherited from our tty, so any terminal-capability queries Node writes during shutdown don't pollute the user's terminal. Closes #59. A defensive tty-snapshot/restore SIGINT handler is also installed as belt-and-suspenders; opt-out via PLAYWRIGHT_NO_SIGNAL_HANDLER=1.

Added

  • trace_on_failure example + README "Testing & Debugging" section — idiomatic Rust pattern for ensuring tracing.stop() / browser.close() run on test failure (since ? and unwrap() skip subsequent cleanup) and for getting line-pinpointed failures despite ? hiding source location. Closest to the Java/.NET pattern (explicit try-finally) since Rust has no first-party Playwright test runner and no async Drop. Closes #61.

Changed

  • Release workflow: stripped dead CLI-binary scaffolding — we're a library-only crate, so the build/strip/archive/upload-asset/SLSA-attestation steps were no-ops guarded by if [ -f playwright ]. Removing them eliminates the cosmetic "Could not find subject" red annotations that appeared on every release. Closes #56.

v0.12.2

Choose a tag to compare

@github-actions github-actions released this 28 Apr 00:11

Added

  • Locator assertionsto_have_attribute(name, value), to_have_class(expected), to_have_css(name, value), to_have_count(count), plus _regex variants for the first three. Closes #58.

v0.12.1

Choose a tag to compare

@github-actions github-actions released this 25 Apr 12:26

Security

  • RUSTSEC-2026-0104 — bump rustls-webpki from 0.103.12 to 0.103.13. Reachable panic in CRL parsing via BorrowedCertRevocationList::from_der when handling a syntactically valid empty BIT STRING in the onlySomeReasons element of an IssuingDistributionPoint extension. Reachable prior to signature verification. Applications that don't use CRLs are not affected. Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0104

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 19 Apr 19:29

Added

  • context.set_storage_state(state) — replaces cookies and localStorage on an existing context without recreation (implemented client-side: clear cookies, add new cookies, restore per-origin localStorage via JS evaluation)

  • context.is_closed() — returns true after close() or a server-initiated "close" event

  • context.clock() / page.clock() — Clock API for fake timer control in deterministic tests

    • Clock::install(options) — install fake timers, optionally setting an initial epoch timestamp (clockInstall RPC on BrowserContext channel)
    • Clock::fast_forward(ticks) — advance the clock by milliseconds, firing due timers (clockFastForward RPC with ticksNumber)
    • Clock::pause_at(time) — jump to an epoch timestamp and pause; no timers fire until resumed (clockPauseAt RPC with timeNumber)
    • Clock::resume() — resume the clock after pause_at (clockResume RPC)
    • Clock::set_fixed_time(time) — freeze Date.now() at a fixed epoch without affecting timer scheduling (clockSetFixedTime RPC with timeNumber)
    • Clock::set_system_time(time) — update system time without freezing the clock (clockSetSystemTime RPC with timeNumber)
    • ClockInstallOptionstime: Option<u64> for setting the install epoch
    • page.clock() delegates to the parent BrowserContext::clock() — all RPCs go on the context channel
    • Clock and ClockInstallOptions exported from crate root
    • See: https://playwright.dev/docs/api/class-clock
  • page.route_from_har(har_path, options) / context.route_from_har(har_path, options) — replays network requests from a HAR archive; uses client-side HarRouter pattern (calls local_utils.har_open() then local_utils.har_lookup() per request); accepts RouteFromHarOptions with url (glob filter), not_found ("abort" or "fallback"), update, update_content, and update_mode fields; maps to harOpen/harLookup RPCs on the LocalUtils channel

  • Touchscreen classpage.touchscreen() returns a Touchscreen handle; touchscreen.tap(x, y) simulates a single touch event at viewport coordinates (touchscreenTap RPC on Page channel); requires has_touch: true in BrowserContextOptions

  • page.drag_and_drop(source, target, options) — performs drag and drop between two CSS selectors on the main frame; delegates to Frame::locator_drag_to (dragAndDrop RPC); accepts the same DragToOptions as Locator::drag_to

  • page.console_messages() — returns all console messages accumulated since page creation (Vec<ConsoleMessage>); console subscription enabled by default on every BrowserContext so no handler registration required

  • page.page_errors() — returns all uncaught JS error messages accumulated since page creation (Vec<String>); populated automatically via pageError events

  • page.opener() — returns the page that opened this popup (Option<Page>), or None for non-popup pages; reads the opener GUID from the page initializer

  • Video classpage.video() returns Some(Video) when the context was created with record_video; Video::path() returns the recording path, Video::save_as(path) copies the file, Video::delete() removes it; all methods wait internally for the artifact (fired via "video" event on page close), so no manual sleep is required

  • page.request_gc() — forces garbage collection (Chromium only)

  • page.workers() — returns all active web workers in the page (Vec<Worker>); accumulated from worker events as workers are created

  • context.service_workers() — returns all active service workers in the browser context (Vec<Worker>); accumulated from serviceWorker events

  • expect_event() — generic event waiting on Page and BrowserContext, returning typed EventValue enum

  • playwright.request() — headless API testing without a browser (get, post, put, delete, patch, head, fetch, APIResponse)

  • to_match_aria_snapshot(expected) — ARIA accessibility tree assertion with auto-retry

  • Locator::aria_snapshot() — returns the ARIA accessibility tree as a YAML string (ariaSnapshot RPC on Frame)

  • Locator::describe(description) — returns a new Locator with a human-readable label appended to the selector (internal:describe=...) for cleaner trace/error output; client-side only

  • Locator::highlight() — highlights the matched element in the browser for visual debugging (highlight RPC on Frame)

  • Locator::content_frame() — returns a FrameLocator for the content of an <iframe> element; client-side only

  • ElementHandle::content_frame() — returns the Frame for an <iframe> element, or None if not an iframe (contentFrame RPC on ElementHandle channel)

  • ElementHandle::owner_frame() — returns the Frame that owns this element (ownerFrame RPC on ElementHandle channel)

  • ElementHandle::wait_for_element_state(state, timeout) — waits until the element reaches the given state ("visible", "hidden", "stable", "enabled", "disabled", "editable") (waitForElementState RPC on ElementHandle channel)

  • Accessibility classpage.accessibility() returns an Accessibility handle; accessibility.snapshot(options) returns the page's ARIA accessibility tree as a YAML string wrapped in serde_json::Value; implemented via FrameAriaSnapshot RPC (the modern Playwright equivalent — the legacy accessibilitySnapshot RPC was removed in current Playwright versions)

  • Coverage classpage.coverage() returns a Coverage handle (Chromium only); start_js_coverage(options) / stop_js_coverage() collect V8 JS coverage (JSCoverageEntry with url, script_id, source, functions: Vec<JSFunctionCoverage>); start_css_coverage(options) / stop_css_coverage() collect CSS coverage (CSSCoverageEntry with url, text, ranges: Vec<CoverageRange>); maps to startJSCoverage / stopJSCoverage / startCSSCoverage / stopCSSCoverage RPCs on the Page channel

  • page.add_locator_handler() / page.remove_locator_handler() — registers an async handler that Playwright calls whenever a matching element appears and blocks an actionability check (e.g. cookie banners, permission dialogs); accepts AddLocatorHandlerOptions with no_wait_after and times; maps to registerLocatorHandler / resolveLocatorHandler / unregisterLocatorHandler RPCs; handler receives the matching Locator as argument

  • page.route_web_socket(url, handler) / context.route_web_socket(url, handler) — intercepts WebSocket connections matching a URL glob pattern; handler receives a WebSocketRoute object with connect_to_server(), close(options), send(message), on_message(handler), and on_close(handler); maps to setWebSocketInterceptionPatterns RPC with webSocketRoute events; WebSocketRoute and WebSocketRouteCloseOptions exported from crate root

  • ConsoleMessage::timestamp() — epoch milliseconds (f64) when the message was emitted

  • Response::http_version() — HTTP version string (e.g. "HTTP/1.1", "HTTP/2.0") via the httpVersion RPC added in Playwright 1.59

  • Request::existing_response() — synchronous Option<Response> for the already-received response, complementing the async response() getter

  • browser.bind(title, options) / browser.unbind() — expose a playwright-rs-launched browser over WebSocket so external clients (@playwright/mcp, Playwright CLI, agent tooling) can attach via BrowserType::connect(); BindOptions has host/port/workspace_dir/metadata; maps to startServer / stopServer RPCs (Playwright 1.59+)

  • Playwright driver upgraded to 1.59.1 (from 1.58.2) — required for Response::http_version() and picks up current Chromium/Firefox/WebKit binaries

Breaking Changes

  • BrowserContextOptions::accept_downloads type changed (closes #49) — field type is now Option<AcceptDownloads> instead of Option<bool>, matching the protocol's three-state "accept"/"deny"/"internal" string. The builder method accepts impl Into<AcceptDownloads>, so bool callers still work (trueAccept, falseDeny). Direct struct-literal construction or field pattern-matching must migrate.
  • macOS 14 WebKit no longer supported — Playwright 1.59 dropped macOS 14 ("Sonoma") support for WebKit. Users on macOS 14 must upgrade to macOS 15+ or pin to playwright-rs = "0.11" (which ships driver 1.58.2). Chromium and Firefox are unaffected on macOS 14.

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 16 Apr 10:11

Added

  • New classes: JSHandle, Worker, WebError, WebSocket (completed), ConsoleMessage, FileChooser, Selectors
  • playwright.devices() — device descriptor map for browser emulation (DeviceDescriptor, DeviceViewport)
  • ConsoleMessage::args() — returns &[Arc<JSHandle>] for console method arguments
  • Browser methodscontexts(), browser_type(), on_disconnected(), start_tracing()/stop_tracing(), new_browser_cdp_session()
  • Page event handlerson_close, on_load, on_crash, on_pageerror, on_popup, on_frameattached, on_framedetached, on_framenavigated, on_worker, on_console, on_filechooser
  • Page expect methodsexpect_popup, expect_download, expect_response, expect_request, expect_console_message, expect_file_chooser
  • BrowserContext eventson_console, on_weberror, on_serviceworker, on_dialog, expect_console_message

Breaking Changes

  • ConnectionLike trait gains selectors() method — internal server infrastructure, not user-facing API. Any code implementing ConnectionLike directly must add the new method.

Fixed

  • unwrap() audit (closes #48) — replaced bare unwrap() calls in library code with expect() (for infallible operations) or proper error handling (for protocol data). Remaining unwrap() calls are only mutex locks (lock().unwrap()) and test code.
  • 15 broken rustdoc links — all intra-doc links now resolve correctly (qualified paths for cross-module references)