Class: Terminus::Browser

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Timeouts
Defined in:
lib/terminus/browser.rb

Constant Summary

Constants included from Timeouts

Timeouts::TIMEOUT

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Timeouts

#wait_with_timeout

Constructor Details

#initialize(controller, id) ⇒ Browser

Returns a new instance of Browser.



11
12
13
14
15
16
17
18
19
20
# File 'lib/terminus/browser.rb', line 11

def initialize(controller, id)
  @controller = controller
  @attributes = {'id' => id}
  @docked     = false
  @frames     = Set.new
  @namespace  = Faye::Namespace.new
  @results    = {}

  add_timeout(:dead, Timeouts::TIMEOUT) { drop_dead! }
end

Instance Attribute Details

#connectorObject (readonly)

Returns the value of attribute connector.



5
6
7
# File 'lib/terminus/browser.rb', line 5

def connector
  @connector
end

#sockets=(value) ⇒ Object (writeonly)

Sets the attribute sockets

Parameters:

  • value

    the value to set the attribute sockets to.



6
7
8
# File 'lib/terminus/browser.rb', line 6

def sockets=(value)
  @sockets = value
end

Instance Method Details

#===(params) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/terminus/browser.rb', line 22

def ===(params)
  return docked? if params == :docked
  return params == id if String === params
  return false if @parent
  return false unless @user_agent

  params.all? do |name, value|
    property = __send__(name)
    value === property
  end
end

#ask(command, retries = RETRY_LIMIT) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/terminus/browser.rb', line 34

def ask(command, retries = RETRY_LIMIT)
  debug(:ask, id, command)
  value = if @connector
    message = MultiJson.dump('commandId' => '_', 'command' => command)
    response = @connector.request(message)
    if response.nil?
      retries == false ? false : ask(command)
    else
      result_hash = MultiJson.load(response)
      result_hash['value']
    end
  else
    command_id = tell(command)
    result_hash = wait_with_timeout(:result) { result(command_id) }
    result_hash[:value]
  end
  debug(:val, id, command, value)
  raise ObsoleteElementError if value.nil?
  value
rescue Timeouts::TimeoutError => e
  raise e if retries == 1
  ask(command, retries - 1)
end

#current_pathObject



58
59
60
# File 'lib/terminus/browser.rb', line 58

def current_path
  URI.parse(current_url).path
end

#current_urlObject



62
63
64
65
66
# File 'lib/terminus/browser.rb', line 62

def current_url
  url = @attributes['url']
  return '' unless url
  rewrite_local(ask([:current_url]))
end

#debug(*args) ⇒ Object



68
69
70
# File 'lib/terminus/browser.rb', line 68

def debug(*args)
  p args if Terminus.debug
end

#debuggerObject



72
73
74
75
# File 'lib/terminus/browser.rb', line 72

def debugger
  Client::PhantomJS.debugger if name == 'PhantomJS'
  Readline.readline('Driver paused, press ENTER to continue')
end

#docked?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/terminus/browser.rb', line 77

def docked?
  @docked
end

#evaluate_script(expression) ⇒ Object



81
82
83
# File 'lib/terminus/browser.rb', line 81

def evaluate_script(expression)
  ask([:evaluate, expression])
end

#execute_script(expression) ⇒ Object



85
86
87
88
# File 'lib/terminus/browser.rb', line 85

def execute_script(expression)
  @connector ? ask([:execute, expression]) : tell([:execute, expression])
  nil
end

#find_css(css, driver = nil) ⇒ Object



90
91
92
93
# File 'lib/terminus/browser.rb', line 90

def find_css(css, driver = nil)
  return [] unless @find_enabled
  ask([:find_css, css, false]).map { |id| Node.new(self, id, driver) }
end

#find_xpath(xpath, driver = nil) ⇒ Object



95
96
97
98
# File 'lib/terminus/browser.rb', line 95

def find_xpath(xpath, driver = nil)
  return [] unless @find_enabled
  ask([:find_xpath, xpath, false]).map { |id| Node.new(self, id, driver) }
end

#frame!(frame_browser) ⇒ Object



100
101
102
# File 'lib/terminus/browser.rb', line 100

def frame!(frame_browser)
  @frames.add(frame_browser)
end

#framesObject



104
105
106
# File 'lib/terminus/browser.rb', line 104

def frames
  @frames.to_a
end

#go_backObject



108
109
110
# File 'lib/terminus/browser.rb', line 108

def go_back
  execute_script('window.history.back()')
end

#go_forwardObject



112
113
114
# File 'lib/terminus/browser.rb', line 112

def go_forward
  execute_script('window.history.forward()')
end

#htmlObject Also known as: body



116
117
118
# File 'lib/terminus/browser.rb', line 116

def html
  ask([:body])
end

#idObject



121
122
123
# File 'lib/terminus/browser.rb', line 121

def id
  @attributes['id']
end

#infinite_redirect?Boolean

Returns:

  • (Boolean)


125
126
127
128
# File 'lib/terminus/browser.rb', line 125

def infinite_redirect?
  return @infinite_redirect unless @connector
  evaluate_script('!!window.TERMINUS_INFINITE_REDIRECT')
