Skip to content

0.20.0

Choose a tag to compare

@route route released this 26 Oct 18:18
· 15 commits to main since this release

Added

  • 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