Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
mobile device's viewport and touch support together. [#94]

### Changed
- `Ferrum::TimeoutError` names the CDP command and session it was waiting on, and exposes them as `#command` and
`#session_id`. Waits that aren't for a command keep the old message [#470]
- `Ferrum::Page::Stream#stream` now closes the CDP stream handle (`IO.close`) once it's been fully read, so streams
opened for `Ferrum::Browser#pdf` and `Ferrum::Page::Tracing#record` no longer keep their backing storage alive in
the browser; a failed `IO.close` is raised to the caller.
Expand Down
2 changes: 1 addition & 1 deletion lib/ferrum/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def send_message(message, async:, timeout: nil)
@pendings.delete(message[:id])

raise DeadBrowserError if data.nil? && @ws.messages.closed?
raise TimeoutError unless data
raise TimeoutError.new(message[:method], session_id: message[:sessionId]) unless data

error, response = data.values_at("error", "result")
raise_browser_error(error) if error
Expand Down
36 changes: 34 additions & 2 deletions lib/ferrum/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,50 @@ def initialize(url, pendings = [])

# Raised when waiting for a response from the browser times out.
class TimeoutError < Error
# The CDP method that didn't answer in time, `nil` when the wait wasn't for a command.
#
# Explains that waiting for a response timed out.
# @return [String, nil]
attr_reader :command

# The session the command was sent to, `nil` for the browser-wide session.
#
# @return [String, nil]
attr_reader :session_id

#
# @param [String, nil] command
# The CDP method that timed out.
#
# @param [String, nil] session_id
# The session it was sent to.
#
def initialize(command = nil, session_id: nil)
@command = command
@session_id = session_id
super()
end

#
# Explains that waiting for a response timed out, naming the command when
# there was one.
#
# @return [String]
#
def message
"Timed out waiting for response. It's possible that this happened " \
"Timed out waiting for #{awaited}. It's possible that this happened " \
"because something took a very long time (for example a page load " \
"was slow). If so, setting the :timeout option to a higher value might " \
"help. If this happened on an internal protocol call instead, try " \
"raising :protocol_timeout."
end

private

def awaited
return "response" unless @command

@session_id ? "a response to #{@command} (session #{@session_id})" : "a response to #{@command}"
end
end

# Raised when an evaluated script takes too long to return a value.
Expand Down
14 changes: 13 additions & 1 deletion sig/ferrum/errors.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,19 @@ module Ferrum
end

class TimeoutError < Error
def message: () -> "Timed out waiting for response. It's possible that this happened because something took a very long time (for example a page load was slow). If so, setting the :timeout option to a higher value might help. If this happened on an internal protocol call instead, try raising :protocol_timeout."
attr_reader command: String?
attr_reader session_id: String?

@command: String?
@session_id: String?

def initialize: (?String? command, ?session_id: String?) -> void

def message: () -> String

private

def awaited: () -> String
end

class ScriptTimeoutError < Error
Expand Down
7 changes: 7 additions & 0 deletions spec/client_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# frozen_string_literal: true

describe Ferrum::Client do
describe "timeouts" do
it "names the command that timed out" do
expect { page.command("Page.navigate", timeout: 0.5, url: base_url("/really_slow")) }
.to raise_error(Ferrum::TimeoutError, /a response to Page.navigate \(session .+\)/)
end
end

describe "a dead connection" do
let(:remote) { Ferrum::Browser.new(base_url: base_url, timeout: 10, protocol_timeout: 10) }

Expand Down
Loading