end

#nameObject



130
131
132
133
# File 'lib/terminus/browser.rb', line 130

def name
  return 'PhantomJS' if @user_agent.to_str =~ /\bPhantomJS\b/
  @user_agent.browser
end

#page_idObject



135
136
137
# File 'lib/terminus/browser.rb', line 135

def page_id
  @attributes['page']
end

#ping!(message) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/terminus/browser.rb', line 139

def ping!(message)
  debug(:ping, id)
  debug(:recv, message)

  remove_timeout(:dead)
  add_timeout(:dead, Timeouts::TIMEOUT) { drop_dead! }

  @attributes['raw_url'] = message['url']
  message['url'] = rewrite_local(message['url'])

  @attributes   = @attributes.merge(message)
  @find_enabled = true
  @user_agent   = UserAgent.parse(message['ua'].gsub(/.*?\bOPR\b/, 'Opera'))

  detect_dock_host

  @infinite_redirect = message['infinite']

  if id =~ /\//
    @parent = Terminus.browser(id.gsub(/\/[^\/]+$/, ''))
    @parent.frame!(self) unless @parent == self
  end

  start_connector if message['sockets'] and sockets?

  @ping = true
end

#raw_urlObject



167
168
169
# File 'lib/terminus/browser.rb', line 167

def raw_url
  @attributes['raw_url']
end

#reset!Object



171
172
173
174
175
176
177
178
179
180
# File 'lib/terminus/browser.rb', line 171

def reset!
  if url = @attributes['url']
    uri = URI.parse(url)
    visit("http://#{uri.host}:#{uri.port}/")
  end
  ask([:clear_cookies])

  @attributes.delete('url')
  @find_enabled = false
end

#response_headersObject



182
183
184
# File 'lib/terminus/browser.rb', line 182

def response_headers
  Headers.new(evaluate_script('TERMINUS_HEADERS'))
end

#result(id) ⇒ Object



191
192
193
194
# File 'lib/terminus/browser.rb', line 191

def result(id)
  return nil unless @results.has_key?(id)
  @results.delete(id)
end

#result!(message) ⇒ Object



186
187
188
189
# File 'lib/terminus/browser.rb', line 186

def result!(message)
  debug(:result, id, message['commandId'], message['result'])
  @results[message['commandId']] = {:value => message['result']}
end

#return_to_dockObject



196
197
198
199
# File 'lib/terminus/browser.rb', line 196

def return_to_dock
  return unless @dock_host
  visit("http://#{@dock_host}:#{Terminus.port}/")
end

#save_screenshot(path, options = {}) ⇒ Object

Raises:

  • (Capybara::NotSupportedByDriverError)


201
202
203
204
# File 'lib/terminus/browser.rb', line 201

def save_screenshot(path, options = {})
  raise Capybara::NotSupportedByDriverError.new unless name == 'PhantomJS'
  Client::PhantomJS.save_screenshot(path, options)
end

#sockets?Boolean

Returns:

  • (Boolean)


206
207
208
# File 'lib/terminus/browser.rb', line 206

def sockets?
  @sockets.nil? ? Terminus.sockets != false : @sockets
end

#sourceObject



210
211
212
# File 'lib/terminus/browser.rb', line 210

def source
  evaluate_script('TERMINUS_SOURCE')
end

#status_codeObject



214
215
216
# File 'lib/terminus/browser.rb', line 214

def status_code
  evaluate_script('TERMINUS_STATUS')
end

#tell(command) ⇒ Object



218
219
220
221
222
223
# File 'lib/terminus/browser.rb', line 218

def tell(command)
  command_id = @namespace.generate
  debug(:tell, id, command, command_id)
  messenger.publish(command_channel, 'command' => command, 'commandId' => command_id)
  command_id
end

#titleObject



225
226
227
# File 'lib/terminus/browser.rb', line 225

def title
  ask([:title])
end

#to_sObject Also known as: inspect



261
262
263
# File 'lib/terminus/browser.rb', line 261

def to_s
  "<#{self.class.name} #{name} #{version} (#{os})>"
end

#visit(url, retries = RETRY_LIMIT) ⇒ Object



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/terminus/browser.rb', line 229

def visit(url, retries = RETRY_LIMIT)
  close_frames!
  uri = @controller.rewrite_remote(url, @dock_host)
  uri.host = @dock_host if uri.host =~ LOCALHOST
  @controller.visit_url(uri.to_s)

  @find_enabled = true

  if @connector
    ask([:visit, uri.to_s], false)
    @connector.drain_socket
    @attributes['url'] = rewrite_local(uri)
  else
    tell([:visit, uri.to_s])
    wait_for_ping
  end

  if infinite_redirect?
    @infinite_redirect = nil
    raise Capybara::InfiniteRedirectError
  end

rescue Timeouts::TimeoutError => e
  raise e if retries.zero?
  visit(url, retries - 1)
end

#wait_for_pingObject



256
257
258
259
# File 'lib/terminus/browser.rb', line 256

def wait_for_ping
  @ping = false
  wait_with_timeout(:ping) { @ping or @dead }
end