Class: Ask::WebFetch::Backends::AttachedBrowser::Page

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/web_fetch/backends/attached_browser.rb

Overview

One tab in the attached browser, closed with #close. Speaks just enough CDP for the Browser backend: navigate, read title/URL/HTML, and report the main-document HTTP status.

Defined Under Namespace

Classes: Network

Instance Method Summary collapse

Constructor Details

#initialize(client, timeout:, restore_focus_to: nil) ⇒ Page

Returns a new instance of Page.



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 50

def initialize(client, timeout:, restore_focus_to: nil)
  @client = client
  @timeout = timeout
  @restore_focus_to = restore_focus_to
  @target_id = @client.command('Target.createTarget', url: 'about:blank')['targetId']
  @session = @client.session(
    @client.command('Target.attachToTarget', targetId: @target_id, flatten: true)['sessionId']
  )
  # Subscribed BEFORE any navigation so the idle wait sees the
  # page's real load traffic (lazy SPAs render in waves).
  @network = Network.new(self)
end

Instance Method Details

#bodyObject



84
85
86
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 84

def body
  evaluate('document.documentElement.outerHTML') || ''
end

#closeObject



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 95

def close
  @client.command('Target.closeTarget', targetId: @target_id)
rescue Ferrum::Error
  nil
ensure
  # The attached dev Chrome window steals focus when a tab is
  # created; give it back once the tab is gone — but only to an
  # app that ISN'T Chrome, so a fetch while the user is already
  # looking at Chrome doesn't ping-pong.
  FocusRestorer.restore_frontmost(@restore_focus_to)
end

#evaluate(expression) ⇒ Object



107
108
109
110
111
112
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 107

def evaluate(expression)
  response = @session.command('Runtime.evaluate', expression: expression, returnByValue: true)
  # Ferrum's command() unwraps CDP's outer "result", leaving
  # { "result" => RemoteObject, "exceptionDetails" => ... }.
  response.dig('result', 'value')
end

#go_to(url) ⇒ Object

Navigates and does not return until the document has actually loaded — Page.navigate only starts the navigation, and reading the page before it commits yields an empty document (the very failure mode this class exists to avoid).



67
68
69
70
71
72
73
74
75
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 67

def go_to(url)
  result = @session.command('Page.navigate', url: url)
  error = result['errorText']
  if error && error != 'net::ERR_ABORTED'
    raise Ferrum::StatusError, "Request to #{url} failed (#{error})"
  end

  wait_for_load
end

#networkObject

Minimal network facade for the Browser backend: status from the Navigation Timing API, idle from CDP Network events (subscribed in the constructor, before navigation).



91
92
93
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 91

def network
  @network
end

#titleObject



76
77
78
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 76

def title
  evaluate('document.title')
end

#urlObject



80
81
82
# File 'lib/ask/web_fetch/backends/attached_browser.rb', line 80

def url
  evaluate('location.href')
end