Releases: padamson/playwright-rust
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)
v0.10.0
Added
-
BrowserContext::new_cdp_session(page)— creates a Chrome DevTools Protocol session (Chromium only)CDPSession::send(method, params)— send any CDP command and receive the result as JSONCDPSession::detach()— detach from the CDP sessionCDPSessionregistered in the object factory for server-created sessions- See: https://playwright.dev/docs/api/class-cdpsession
-
BrowserContext::tracing()— access the per-context Tracing objectTracing::start(options)— begin trace recording (tracingStart+tracingStartChunk)Tracing::stop(options)— stop trace recording (tracingStopChunk+tracingStop)TracingStartOptions—name,screenshots,snapshotsfieldsTracingStopOptions—pathfield to export trace as a.ziparchive- Artifact export wired through
Artifact::save_asfor path-based stop - See: https://playwright.dev/docs/api/class-tracing
-
install_browsers()/install_browsers_with_deps()— programmatic browser installation (closes #46)install_browsers(None)— install all browsersinstall_browsers(Some(&["chromium", "firefox"]))— install specific browsersinstall_browsers_with_deps(browsers)— also installs system dependencies (useful for CI)- Reuses the bundled Playwright driver — no
npxrequired
-
Frame public API completion — Frame now at 100% coverage
frame.locator(selector)— create Locator scoped to a frame (was internal-only)- All 7
get_by_*methods (get_by_text,get_by_label,get_by_role, etc.) evaluate_handle(expression)— returns ElementHandle from JS evaluationchild_frames()— returns child frames by scanning the connection registry- Properties:
name(),page(),parent_frame(),is_detached() frame.page()back-reference set lazily when Page accesses its main frame
-
FrameLocatorclass — locate elements inside iframes using Playwright'sinternal:control=enter-frameselector enginepage.frame_locator(selector)/locator.frame_locator(selector)— entry pointsframe_locator.locator(selector)— create Locator inside iframeframe_locator.frame_locator(selector)— nested iframes- All 7
get_by_*methods (get_by_text,get_by_label,get_by_role, etc.) first(),last(),nth(index)— composition for multiple matching iframesowner()— Locator for the iframe element itself
-
ConnectionExtextension trait — typed object retrieval viaconnection.get_typed::<T>(guid).await?, eliminating boilerplateget_object+as_any().downcast_ref::<T>()pattern -
downcast_parent<T>()helper — one-line parent type resolution replacing manual parent + downcast chains -
Error::TypeMismatch— structured error variant with guid, expected type, and actual type for better diagnostics
Breaking Changes
- MSRV bumped from 1.85 to 1.88 — transitive dependencies (
icu_*,image,time,zip) now require Rust 1.88 ConnectionLiketrait uses#[async_trait]— methods migrated from manualPin<Box<dyn Future>>returns to idiomaticasync fn. Any code implementingConnectionLikedirectly must update method signatures (internal server infrastructure, not user-facing API).
Fixed
- 15 broken rustdoc links — all intra-doc links now resolve correctly (qualified paths for cross-module references)
Changed
- Security & quality CI —
cargo auditandcargo denyrun on every push to main and weekly; mutation testing moved fromtest.ymlto dedicatedsecurity.ymlwith weekly schedule + release tag triggers; MSRV check (Rust 1.85) intest.yml deny.toml— license compliance (Apache-2.0 compatible), crate bans, source restrictions, duplicate detectioncargo vet— supply chain review with trusted imports from 7 organizations; new dependencies require audit- SLSA provenance — release artifacts include signed build attestations via
actions/attest-build-provenance - Fuzz targets —
cargo-fuzztargets forparse_value,serialize_argument,parse_result(protocol parsing layer) - BrowserContext event handlers — context-level event subscriptions (fire before page handlers)
on_page(handler)— fires when new page created in contexton_close(handler)— fires when context is closedon_request(handler)/on_request_finished(handler)/on_request_failed(handler)— network events from any pageon_response(handler)— response events from any page
expect_page()/expect_close()— promise-based event waiting with timeoutexpect_page(timeout)— returnsEventWaiter<Page>that resolves when a new page is createdexpect_close(timeout)— returnsEventWaiter<()>that resolves when the context closesEventWaiter<T>— generic one-shot waiter backed bytokio::sync::oneshotwith configurable timeout (default 30s)
on_dialog(handler)— context-level dialog handler, fires before page handlersexpose_function()/expose_binding()— JS→Rust callback bridge on both BrowserContext and Pageexpose_function(name, callback)— inject a Rust function callable from JS aswindow[name](...)expose_binding(name, callback)— same with source info (note:needsHandle: truenot yet supported)- BindingCall protocol object for handling JS→Rust invocations
- Added
async-traitas a dependency
v0.9.0
Added
- Back-reference properties — navigate the protocol object hierarchy from child to parent
dialog.page()— returns thePagethat owns the dialog (via protocol parent)download.page()— returns thePagethat triggered the download (stored at construction)response.request()— returns theRequestthat triggered the response (via ResponseObject parent)response.frame()— returns theFramethat initiated the request (delegates torequest.frame())request.frame()— returns theFramethat initiated the request (eagerly resolved from initializer GUID)
- Response server info — inspect connection and TLS details
response.security_details()— TLS/SSL certificate info (SecurityDetails: issuer, protocol, subject_name, valid_from, valid_to); returnsNonefor HTTPresponse.server_addr()— server IP address and port (RemoteAddr); returnsNonefor cached responsesresponse.finished()— wait for response to finish loading (currently returns immediately for goto/reload responses)
- Request completion methods — full request lifecycle access
request.redirected_from()/request.redirected_to()— navigate the redirect chain (eagerly resolved from initializer)request.response()— get the matchingResponsevia RPCrequest.sizes()— resource size info (RequestSizes: request_body_size, request_headers_size, response_body_size, response_headers_size)
- New types:
SecurityDetails,RemoteAddr,RequestSizes(exported fromplaywright_rs::protocol) - Page assertions —
expect_page(&page)now supports title and URL assertionsto_have_title(expected)/to_have_title_regex(pattern)— assert page title with auto-retryto_have_url(expected)/to_have_url_regex(pattern)— assert page URL with auto-retry.not()negation and.with_timeout()supported (matching locator assertion pattern)
Breaking Changes
- Response struct fields are now private —
response.url,response.status,response.status_text,response.ok,response.headersare no longer accessible as public fields. Use the existing accessor methods instead:response.url(),response.status(),response.status_text(),response.ok(),response.headers(). These methods were already available; only direct field access is removed. Download::from_artifactis nowpub(crate)— this was an internal constructor not intended for public use.
Fixed
- Request parent type corrected — Request's parent in the Playwright protocol is Page (not Frame as previously assumed). The
request.frame()method now correctly resolves the frame from the initializer'sframeGUID via the connection registry.
v0.8.7
Added
- Locator advanced methods —
tap(),evaluate(),evaluate_all(),drag_to(),wait_for(),dispatch_event(),bounding_box(),scroll_into_view_if_needed()tap(options)— touch-tap on an element (requireshas_touch: truecontext);TapOptionsbuilder withforce,modifiers,position,timeout,trialevaluate(expression, arg)— run a JavaScript function with the element as first argument, returns typedR: DeserializeOwnedevaluate_all(expression, arg)— run a JavaScript function with all matching elements as an array, returns typedR: DeserializeOwneddrag_to(target, options)— drag this element to another;DragToOptionsbuilder withforce,source_position,target_position,timeout,trialwait_for(options)— wait for element to reach a state (Visible,Hidden,Attached,Detached);WaitForOptionswithstateandtimeoutdispatch_event(type, event_init)— fire DOM events with optional initialization databounding_box()— get element dimensions and position (x, y, width, height)scroll_into_view_if_needed()— scroll element into viewportpageproperty — back-reference to the owning Page from any Locator
- TLS backend features — Expose
native-tls,rustls-tls-native-roots, andrustls-tls-webpki-rootsfeatures for choosing TLS implementation (PR #41). Defaults tonative-tls. - Locator filtering & composition —
filter(),and_(),or_()methods for narrowing and combining locatorsfilter(FilterOptions)— narrow byhas_text,has_not_text,has(child locator),has_notand_(locator)— match elements satisfying both locatorsor_(locator)— match elements satisfying either locator
- Locator interaction methods —
focus(),blur(),press_sequentially(),all_inner_texts(),all_text_contents()focus()/blur()— set or remove keyboard focus on an elementpress_sequentially(text, options)— type characters one by one with optional delayall_inner_texts()/all_text_contents()— bulk text retrieval from all matching elementsdispatch_event(type, event_init)— fire DOM events with optional initialization databounding_box()— get element dimensions and position (x, y, width, height)scroll_into_view_if_needed()— scroll element into viewport
- BrowserContext runtime setters — configure context after creation
cookies(urls)— retrieve cookies, optionally filtered by URLclear_cookies(options)— remove cookies with optional name/domain/path filtersset_extra_http_headers(headers)— add HTTP headers to all requestsgrant_permissions(permissions, options)— grant browser permissions (geolocation, camera, etc.)clear_permissions()— revoke all granted permissionsset_geolocation(geolocation)— override device geolocation, or pass None to clearset_offline(offline)— toggle offline mode
- Page methods —
bring_to_front(),viewport_size(),set_extra_http_headers(),emulate_media(),pdf(),add_script_tag()bring_to_front()— activate the page tabviewport_size()— get current viewport dimensions (returns None if no_viewport context)set_extra_http_headers(headers)— add HTTP headers to all page requestsemulate_media(options)— override CSS media type, color scheme, reduced motion, forced colorspdf(options)— generate PDF (Chromium only), with full options (margins, scale, landscape, etc.)add_script_tag(options)— inject JavaScript via URL, file path, or inline content
- Page timeout & state —
set_default_timeout(),set_default_navigation_timeout(),is_closed(),frames()set_default_timeout(ms)/set_default_navigation_timeout(ms)— configure default timeouts for actions and navigationis_closed()— check if page has been closed (tracks close events from server)frames()— list page frames (currently main frame only; iframe enumeration planned)
- BrowserContext timeout defaults —
set_default_timeout(),set_default_navigation_timeout()- Propagates to all existing pages and newly created pages in the context
- Response body access —
body(),text(),json(),all_headers(),header_value(),headers_array()body()— response body as raw bytestext()— response body as UTF-8 stringjson::<T>()— parse response body as typed JSON (T: DeserializeOwned)all_headers()— all response headers as HashMap (merges duplicates)header_value(name)— get a single header value by nameheaders_array()— all headers asVec<HeaderEntry>preserving duplicates
- Request properties —
headers(),post_data(),post_data_buffer(),post_data_json(),failure(),all_headers(),header_value(),headers_array(),timing()headers()— request headers as HashMap (from initializer)post_data()/post_data_buffer()— request body as string or bytes (base64-decoded)post_data_json::<T>()— parse request body as typed JSONfailure()— error text if request failed (set onrequestFailedevent)all_headers()/header_value()/headers_array()— full raw headers via RPCtiming()—ResourceTimingwith 9 timing fields (extracted from Response onrequestFinished)
Changed
- Playwright driver upgraded to 1.58.2 (from 1.56.1) — includes WebKit 26.0, Chromium 133, Firefox 135
Fixed
- WebKit
launchPersistentContextnow works — Closes #39. Upgraded Playwright driver resolves "Browser started with no default context" error on macOS ARM64 - docs.rs build — Pin docs.rs to
nightly-2025-05-01to work aroundgeneric-array0.14 incompatibility with Rust 1.92+ (doc_auto_cfgremoval)
v0.8.6
Fixed
- docs.rs build — Skip Playwright driver download when building on docs.rs (no network access needed for documentation)
- Imprecise dependency versions — Pin workspace dependencies to minor versions (e.g.,
serde = "1.0"instead of"1")
v0.8.5
Added
ignore_default_argsfor persistent contexts - Addedignore_default_argsoption toBrowserContextOptionsfor use withlaunch_persistent_context_with_options()(Issue #38)IgnoreDefaultArgs::Bool(true)- Playwright does not pass its own default argsIgnoreDefaultArgs::Array(vec)- Filters out specific default arguments- Applies same
ignoreDefaultArgs→ignoreAllDefaultArgsprotocol normalization asLaunchOptions - Matches Playwright's official
launchPersistentContextAPI
- Page network event listeners - Subscribe to network events on individual pages (PR #37)
page.on_request(handler)- Fires when a request is issuedpage.on_response(handler)- Fires when a response is receivedpage.on_request_finished(handler)- Fires when a request completes successfullypage.on_request_failed(handler)- Fires when a request fails- Lazy subscription: events are only subscribed when a handler is registered
- Works with iframes and sub-resources
- Response accessor methods -
response.status(),response.status_text(),response.url()(PR #37) page.go_back()/page.go_forward()- History navigation with optional timeout and wait_until optionspage.set_content(html)- Set page HTML content directly, with optional timeout and wait_until optionspage.wait_for_load_state(state)- Wait forload,domcontentloaded, ornetworkidlestatespage.wait_for_url(url)- Wait for navigation to a matching URL (exact string or glob pattern)locator.is_hidden()/locator.is_disabled()- Negative state checks complementingis_visible()andis_enabled()to_have_screenshot()visual regression assertion (Issue #35)expect(locator).to_have_screenshot(path, options)— compare locator screenshot against baselineexpect_page(&page).to_have_screenshot(path, options)— page-level screenshot comparison- Auto-creates baseline on first run, compares on subsequent runs
max_diff_pixels/max_diff_pixel_ratio— configurable tolerancethreshold— per-pixel color distance tolerance (default 0.2)animations: Disabled— freeze CSS animations/transitions before capturemask— overlay locators with pink (#FF00FF) to exclude dynamic contentupdate_snapshots— force baseline update- Generates diff image on failure highlighting differences in red
- Auto-retry with timeout (default 5s), matching Playwright's assertion pattern
Fixed
- Replace
unwrap()with graceful error handling in network event dispatch (Issue #40)
v0.8.4
Added
get_by_*locators - Modern Playwright locator methods for finding elements by user-facing attributesget_by_text(text, exact)- Find by text contentget_by_label(text, exact)- Find form controls by associated labelget_by_placeholder(text, exact)- Find inputs by placeholder textget_by_alt_text(text, exact)- Find images by alt textget_by_title(text, exact)- Find elements by title attributeget_by_test_id(test_id)- Find elements bydata-testidattribute (always exact)get_by_role(role, options)- Find elements by ARIA role with optional name, checked, disabled, expanded, selected, level, pressed, include_hidden filters- All methods available on both
PageandLocator(chainable) - Case-insensitive substring matching by default (
exact=false), case-sensitive exact withexact=true AriaRoleenum with 81 ARIA roles for compile-time safetyGetByRoleOptionsstruct for role-based filtering
connect_over_cdp- Connect to Chrome DevTools Protocol endpoints (Issue #32)browser_type.connect_over_cdp(endpoint_url, options)- Connect to remote Chrome via CDP- Supports browserless, Chrome with
--remote-debugging-port, and other CDP services - Accepts optional headers, timeout, and slow_mo options
- Chromium-only (returns error for Firefox/WebKit)
Locator.all()- Iterate over all matching elements (Issue #33)locator.all()returnsVec<Locator>, one per matching element- Empty vec for non-matching selectors (no error)
- Matches Playwright's
locator.all()API
- Improved error messages - All locator methods now include the selector in error messages (Issue #33)
- Timeout errors show
[selector: div.page-number > span:last-child]instead of generic messages - Applied to all query methods (
text_content,get_attribute, etc.) and action methods (click,fill, etc.)
- Timeout errors show
- BrowserContext proxy support - Added
proxyoption toBrowserContextOptionsfor per-context proxy configuration (PR #29, Issue #28)- Enables rotating proxies without creating new browser instances
- Supports HTTP and SOCKS proxies with optional authentication
- Complete Route API - Full network interception parity with Playwright (Issue #36)
route.fallback(overrides)- Continue to next matching handler (handler chaining)route.fetch(options)- Fetch actual response for inspection/modification before fulfillingFetchResponsetype withstatus(),ok(),headers(),body(),text(),json()methodsFetchOptionsbuilder for customizing fetch requests (method, headers, post_data, timeout)
- Context-level routing -
BrowserContext.route(),unroute(),unroute_all()for routing across all pages in a context - Page unroute methods -
page.unroute(pattern)andpage.unroute_all()for removing route handlers - APIRequestContext - Internal implementation for
route.fetch()via BrowserContext's request context- Handles fetch → fetchResponseBody → disposeAPIResponse protocol flow
- Automatic base64 encoding/decoding for request and response bodies
UnrouteBehaviorenum - Control behavior when removing route handlers
Fixed
no_viewport(true)/--start-maximizednot working - Fixed protocol field name for viewport disabling (Issue #34)no_viewportnow correctly serializes asnoDefaultViewport(matching the Playwright protocol)- Previously serialized as
noViewportwhich the server silently ignored - Enables
--start-maximizedwithno_viewport(true)to produce maximized browser windows
v0.8.3
Added
- PLAYWRIGHT_VERSION constant - Exposes bundled Playwright driver version (
1.56.1) as a public constant for version-aware browser installation (Issue #27) - Helpful browser installation errors - Detects missing browser errors and provides actionable guidance (Issue #27)
- Page.content() - Returns full HTML content of the page including DOCTYPE (Issue #23)
page.content()- Retrieves complete HTML markupframe.content()- Frame-level implementation for consistency with Playwright API
- Page.set_viewport_size() - Dynamically resize viewport for responsive testing (Issue #24)
page.set_viewport_size(viewport)- Set viewport to specific width/height- Enables testing mobile, tablet, and desktop layouts within a single page session
Fixed
- page.url() hash navigation - URL now correctly includes hash fragment after anchor clicks (Issue #26)
- Frame now handles "navigated" events to track URL changes including hash updates
- Page delegates to main frame for URL (matches playwright-python/JS behavior)
Changed
- Rust Edition 2024 - Upgraded to Rust Edition 2024, requiring Rust 1.85+
- README documentation - Added comprehensive browser installation section (Issue #25)