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
keyboard.hold(:shift) { } holds modifiers for every keyboard and mouse event in the block, e.g. a shift+drag, and
releases them afterwards. mouse.move accepts modifiers: like down and up [#581]
page.console collects console.* calls, browser log entries and uncaught exceptions as Console::Messages, Enumerable over the last 1000, and page.on(:console) yields new ones, also on workers. No more parsing the :logger output to get them [cuprite#113]
:logger accepts a Logger: CDP messages and browser output go out at debug level, with ferrum:protocol or ferrum:browser as program name
FERRUM_LOG picks what's logged: *, -browser, CDP method patterns like Page.* or -Network.*, 0 for nothing
Logger output written to a terminal is colored: arrows by kind, bold methods, dimmed times. Files, pipes and NO_COLOR keep plain text, FERRUM_LOG_COLOR=always|never overrides it
FERRUM_LOG_FORMAT=annotated puts the command id and method in front of each CDP message and gives responses
their command's method and duration, FERRUM_LOG_FORMAT=json writes each CDP message as JSON alone
Ferrum keeps reading what Chrome writes after startup: it's logged on the browser channel, the last 100 lines are in browser.process.output
browser.add_extension adds an extension for pages and iframes attached afterwards [#663]
page.isolated_world(name) and frame.isolated_world(name) evaluate JavaScript in a world hidden from the page
Node#backend_node_id and Node#node_type
page.wait_for_navigation { } and wait_for_navigation! { } wait for a navigation the block starts, e.g. a click
made from JavaScript [#679]
Changed
evaluate fetches the whole result in one CDP call instead of one per nested object, dates come back as ISO 8601
strings and a cyclic result is a Hash/Array with CyclicObject only where it refers back to itself, instead of
being replaced by CyclicObject entirely
Nodes returned by evaluate, css and the other finders no longer cost a DOM.describeNode call each, Node#description is fetched on first use. Node.new takes the node as Chrome deep serializes it instead of
a target id and a description
The logger cuts any string value over 1024 characters in CDP messages, not just screenshots. FERRUM_LOG_VALUE_LENGTH sets the length, 0 keeps them whole. FERRUM_LOGGING_SCREENSHOTS is gone
ProcessTimeoutError is raised as soon as Chrome exits instead of after :process_timeout
The logger no longer prints [log] ... lines for console calls, use page.on(:console) { |message| puts message }
FERRUM_DEBUG is deprecated in favor of FERRUM_LOG=*
keyboard.down and keyboard.up raise ArgumentError for a modifier such as :shift and point to hold. down
used to crash with NoMethodError, up sent an empty keyup event [#581]
Behind a proxy with :user and :password, Ferrum stops continuing intercepted requests once you subscribe to on(:request), like it already does without a proxy: your callbacks have to continue or abort every request, or it
stays paused until the page times out [#332]
evaluate_on_new_document is a Page method sending Page.addScriptToEvaluateOnNewDocument to that page, with world_name: and run_immediately:. It returns the script id for remove_script_on_new_document. It used to add
an extension for every page built afterwards, use browser.add_extension for that [#663]
Extension files are read in Browser.new, a missing one raises Errno::ENOENT there instead of on first
navigation [#663]
Browser details (user agent, versions) come from Browser.getVersion over CDP for every browser, local or remote. /json/version is only asked for the websocket url when url: is given, so ws_url: works against services
without an HTTP endpoint and a local launch makes no HTTP call
NoWebSocketUrlError names the HTTP status /json/version answered with, e.g. 401 Unauthorized for a missing token or 429 Too Many Requests for a full remote browser service, and exposes it as #status
Fixed
Node#property and Node#attribute read any name, a quote in it no longer breaks the script, and property
returns a Ferrum::Node for a property holding one instead of {} [#673]
evaluate, execute and friends raise JavaScriptError when JS throws something other than an Error, e.g. throw "smth", instead of returning it. Returning an Error object no longer crashes with NoMethodError
evaluate keeps null and undefined in arrays and returns NaN, Infinity, -0 and BigInt instead of nil,
and no longer crashes on objects with getters
workers skips detached workers, target.worker with no session raises NoSuchTargetError instead of a CDP error
attach_target reuses a target's session and returns the target, instead of opening one more that reruns extensions
Service workers registered by a page stayed attached and alive for the browser's lifetime, now Chrome can stop them
An out-of-process iframe kept its parent page's session when Target.targetCreated came before Target.attachedToTarget, so commands sent through it reached the page [#663]
:extensions run before the document's own scripts in popups and out-of-process iframes too. Popups used to get
them only after loading, iframes not at all, and every page ran them once more on about:blank [#663]
Every CDP response was scanned for Base64 screenshots to hide from the logger, even with no :logger set
Headers can be added on a remote browser whose /json/version has no User-Agent, such as browserless v2, instead of
failing with Invalid parameters [rubycdp/cuprite#300]
A Ferrum::Node found before a navigation or reload kept its cached CDP node id, which Chrome reuses for the new
document, so focus, click, scroll_into_view and friends silently hit another element. Node ids are now dropped
on DOM.documentUpdated and such nodes raise Ferrum::NodeNotFoundError [#86]
Replacing an iframe's content with frame.content= or querying the whole page with accessibility.query broke every
node found before it with Ferrum::NodeNotFoundError, even though the nodes were still on the page. Their ids are
requested again now. A node used while the page is still loading a new document says so in its error [#650]
Behind a proxy with credentials, request.abort in on(:request) and network.blacklist/whitelist were ignored
because Ferrum's own proxy handler continued every request first. It now only continues requests nobody else handles [#332]
mouse.click(modifiers:) sent its mousemove without the modifiers [#581]
When Chrome can't compute an element's content quads, node.click falls back to its bounding rect, but it added the
page scroll offset and missed the element on a scrolled page. It clicks in viewport coordinates now
Proxy#rotate to an upstream proxy failed every HTTPS request with ERR_TUNNEL_CONNECTION_FAILED
On JRuby browser.pages, windows(:last) and workers came back in random order, so the window a page had just
opened wasn't the last one. Targets are kept in the order they were created now
On JRuby lines written to a :logger IO from several threads at once could get mixed up, they're written one by one now
Removed
Browser::Process#default_user_agent, #browser_version, #protocol_version, #v8_version and #webkit_version,
use Browser#default_user_agent and Browser#version instead
Ruby 3.1 support, Ferrum requires Ruby 3.2 or newer