apparition 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4f76aefa6b5bebbab16d325e6f434846c2a426b74df9b8c0248465653124202
4
- data.tar.gz: e9538e39a9c912471527fc456e801f0b3cc261bf042ddc82177d0e74e0769a33
3
+ metadata.gz: 69753c37a3e00ce9d57e86847601bef5e39a820ebef96db2c4ad7a6cb922f341
4
+ data.tar.gz: 486caf74087a17e078b39e4960a0c707b090142f1831d12b9755ad8b2cbb0596
5
5
  SHA512:
6
- metadata.gz: 9f187d2d4b1185e2fe5460adf9435daec58d008789e69bca907df06bdc20f59b1b8808ac4f346ef1c7d00d4caa62a6fe7aaf033a9e3287299a007e8c9c7493fb
7
- data.tar.gz: 443d5076e6b92f8c051a261663a8dc93a3ae2b0a75d87943579b762927b0f8d4e42a527b3c047c4ae937bf001198f7e14ebd8f4ea77de7ffd1ec04d4e096ad65
6
+ metadata.gz: 2f512ba7bbaca565d304a2ac0ede0d1c2b41fd3dc38d7f00b8dbe30b75bba2bbf3c35d7bcea2b00a17bdcbdb9d1702c27efcdfb9ef082b75de3988e7e48664c6
7
+ data.tar.gz: e01438d8900cd67015e0b473e7f710528ac1d8d4597cb8d0f47c97a1971a914b63cb52013bc1958d46621be58123105e1ed1f3d8f9e033ca0d908490fb152f8f
data/README.md CHANGED
@@ -51,7 +51,7 @@ Apparition supports all Capybara features, and the following extended features:
51
51
  * `page.driver.render_base64(format, options)`
52
52
  * `page.driver.scroll_to(left, top)`
53
53
  * `page.driver.basic_authorize(user, password)`
54
- * `page.driver.set_proxy(ip, port, type, user, password)`
54
+ * `page.driver.set_proxy(host, port, type, user, password, bypass: [bypass list passed to chrome])`
55
55
  * cookie handling
56
56
  * extra headers
57
57
 
@@ -3,21 +3,31 @@
3
3
  require 'capybara/apparition/errors'
4
4
  require 'capybara/apparition/dev_tools_protocol/target_manager'
5
5
  require 'capybara/apparition/page'
6
+ require 'capybara/apparition/console'
6
7
  require 'json'
7
8
  require 'time'
8
9
 
9
10
  module Capybara::Apparition
10
11
  class Browser
11
- attr_reader :client, :logger, :paper_size, :zoom_factor
12
+ attr_reader :client, :paper_size, :zoom_factor, :console
13
+ extend Forwardable
14
+
15
+ delegate %i[visit current_url status_code
16
+ title frame_title frame_url
17
+ find scroll_to clear_network_traffic
18
+ evaluate evaluate_async execute
19
+ fullscreen maximize
20
+ response_headers
21
+ go_back go_forward refresh] => :current_page
12
22
 
13
23
  def initialize(client, logger = nil)
14
24
  @client = client
15
- @logger = logger
16
25
  @current_page_handle = nil
17
26
  @targets = Capybara::Apparition::DevToolsProtocol::TargetManager.new
18
27
  @context_id = nil
19
28
  @js_errors = true
20
29
  @ignore_https_errors = false
30
+ @console = Console.new(logger)
21
31
 
22
32
  initialize_handlers
23
33
 
@@ -39,18 +49,6 @@ module Capybara::Apparition
39
49
  current_page.clear_network_traffic
40
50
  end
41
51
 
42
- def visit(url)
43
- current_page.visit url
44
- end
45
-
46
- def current_url
47
- current_page.current_url
48
- end
49
-
50
- def status_code
51
- current_page.status_code
52
- end
53
-
54
52
  def body
55
53
  current_page.content
56
54
  end
@@ -60,40 +58,10 @@ module Capybara::Apparition
60
58
  # command 'source'
61
59
  end
62
60
 
63
- def title
64
- # Updated info doesn't have correct title when changed programmatically
65
- # current_target.title
66
- current_page.title
67
- end
68
-
69
- def frame_title
70
- current_page.frame_title
71
- end
72
-
73
- def frame_url
74
- current_page.frame_url
75
- end
76
-
77
- def find(method, selector)
78
- current_page.find(method, selector)
79
- end
80
-
81
61
  def click_coordinates(x, y)
82
62
  current_page.click_at(x, y)
83
63
  end
84
64
 
85
- def evaluate(script, *args)
86
- current_page.evaluate(script, *args)
87
- end
88
-
89
- def evaluate_async(script, wait_time, *args)
90
- current_page.evaluate_async(script, wait_time, *args)
91
- end
92
-
93
- def execute(script, *args)
94
- current_page.execute(script, *args)
95
- end
96
-
97
65
  def switch_to_frame(frame)
