You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Chainable setters where an option struct had none, or was missing some.AddLocatorHandlerOptions gains times and no_wait_after; HighlightOptions gains style; StartJSCoverageOptions gains reset_on_navigation and report_anonymous_scripts; StartCSSCoverageOptions gains reset_on_navigation; WebSocketRouteCloseOptions gains code and reason; RouteFromHarOptions gains the update_content and update_mode it lacked. These structs are #[non_exhaustive], so outside the crate those fields could only be set by building default() and mutating field by field. AccessibilitySnapshotOptions deliberately gets none: its two fields are ignored, which its docs now say.
Changed
The build script assembles the driver into the user cache, not the build directory. The path is the one playwright-rs install already wrote and the runtime already probed (~/.cache/playwright-rust/<version>/ on Linux, ~/Library/Caches on macOS, %LOCALAPPDATA% on Windows), so one download serves every target directory, cargo-mutants copy, and workspace on a machine instead of one per dependency hash. Deleting the cache reassembles on the next build. PLAYWRIGHT_DRIVER_CACHE_DIR and PLAYWRIGHT_SKIP_DRIVER_DOWNLOAD are unchanged; in CI, cache that directory alongside the browsers and drop the cache-dir knob. ADR 0007 records why this breaks cargo's write-only-to-OUT_DIR convention on purpose.
Error::ServerNotFound now says what became of the bundled driver. The build script assembles the driver at compile time, and when that download fails in a consumer's build nothing tells them: cargo shows a dependency's cargo:warning lines to nobody, the crate compiles, and the first launch fails with a message that said to npm install playwright. The message now reports the build-time outcome recorded by build.rs (the download failed, it was skipped with PLAYWRIGHT_SKIP_DRIVER_DOWNLOAD, or the assembled driver has since gone missing from the directory it names) and the ways to get one: rebuilding, playwright-rs install, or PLAYWRIGHT_DRIVER_PATH. The variant itself is unchanged, so code matching on it still compiles.
Removed
The Claude Code plugin channel for the agent skill. The .claude-plugin/ manifests are gone, so /plugin install playwright-rs@playwright-rust no longer resolves and an existing plugin install will not see further updates. The skill ships through one channel now: npx skills add padamson/playwright-rust, refreshed with npx skills update. The skill's own metadata.version is the update gate consumers compare against, and the version guard checks only that.
Fixed
A triggered locator handler no longer stalls the action that tripped it until its timeout. After running the handler the crate told the server to resume with a method name the driver does not have (resolveLocatorHandler; the protocol calls it resolveLocatorHandlerNoReply), the rejection was discarded, and the parked click or fill waited out its full timeout and failed. Present since the feature shipped in 0.12.0; the existing test removed the overlay before acting, so no handler ever fired under test. The resume is now sent in every case, including a handler that panics or a trigger for a uid the page no longer knows, and a failed resume is logged at warn.
add_locator_handler with times: Some(0) is now a no-op, as upstream's is. The invocation counter was decremented past zero on the first trigger: a debug build panicked inside the dispatch task while it held the handler registry lock, so every later locator-handler call on that page panicked too; a release build wrapped to u32::MAX and the "zero times" handler ran on every trigger, forever. Counted handlers still run exactly times times and are unregistered on the last one.
A locator handler that returns an error keeps its registration, so the next actionability check retries it, matching upstream. It used to be unregistered as if it had succeeded.
Download::path() returns the downloaded file. It asked the driver for path, a method the Artifact channel does not have; the protocol calls it pathAfterFinished. Every call failed with a protocol error since the method shipped, and no test called it.
Routed WebSockets work end to end.WebSocketRoute sent connectToServer and close, neither of which exists on its channel (the protocol has connect and closePage), and it listened for a close event that the server never emits (closePage and closeServer are the real ones). It also never forwarded traffic: upstream's client does the proxying itself once connect_to_server is called, so page messages now go to the server, server messages and closes go to the page, and a page-side close closes the server side, unless an on_message or on_close handler takes over. A handler that neither connects nor closes now leaves the page's socket open (ensureOpened), so a mocked socket can be written to. The route tests called connect_to_server inside handlers whose errors were only logged; they now assert the server's echo reaches the page, and a new test mocks replies without a server. WebSocketRoute::is_connected() is new.
set_default_timeout and set_default_navigation_timeout no longer send the driver a command it does not have. Each call also sent setDefaultTimeoutNoReply or setDefaultNavigationTimeoutNoReply, which no driver this crate has shipped defines (upstream dropped them when it moved the defaults client-side); the rejection was logged at warn on every call. The defaults were, and are, applied client-side to each call that takes a timeout, as upstream does, so behavior is unchanged apart from the log line.
remove_locator_handler on a selector with no handler is a no-op, matching upstream; it used to fail with a protocol error, which a times(0) registration or an exhausted counted handler always left behind.