Releases: padamson/playwright-rust
Release list
playwright-rs 0.14.1
Security
- Bumped
crossbeam-epoch0.9.18 → 0.9.20 (RUSTSEC-2026-0204) andanyhow1.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 ofplaywright-rswas exposed.
Fixed
- Driver acquisition survives the shutdown of Microsoft's
playwright.azureedge.netCDN. The prebuiltplaywright-<version>-<platform>.zipdriver archives were discontinued with that CDN (they now 404), which broke every fresh build — cold caches, new machines, and CI failed withenvironment variable PLAYWRIGHT_DRIVER_VERSION not defined(issue #116). The build script (and theclifeature'splaywright-rs install) now assemble the driver from two artifacts instead: theplaywright-corenpm 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 toPLAYWRIGHT_DRIVER_PATHor an npm-installed Playwright, failing at launch withServerNotFound) 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
Added
-
Tracing + HAR types are now re-exported at the crate root —
Tracing,TracingStartOptions,TracingStopOptions,StartHarOptions,HarMode, andHarContentjoin every other consumer-facing type atplaywright_rs::*(previously reachable only viaplaywright_rs::protocol::*, which still works). Surfaced by dogfooding: a consumer following the obviousplaywright_rs::Viewportpattern hit a compile error onplaywright_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/::afterpseudo-element; adescriptionoption onget_by_role; aboxesoption onaria_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); ano_defaultsoption onconnect_over_cdp(attach to a running browser without Playwright's default overrides); andPage::hide_highlight(). Internally,ConsoleMessagelocation now reads the 1.60line/columnkeys, falling back to the deprecatedlineNumber/columnNumber. With this, the crate covers the full Playwright 1.60 API surface. -
BrowserContextlifecycle events +Browser::on_context— the Playwright 1.60 context-level event surface.Browser::on_contextfires when a new context is created on the browser.BrowserContext::on_download,on_frame_attached,on_frame_detached,on_frame_navigated,on_page_load, andon_page_closeobserve 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_snapshot—expect_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.StartHarOptionscontrolscontent(omit/embed/attach),mode(full/minimal), aurl_filterglob, andresources_dir. A.zippath bundles bodies as attachments; any other path extracts the.harJSON (via the newLocalUtils::har_unzip). The result opens in browser devtools or replays in tests throughroute_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 fromdrag_to(intra-page element drag). Pass files asFilePayloads anddataas(mime_type, value)pairs viaDropOptions, with optionalpositionandtimeout. New API surface in Playwright 1.60. -
Screenshot options:
animations,caret,scale,style,mask,mask_coloronPage::screenshotandLocator::screenshot(viaScreenshotOptions). 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).Animationsis now always available (previously only with thescreenshot-difffeature) and shared betweenScreenshotOptionsand theto_have_screenshotassertions; newCaretandScaleenums are re-exported from the crate root.mask(Vec<Locator>)overpaints the given locators with a solid box (color set bymask_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
tracingspans on the internal JSON-RPC layer — Phase 2 of the observability work.Connection::send_messageand inbound messagedispatch, plus the pipe and websocket transport send paths, now carry#[tracing::instrument(level = "trace")]spans with structural fields only (method,guid, requestid, framebytes_len);skip_allkeeps arbitrary-JSON RPC params out of the spans. Opt in withplaywright_rs=tracefor per-request protocol timing and event sequencing. Closes #98 (Phase 2 sub-task of #83).
Changed
- Breaking:
FilePayload::builder()replaced byFilePayload::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_fileare 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), ...), orDefault+ field mutation. Matching on public enums (includingError) 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 takesOption<HighlightOptions>(previously no arguments), to carry the new 1.60styleoption and to match Playwright'shighlight(options)plus this crate's option-method convention. Existing calls migrate.highlight()→.highlight(None). build.rsdriver download is now relocatable and skippable via env.PLAYWRIGHT_DRIVER_CACHE_DIRdownloads the driver to a stable, version-keyed path instead of$OUT_DIRso CI can cache it on its own key — necessary becauseSwatinem/rust-cacheprunes workspace build-script output, so a driver left in$OUT_DIRis not cached by it and re-downloads (~42 MB) every run (correcting the v0.13.0 note that claimed$OUT_DIRwas automatically cached).PLAYWRIGHT_SKIP_DRIVER_DOWNLOADskips 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
```ignoreand "executed" them in CI with--ignored— but rustdoc never compilesignoreblocks 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 everycargo 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_objectblocks on aNotifyinstead 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. Frameno longer keeps itsPagealive after disposal. The frame's back-reference is cleared when the frame is disposed, breaking thePage↔Framereference cycle that previously kept both objects in memory after a page closed (frame.page()returnsNoneonce 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 atPageconstruction (matching playwright-python), making locator creation genuinely infallible; actions on a closed page still fail with a normalError.Page::url()now always reads through the main frame too, instead of a fallback cache. The remaining flagged panics on public paths (FilePayloadbuilder, root-object init, a CDP params invariant) were converted to errors or made unreachable.
playwright-rs 0.13.0
Security
- Bumped transitive
opensslfrom 0.10.79 to 0.10.80 to pick up the fix for GHSA-phqj-4mhp-q6mq — potential out-of-bounds write inCipherCtxRef::cipher_update_inplacefor AES-KW-PAD ciphers. We don't use AES-KW-PAD anywhere; the path enters the tree transitively viatokio-tungstenite→native-tls→openssl. Affected the workspaceCargo.lockand the fuzz target's lockfile; both now resolve to 0.10.80+. Detected by Dependabot (alerts #17 / #18). - Bumped transitive
opensslfrom 0.10.78 to 0.10.79 to pick up the fix for GHSA-xp3w-r5p5-63rr / CVE-2026-42327 — undefined behaviour inX509Ref::ocsp_respondersfor certificates with non-UTF-8 OCSP URLs. Affected the workspaceCargo.lockand the fuzz target's lockfile; both now resolve to 0.10.79+. We pullopenssltransitively vianative-tls(the default TLS feature); no public-API impact. Detected by Dependabot (alerts #15 / #16);cargo audithad not yet picked up the advisory at fix time. - Refreshed
supply-chain/imports.lockexemptions for the bumpedopensslandopenssl-sysversions viacargo vet regenerate exemptions.cargo vet,cargo audit,cargo deny checkall green post-bump. - Adopted transitively-trusted publishers (
cargo vet trust --all) for BurntSushi, Lokathor, epage, seanmonstar, and kennykerr (the latter three with--allow-multiple-publishersfor flagship multi-maintainer crates likeclap,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 checkall green.
Breaking changes
Locator::aria_snapshot()now takesOption<AriaSnapshotOptions>. The Playwright 1.59ariaSnapshotRPC acceptsmode(Ai or Default),track,depth, andtimeout; we now surface those through a struct passed toaria_snapshot(...). To migrate, changelocator.aria_snapshot()→locator.aria_snapshot(None). The newly-addedPage::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::datachanged fromVec<u8>tobytes::Bytes. With high-FPS streams and multiple registered handlers, the previous shape allocated a freshVec<u8>for every handler on every frame;Bytesmakes 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 toaxum,tonic,tokio_util::codec, or anyBytes-aware API now hand off without copying.BytesimplementsDeref<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.data→let 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, thehandleoption onexposeBinding, theloggeroption onconnect/connectOverCDP, and thevideosPath/videoSizecontext options) — none of which were exposed in this crate, so the bump is source-compatible. Theroute.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,descriptiononget_by_role,pseudoonto_have_css, etc.) is tracked separately under the v1.0 gap analysis for incremental rollout pre-1.0. build.rswrites the Playwright driver into Cargo's$OUT_DIRinstead of<repo>/drivers/. The previous strategy walked up fromCARGO_MANIFEST_DIRlooking for a workspaceCargo.toml, which misbehaved when playwright-rs was consumed as a git dependency: the walk wandered into$CARGO_HOME/git/checkouts/..., and the resolveddrivers/directory did not survive Cargo's CI cache restore (the embedded driver path in the cached.rlibpointed at a directory that no longer existed; runtime fell through toError::ServerNotFound).$OUT_DIRis the idiomatic Rust location for build-script artifacts and is automatically cached by anytarget/-cache CI configuration. Dropped thedirsbuild-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 Driverssteps in.github/workflows/test.ymland.github/workflows/release.ymlare removed; the existingtarget/cache covers$OUT_DIR. The three OS-conditional hardcodeddrivers/playwright-<version>-<platform>/node ... cli.js installshell invocations are replaced with a single cross-platformcargo run --release --bin playwright-rs --features cli -- install chromium firefox webkitstep. - Integration tests use the public
get_driver_executable()API. Three tests incrates/playwright/tests/integration/connection.rspreviously hardcodedenv!("CARGO_MANIFEST_DIR").join("drivers")and probed the filesystem; they now callcrate::common::playwright_package_dir()which wraps the public driver-resolution API. Removes implicit dependence on the legacy<repo>/drivers/layout. build.rs: replacedreqwestwithureqfor the one blocking driver download from Azure CDN.reqwestpulled in hyper, tower, h2, and ~220 lines of transitive build-time dependencies for a single GET;ureqis a thin synchronous client that covers the use case directly. Cuts our totalcargo treesize from ~619 → ~507 lines (~18%). Build-only change, zero user-facing impact. Closes #63 (sub-task of #62).- Narrowed
tokiofeatures from"full"to the explicit subset we use (fs,io-util,macros,net,process,rt,rt-multi-thread,signal,sync,time). Drops the unusedparking_lot,tracing, andio-stdfeatures. No public API change; this just documents the runtime surface we depend on. Closes #64 (sub-task of #62). - Replaced
mime_guesswith a small hand-rolled extension-to-MIME map.mime_guessships 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 toapplication/octet-stream. Internal-use only; SemVer-compatible. Closes #65 (sub-task of #62).
Added
playwright-rsbinary (featurecli). clap-based CLI shipped behind the newclifeature. 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 viacargo install playwright-rs --features cli. Future-proofed forplaywright-rs driver path/driver versionsubcommands.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 probesdirs::cache_dir()/playwright-rust/<version>/playwright-<version>-<platform>/. This is the location thatplaywright-rs installpopulates, so downstream binaries distributed viacargo installcan rely on a stable runtime driver path after the user runs the installer once.Page::aria_snapshot(options)— page-level shorthand forpage.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).AriaSnapshotOptionson bothLocator::aria_snapshotandPage::aria_snapshot— surfaces the Playwright 1.59mode,track,depth, andtimeoutparameters. The headline knob ismode: AriaSnapshotMode::Aifor AI-friendly snapshots intended for LLM/codegen consumption (the default mode is the human-readable form). Re-exported asAriaSnapshotModeandAriaSnapshotOptionsfrom the crate root. Breaking: theLocator::aria_snapshot()no-arg signature is gone; the new shape isaria_snapshot(options: Option<AriaSnapshotOptions>). Migration is one character per call site — passNoneto keep the prior behaviour.TracingStartOptions::live— new field; whenSome(true), enables Playwright's live-trace mode so a viewer can attach to an in-progress recording. Forwarded as{"live": true}to thetracingStartRPC. Closes #71 (sub-task of #55, v0.13.0).- **`Locator:...
playwright-rs-trace 0.1.0
Added
-
TraceReader— open a Playwright trace zip, stream events, reassemble actions.TraceReader::open(reader)parses thecontext-optionsevent
eagerly so callers can readreader.context()before iterating.TraceReader::raw_events()— lossless iterator over every JSONL
line intrace.trace, yieldingRawEvent(the full JSON object).
Forward-compat escape hatch for callers dispatching on event kinds
the parser doesn't model yet.TraceReader::events()— typed iterator yieldingTraceEvent.
Known kinds become typed variants; anything else surfaces as
TraceEvent::Unknown(RawEvent)so nothing is silently dropped.TraceReader::actions()— reassemblesbefore+ optionalinput- zero-or-more
log+afterevents into a logicalAction.
Truncated actions are emitted at end-of-stream rather than
discarded.
- zero-or-more
- Free function
playwright_rs_trace::open(path)for the
file-on-disk case.
-
TraceReader::network()—trace.networkparsing →NetworkEntryiterator.- One entry per recorded HTTP request/response pair (HAR-like
resource snapshot). Emptytrace.network(typical for traces
driven againstdata:URLs) yields zero items. - HAR
-1"unknown" sentinels are mapped toNoneat parse time —
the public types useOption<u64>/Option<u16>/Option<f64>
ontime,headers_size,body_size,status,content.size,
so callers don't have to know the convention. EmptyredirectURL
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.networkyield an error rather than
being silently skipped — the stream is single-purpose.
- One entry per recorded HTTP request/response pair (HAR-like
-
xtaskworkspace member withregenerate-trace-fixture
subcommand. Drives a real Chromium session through
playwright-rs::Tracing— including a localhostaxumserver so
the navigation produces a realresource-snapshot— to refresh
the deterministic test fixture undertests/fixtures/. New
.cargo/config.tomlaliasescargo xtask.
playwright-rs-macros 0.1.0
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 theinternal:*=namespace are
recognized), and expands to the validated&'static strso calls
likepage.locator(locator!("#submit"))carry zero runtime cost
versuspage.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 viatrybuild
— seetests/ui/README.mdfor the workflow when extending coverage.Closes #81.
v0.12.3
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
^[[Ainstead of recalling history; recovering requiredstty saneorreset. Two layers fix it: (1) the Node driver is now spawned in its own process group viaprocess_group(0), so SIGINT only signals our Rust process and Node runsgracefullyProcessExitDoNotHanginstead of crashing on EPIPE while chromium events are in flight; (2) the driver's stderr is piped and drained intotracing::debug!on targetplaywright_rs::driver_stderrinstead 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 viaPLAYWRIGHT_NO_SIGNAL_HANDLER=1.
Added
trace_on_failureexample + README "Testing & Debugging" section — idiomatic Rust pattern for ensuringtracing.stop()/browser.close()run on test failure (since?andunwrap()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 asyncDrop. 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
Added
- Locator assertions —
to_have_attribute(name, value),to_have_class(expected),to_have_css(name, value),to_have_count(count), plus_regexvariants for the first three. Closes #58.
v0.12.1
Security
RUSTSEC-2026-0104— bumprustls-webpkifrom0.103.12to0.103.13. Reachable panic in CRL parsing viaBorrowedCertRevocationList::from_derwhen handling a syntactically valid emptyBIT STRINGin theonlySomeReasonselement of anIssuingDistributionPointextension. 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
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()— returnstrueafterclose()or a server-initiated "close" event -
context.clock()/page.clock()— Clock API for fake timer control in deterministic testsClock::install(options)— install fake timers, optionally setting an initial epoch timestamp (clockInstallRPC on BrowserContext channel)Clock::fast_forward(ticks)— advance the clock by milliseconds, firing due timers (clockFastForwardRPC withticksNumber)Clock::pause_at(time)— jump to an epoch timestamp and pause; no timers fire until resumed (clockPauseAtRPC withtimeNumber)Clock::resume()— resume the clock afterpause_at(clockResumeRPC)Clock::set_fixed_time(time)— freezeDate.now()at a fixed epoch without affecting timer scheduling (clockSetFixedTimeRPC withtimeNumber)Clock::set_system_time(time)— update system time without freezing the clock (clockSetSystemTimeRPC withtimeNumber)ClockInstallOptions—time: Option<u64>for setting the install epochpage.clock()delegates to the parentBrowserContext::clock()— all RPCs go on the context channelClockandClockInstallOptionsexported 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-sideHarRouterpattern (callslocal_utils.har_open()thenlocal_utils.har_lookup()per request); acceptsRouteFromHarOptionswithurl(glob filter),not_found("abort"or"fallback"),update,update_content, andupdate_modefields; maps toharOpen/harLookupRPCs on theLocalUtilschannel -
Touchscreenclass —page.touchscreen()returns aTouchscreenhandle;touchscreen.tap(x, y)simulates a single touch event at viewport coordinates (touchscreenTapRPC on Page channel); requireshas_touch: trueinBrowserContextOptions -
page.drag_and_drop(source, target, options)— performs drag and drop between two CSS selectors on the main frame; delegates toFrame::locator_drag_to(dragAndDropRPC); accepts the sameDragToOptionsasLocator::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 viapageErrorevents -
page.opener()— returns the page that opened this popup (Option<Page>), orNonefor non-popup pages; reads the opener GUID from the page initializer -
Videoclass —page.video()returnsSome(Video)when the context was created withrecord_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 fromworkerevents as workers are created -
context.service_workers()— returns all active service workers in the browser context (Vec<Worker>); accumulated fromserviceWorkerevents -
expect_event()— generic event waiting on Page and BrowserContext, returning typedEventValueenum -
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 (ariaSnapshotRPC 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 (highlightRPC on Frame) -
Locator::content_frame()— returns aFrameLocatorfor the content of an<iframe>element; client-side only -
ElementHandle::content_frame()— returns theFramefor an<iframe>element, orNoneif not an iframe (contentFrameRPC on ElementHandle channel) -
ElementHandle::owner_frame()— returns theFramethat owns this element (ownerFrameRPC on ElementHandle channel) -
ElementHandle::wait_for_element_state(state, timeout)— waits until the element reaches the given state ("visible","hidden","stable","enabled","disabled","editable") (waitForElementStateRPC on ElementHandle channel) -
Accessibilityclass —page.accessibility()returns anAccessibilityhandle;accessibility.snapshot(options)returns the page's ARIA accessibility tree as a YAML string wrapped inserde_json::Value; implemented viaFrameAriaSnapshotRPC (the modern Playwright equivalent — the legacyaccessibilitySnapshotRPC was removed in current Playwright versions) -
Coverageclass —page.coverage()returns aCoveragehandle (Chromium only);start_js_coverage(options)/stop_js_coverage()collect V8 JS coverage (JSCoverageEntrywithurl,script_id,source,functions: Vec<JSFunctionCoverage>);start_css_coverage(options)/stop_css_coverage()collect CSS coverage (CSSCoverageEntrywithurl,text,ranges: Vec<CoverageRange>); maps tostartJSCoverage/stopJSCoverage/startCSSCoverage/stopCSSCoverageRPCs 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); acceptsAddLocatorHandlerOptionswithno_wait_afterandtimes; maps toregisterLocatorHandler/resolveLocatorHandler/unregisterLocatorHandlerRPCs; handler receives the matchingLocatoras argument -
page.route_web_socket(url, handler)/context.route_web_socket(url, handler)— intercepts WebSocket connections matching a URL glob pattern; handler receives aWebSocketRouteobject withconnect_to_server(),close(options),send(message),on_message(handler), andon_close(handler); maps tosetWebSocketInterceptionPatternsRPC withwebSocketRouteevents;WebSocketRouteandWebSocketRouteCloseOptionsexported 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 thehttpVersionRPC added in Playwright 1.59 -
Request::existing_response()— synchronousOption<Response>for the already-received response, complementing the asyncresponse()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 viaBrowserType::connect();BindOptionshashost/port/workspace_dir/metadata; maps tostartServer/stopServerRPCs (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_downloadstype changed (closes #49) — field type is nowOption<AcceptDownloads>instead ofOption<bool>, matching the protocol's three-state"accept"/"deny"/"internal"string. The builder method acceptsimpl Into<AcceptDownloads>, soboolcallers still work (true→Accept,false→Deny). 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
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 methods —
contexts(),browser_type(),on_disconnected(),start_tracing()/stop_tracing(),new_browser_cdp_session() - Page event handlers —
on_close,on_load,on_crash,on_pageerror,on_popup,on_frameattached,on_framedetached,on_framenavigated,on_worker,on_console,on_filechooser - Page expect methods —
expect_popup,expect_download,expect_response,expect_request,expect_console_message,expect_file_chooser - BrowserContext events —
on_console,on_weberror,on_serviceworker,on_dialog,expect_console_message
Breaking Changes
ConnectionLiketrait gainsselectors()method — internal server infrastructure, not user-facing API. Any code implementingConnectionLikedirectly must add the new method.
Fixed
- unwrap() audit (closes #48) — replaced bare
unwrap()calls in library code withexpect()(for infallible operations) or proper error handling (for protocol data). Remainingunwrap()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)