98
66
  case frame
99
67
  when Capybara::Node::Base
@@ -166,10 +134,6 @@ module Capybara::Apparition
166
134
  true
167
135
  end
168
136
 
169
- def scroll_to(left, top)
170
- current_page.scroll_to(left, top)
171
- end
172
-
173
137
  def render(path, options = {})
174
138
  check_render_options!(options, path)
175
139
  img_data = current_page.render(options)
@@ -197,14 +161,6 @@ module Capybara::Apparition
197
161
  current_page.set_viewport width: width, height: height, screen: screen
198
162
  end
199
163
 
200
- def fullscreen
201
- current_page.fullscreen
202
- end
203
-
204
- def maximize
205
- current_page.maximize
206
- end
207
-
208
164
  def network_traffic(type = nil)
209
165
  case type
210
166
  when :blocked
@@ -214,18 +170,6 @@ module Capybara::Apparition
214
170
  end
215
171
  end
216
172
 
217
- def clear_network_traffic
218
- current_page.clear_network_traffic
219
- end
220
-
221
- def set_proxy(ip, port, type, user, password)
222
- args = [ip, port, type]
223
- args << user if user
224
- args << password if password
225
- # TODO: Implement via CDP if possible
226
- # command('set_proxy', *args)
227
- end
228
-
229
173
  def headers
230
174
  current_page.extra_headers
231
175
  end
@@ -260,10 +204,6 @@ module Capybara::Apparition
260
204
  end
261
205
  end
262
206
 
263
- def response_headers
264
- current_page.response_headers
265
- end
266
-
267
207
  def cookies
268
208
  current_page.command('Network.getCookies')['cookies'].each_with_object({}) do |c, h|
269
209
  h[c['name']] = Cookie.new(c)
@@ -343,18 +283,6 @@ module Capybara::Apparition
343
283
  raise
344
284
  end
345
285
 
346
- def go_back
347
- current_page.go_back
348
- end
349
-
350
- def go_forward
351
- current_page.go_forward
352
- end
353
-
354
- def refresh
355
- current_page.refresh
356
- end
357
-
358
286
  def accept_alert
359
287
  current_page.add_modal(alert: true)
360
288
  end
@@ -383,6 +311,10 @@ module Capybara::Apparition
383
311
  current_target.page
384
312
  end
385
313
 
314
+ def console_messages
315
+ console.messages
316
+ end
317
+
386
318
  private
387
319
 
388
320
  def current_target
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara::Apparition
4
+ class Console
5
+ def initialize(logger = nil)
6
+ @logger = logger
7
+ @messages = []
8
+ end
9
+
10
+ def log(type, message)
11
+ @messages << OpenStruct.new(type: type, message: message)
12
+ @logger&.puts message
13
+ end
14
+
15
+ def clear
16
+ @messages.clear
17
+ end
18
+
19
+ def messages
20
+ @messages
21
+ end
22
+ end
23
+ end
@@ -47,5 +47,10 @@ module Capybara::Apparition
47
47
  def expires
48
48
  Time.at @attributes['expires'] unless [nil, 0, -1].include? @attributes['expires']
49
49
  end
50
+
51
+ def ==(value)
52
+ return super unless value.is_a? String
53
+ self.value == value
54
+ end
50
55
  end
51
56
  end
@@ -22,7 +22,8 @@ module Capybara::Apparition
22
22
  headers headers= add_headers
23
23
  cookies remove_cookie clear_cookies cookies_enabled=
24
24
  clear_memory_cache
25
- go_back go_forward refresh] => :browser
25
+ go_back go_forward refresh
26
+ console_messages] => :browser
26
27
 
27
28
  def initialize(app, options = {})
28
29
  @app = app
@@ -37,9 +38,9 @@ module Capybara::Apparition
37
38
  true
38
39
  end
39
40
 
40
- def chrome_url
41
- 'ws://localhost:9223'
42
- end
41
+ # def chrome_url
42
+ # 'ws://localhost:9223'
43
+ # end
43
44
 
44
45
  def browser
45
46
  @browser ||= begin
@@ -64,6 +65,7 @@ module Capybara::Apparition
64
65
  browser_options['remote-debugging-port'] = options[:port] || 0
65
66
  browser_options['remote-debugging-address'] = options[:host] if options[:host]
66
67
  browser_options['window-size'] = options[:window_size].join(',') if options[:window_size]
68
+ browser_options.merge! @options[:browser] if @options[:browser]
67
69
  @launcher ||= Browser::Launcher.start(
68
70
  headless: options[:headless] != false,
69
71
  browser: browser_options
@@ -194,13 +196,19 @@ module Capybara::Apparition
194
196
  end
195
197
  end
196
198
 
197
- def set_proxy(ip, port, type = 'http', user = nil, password = nil)
198
- browser.set_proxy(ip, port, type, user, password)
199
+ def set_proxy(host, port, type = nil, user = nil, password = nil, bypass: [])
200
+ # TODO: Look at implementing via the CDP Fetch domain
201
+ raise ArgumentError, "Proxy auth is not yet implented" if user || password
202
+ @options[:browser] ||= {}
203
+ @options[:browser].merge!("proxy-server" => "#{type+"=" if type}#{host}:#{port}")
204
+ bypass = Array(bypass).join(';')
205
+ @options[:browser].merge!("proxy-bypass-list" => bypass) unless bypass.empty?
199
206
  end
200
207
 
201
208
  def add_header(name, value, options = {})
202
209
  browser.add_header({ name => value }, { permanent: true }.merge(options))
203
210
  end
211
+ alias_method :header, :add_header
204
212
 
205
213
  def response_headers
206
214
  browser.response_headers.each_with_object({}) do |(key, value), hsh|
@@ -208,7 +216,9 @@ module Capybara::Apparition
208
216
  end
209
217
  end
210
218
 
211
- def set_cookie(name, value, options = {})
219
+ def set_cookie(name, value=nil, options = {})
220
+ name, value, options = parse_raw_cookie(name) if value.nil?
221
+
212
222
  options[:name] ||= name
213
223
  options[:value] ||= value
214
224
  options[:domain] ||= begin
@@ -227,6 +237,7 @@ module Capybara::Apparition
227
237
  # credentials = ["#{user}:#{password}"].pack('m*').strip
228
238
  # add_header('Authorization', "Basic #{credentials}")
229
239
  end
240
+ alias_method :authenticate, :basic_authorize
230
241
 
231
242
  def debug
232
243
  if @options[:inspector]
@@ -324,8 +335,41 @@ module Capybara::Apparition
324
335
  client.timeout = sec
325
336
  end
326
337
 
338
+ def within_frame(frame_selector)
339
+ warn "Driver#within_frame is deprecated, please use Session#within_frame"
340
+
341
+ frame = case frame_selector
342
+ when Capybara::Apparition::Node
343
+ frame_selector
344
+ when Integer
345
+ find_css('iframe')[frame_selector]
346
+ when String
347
+ find_css("iframe[name='#{frame_selector}']")[0]
348
+ else
349
+ raise TypeError, 'Unknown frame selector'
350
+ command("FrameFocus")
351
+ end
352
+
353
+ switch_to_frame(frame)
354
+ begin
355
+ yield
356
+ ensure
357
+ switch_to_frame(:parent)
358
+ end
359
+ end
360
+
327
361
  private
328
362
 
363
+ def parse_raw_cookie(raw)
364
+ parts = raw.split(/;\s*/)
365
+ name, value = parts[0].split('=', 2)
366
+ options = parts[1..-1].each_with_object({}) do |part, opts|
367
+ name, value = part.split('=', 2)
368
+ opts[name.to_sym] = value
369
+ end
370
+ [name, value, options]
371
+ end
372
+
329
373
  def screen_size
330
374
  options[:screen_size] || [1366, 768]
331
375
  end
@@ -341,8 +385,9 @@ module Capybara::Apparition
341
385
  raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
342
386
  rescue Capybara::ModalNotFound => e
343
387
  if timer.expired?
344
- raise e, 'Unable to find modal dialog'\
345
- "#{" with #{expect_text}" if expect_text}"\
388
+ raise e, 'Timed out waiting for modal dialog. Unable to find modal dialog.' if !found_text
389
+ raise e, 'Unable to find modal dialog' \
390
+ "#{" with #{expect_text}" if expect_text}" \
346
391
  "#{", did find modal with #{found_text}" if found_text}"
347
392
  end
348
393
  sleep(0.05)
@@ -128,12 +128,14 @@ module Capybara
128
128
  'new element.'
129
129
  end
130
130
  end
131
+ NodeNotAttachedError = ObsoleteNode
131
132
 
132
133
  class WrongWorld < ObsoleteNode
133
134
  def message
134
135
  'The element you are trying to access is not from the current page'
135
136
  end
136
137
  end
138
+ NodeNotAttachedError = ObsoleteNode
137
139
 
138
140
  class UnsupportedFeature < ClientError
139
141
  def name
@@ -186,6 +186,7 @@ module Capybara::Apparition
186
186
  'abort': { 'keyCode': 3, 'code': 'Abort', 'key': 'Cancel' },
187
187
  'help': { 'keyCode': 6, 'code': 'Help', 'key': 'Help' },
188
188
  'backspace': { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
189
+ "\b": { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
189
190
  'tab': { 'keyCode': 9, 'code': 'Tab', 'key': 'Tab' },
190
191
  'enter': { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
191
192
  "\r": { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
@@ -64,6 +64,11 @@ module Capybara::Apparition
64
64
  .tr("\u00a0", ' ')
65
65
  end
66
66
 
67
+ def text # capybara-webkit method
68
+ warn "Node#text is deprecated, please use Node#visible_text instead"
69
+ visible_text
70
+ end
71
+
67
72
  def property(name)
68
73
  evaluate_on('function(name){ return this[name] }', value: name)
69
74
  end
@@ -161,8 +166,11 @@ module Capybara::Apparition
161
166
 
162
167
  @page.mouse.click_at pos.merge(button: button, count: count, modifiers: keys)
163
168
  if ENV['DEBUG']
164
- new_pos = element_click_pos(options)
165
- puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
169
+ begin
170
+ new_pos = element_click_pos(options)
171
+ puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
172
+ rescue WrongWorld
173
+ end
166
174
  end
167
175
  # Wait a short time to see if click triggers page load
168
176
  sleep 0.05
@@ -430,7 +438,11 @@ module Capybara::Apparition
430
438
  # Clear field by JavaScript assignment of the value property.
431
439
  # Script can change a readonly element which user input cannot, so
432
440
  # don't execute if readonly.
433
- driver.execute_script "arguments[0].value = ''", self unless clear == :none
441
+ driver.execute_script <<~JS, self unless clear == :none
442
+ if (!arguments[0].readOnly) {
443
+ arguments[0].value = ''
444
+ }
445
+ JS
434
446
  send_keys(value)
435
447
  end
436
448
  end
@@ -706,13 +718,7 @@ module Capybara::Apparition
706
718
  GET_VALUE_JS = <<~JS
707
719
  function(){
708
720
  if ((this.tagName == 'SELECT') && this.multiple){
709
- let selected = [];
710
- for (let option of this.children) {
711
- if (option.selected) {
712
- selected.push(option.value);
713
- }
714
- }
715
- return selected;
721
+ return Array.from(this.querySelectorAll("option:checked"),e=>e.value);
716
722
  } else {
717
723
  return this.value;
718
724
  }
@@ -339,8 +339,8 @@ module Capybara::Apparition
339
339
 
340
340
  def update_headers(async: false)
341
341
  method = async ? :async_command : :command
342
- if extra_headers['User-Agent']
343
- send(method, 'Network.setUserAgentOverride', userAgent: extra_headers['User-Agent'])
342
+ if (ua = extra_headers.find { |k, _v| k=~/^User-Agent$/i })
343
+ send(method, 'Network.setUserAgentOverride', userAgent: ua[1])
344
344
  end
345
345
  send(method, 'Network.setExtraHTTPHeaders', headers: extra_headers)
346
346
  setup_network_interception
@@ -526,9 +526,8 @@ module Capybara::Apparition
526
526
  end
527
527
 
528
528
  @session.on 'Runtime.consoleAPICalled' do |params|
529
- @browser.logger&.puts(
530
- "#{params['type']}: #{params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ')}"
531
- )
529
+ @browser.console.log(params['type'],
530
+ "#{params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ')}")
532
531
  end
533
532
 
534
533
  # @session.on 'Security.certificateError' do |params|
@@ -603,7 +602,9 @@ module Capybara::Apparition
603
602
  entry = history['entries'][history['currentIndex'] + delta]
604
603
  return nil unless entry
605
604
 
605
+ main_frame.loading(-1)
606
606
  command('Page.navigateToHistoryEntry', entryId: entry['id'])
607
+ wait_for_loaded
607
608
  end
608
609
 
609
610
  def _execute_script(script, *args)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.0.3'
5
+ VERSION = '0.0.4'
6
6
  end
7
7
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'backports/2.4.0/enumerable/sum'
4
+ require 'backports/2.4.0/string/match'
3
5
  require 'capybara'
4
6
 
5
7
  module Capybara
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apparition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-27 00:00:00.000000000 Z
11
+ date: 2019-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backports
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: capybara
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -197,6 +211,7 @@ files:
197
211
  - lib/capybara/apparition.rb
198
212
  - lib/capybara/apparition/browser.rb
199
213
  - lib/capybara/apparition/chrome_client.rb
214
+ - lib/capybara/apparition/console.rb
200
215
  - lib/capybara/apparition/cookie.rb
201
216
  - lib/capybara/apparition/dev_tools_protocol/session.rb
202
217
  - lib/capybara/apparition/dev_tools_protocol/target.rb
@@ -232,7 +247,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
232
247
  requirements:
233
248
  - - ">="
234
249
  - !ruby/object:Gem::Version
235
- version: 2.4.0
250
+ version: 2.3.0
236
251
  required_rubygems_version: !ruby/object:Gem::Requirement
237
252
  requirements:
238
253
  - - ">="