apparition 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2df57d16d5cfa6f966f3b8de2146a63ca23877e4dddc2f81a12170ae37f5ec5d
4
- data.tar.gz: b7b06eacc056f6b627b31ad091a7db9af5508b3f14ae69e7d9f1bedce6e8e63a
3
+ metadata.gz: 594a3f464bdb932d89f32f9bc0c3ce132ae5322c167e96016b0e66e292a8d71f
4
+ data.tar.gz: 4e2bf086855cb7aad5d38727efb96c9945f325e6c4b53f4ab17b4caa5a4caa35
5
5
  SHA512:
6
- metadata.gz: fd65552a378369a1d27852736c1cf2e1c51fb852a2c3e7c90b7c536f58608846bec86b471f009ef6eb9f9cbb803773d99c8af9b01575a0e5b2de953f1e0093f2
7
- data.tar.gz: 77f8e17427d5621179b1707182e6df8bf3fc2bc52cb9f5f25e42ed31c6db945bd28b00c8f20ea09c2cf55e76476cf0fe467fd0b5aa8eece8f13a08611d9408e5
6
+ metadata.gz: d4111cb452f2f30f69619bbdfe499b1a44aa00208e255264797440dfed1dd5c98c4045a31ebd6572b902bf16ed62c4873dbfc5229d5ec273296c7ba688cb4c70
7
+ data.tar.gz: 1c160f3115ec245d2ddb834053913627f1ed34fe681fd8cb892d0a2b9bcd1af7d61f673b392582c84d248d5341239b4b2343ee5eee14c357fd018396f6e919d8
data/README.md CHANGED
@@ -174,6 +174,7 @@ end
174
174
  * `:url_whitelist` (Array) - Default session url whitelist - expressed as an array of strings to match against requested URLs.
175
175
  * `:ignore_https_errors` (Boolean) - Ignore certificate errors when connecting to https URLs.
176
176
  * `:browser_options` (Hash) - Extra command line options to pass to Chrome when starting
177
+ * `:skip_image_loading` (Boolean) - Don't load images
177
178
 
178
179
  ### URL Blacklisting & Whitelisting ###
179
180
  Apparition supports URL blacklisting, which allows you
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara::Apparition
4
+ module DevToolsProtocol
5
+ class RemoteObject
6
+ attr_reader :params
7
+
8
+ def initialize(page, params)
9
+ @params = params
10
+ @page = page
11
+ end
12
+
13
+ def value
14
+ cyclic_checked_value({})
15
+ end
16
+
17
+ protected
18
+
19
+ def cyclic_checked_value(object_cache)
20
+ if object?
21
+ if array?
22
+ extract_properties_array(get_remote_object(object_id), object_cache)
23
+ elsif node?
24
+ params
25
+ elsif object_class?
26
+ extract_properties_object(get_remote_object(object_id), object_cache)
27
+ elsif window_class?
28
+ { object_id: object_id }
29
+ else
30
+ params['value']
31
+ end
32
+ else
33
+ params['value']
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def object?; type == 'object' end
40
+ def array?; subtype == 'array' end
41
+ def node?; subtype == 'node' end
42
+ def object_class?; classname == 'Object' end
43
+ def window_class?; classname == 'Window' end
44
+
45
+ def type; params['type'] end
46
+ def subtype; params['subtype'] end
47
+ def object_id; params['objectId'] end
48
+ def classname; params['className'] end
49
+
50
+ def extract_properties_array(properties, object_cache)
51
+ properties.reject { |prop| prop['name'] == 'apparitionId' }
52
+ .each_with_object([]) do |property, ary|
53
+ # TODO: We may need to release these objects
54
+ next unless property['enumerable']
55
+
56
+ if property.dig('value', 'subtype') == 'node' # performance shortcut
57
+ ary.push(property['value'])
58
+ else
59
+ ary.push(RemoteObject.new(@page, property['value']).cyclic_checked_value(object_cache))
60
+ end
61
+ end
62
+ end
63
+
64
+ def extract_properties_object(properties, object_cache)
65
+ apparition_id = properties&.find { |prop| prop['name'] == 'apparitionId' }
66
+ &.dig('value', 'value')
67
+
68
+ result = if apparition_id
69
+ return '(cyclic structure)' if object_cache.key?(apparition_id)
70
+
71
+ object_cache[apparition_id] = {}
72
+ end
73
+
74
+ properties.reject { |prop| prop['name'] == 'apparitionId' }
75
+ .each_with_object(result || {}) do |property, hsh|
76
+ # TODO: We may need to release these objects
77
+ next unless property['enumerable']
78
+
79
+ hsh[property['name']] = RemoteObject.new(@page, property['value']).cyclic_checked_value(object_cache)
80
+ end
81
+ end
82
+
83
+ def get_remote_object(id)
84
+ @page.command('Runtime.getProperties', objectId: id, ownProperties: true)['result']
85
+ end
86
+ end
87
+ end
88
+ end
@@ -28,6 +28,7 @@ module Capybara::Apparition
28
28
  def initialize(app, options = {})
29
29
  @app = app
30
30
  @options = options
31
+ generate_browser_options
31
32
  @browser = nil
32
33
  @inspector = nil
33
34
  @client = nil
@@ -45,10 +46,10 @@ module Capybara::Apparition
45
46
  def browser
46
47
  @browser ||= begin
47
48
  browser = Browser.new(client, browser_logger)
48
- browser.js_errors = options[:js_errors] if options.key?(:js_errors)
49
- browser.ignore_https_errors = options[:ignore_https_errors] if options.key?(:ignore_https_errors)
49
+ browser.js_errors = options.fetch(:js_errors, true)
50
+ browser.ignore_https_errors = options.fetch(:ignore_https_errors, false)
50
51
  browser.extensions = options.fetch(:extensions, [])
51
- browser.debug = true if options[:debug]
52
+ browser.debug = options.fetch(:debug, false)
52
53
  browser.url_blacklist = options[:url_blacklist] || []
53
54
  browser.url_whitelist = options[:url_whitelist] || []
54
55
  browser
@@ -61,33 +62,15 @@ module Capybara::Apparition
61
62
 
62
63
  def client
63
64
  @client ||= begin
64
- browser_options = {}
65
- browser_options['remote-debugging-port'] = options[:port] || 0
66
- browser_options['remote-debugging-address'] = options[:host] if options[:host]
67
- browser_options['window-size'] = options[:window_size].join(',') if options[:window_size]
68
- browser_options.merge! @options[:browser] if @options[:browser]
69
65
  @launcher ||= Browser::Launcher.start(
70
- headless: options[:headless] != false,
71
- browser: browser_options
66
+ headless: options.fetch(:headless, true),
67
+ browser_options: browser_options
72
68
  )
73
69
  ws_url = @launcher.ws_url
74
70
  ::Capybara::Apparition::ChromeClient.client(ws_url.to_s)
75
71
  end
76
72
  end
77
73
 
78
- def browser_options
79
- list = options[:browser_options] || []
80
- # TODO: configure SSL options
81
- # PhantomJS defaults to only using SSLv3, which since POODLE (Oct 2014)
82
- # many sites have dropped from their supported protocols (eg PayPal,
83
- # Braintree).
84
- # list += ["--ignore-ssl-errors=yes"] unless list.grep(/ignore-ssl-errors/).any?
85
- # list += ["--ssl-protocol=TLSv1"] unless list.grep(/ssl-protocol/).any?
86
- # list += ["--remote-debugger-port=#{inspector.port}", "--remote-debugger-autorun=yes"] if inspector
87
- # Note: Need to verify what Chrome command line options are valid for this
88
- list
89
- end
90
-
91
74
  def quit
92
75
  @client&.stop
93
76
  @launcher&.stop
@@ -205,10 +188,10 @@ module Capybara::Apparition
205
188
  end
206
189
 
207
190
  # TODO: Look at implementing via the CDP Fetch domain when available
208
- @options[:browser] ||= {}
209
- @options[:browser]['proxy-server'] = "#{type + '=' if type}#{host}:#{port}"
191
+ @options[:browser_options] ||= {}
192
+ @options[:browser_options]['proxy-server'] = "#{type + '=' if type}#{host}:#{port}"
210
193
  bypass = Array(bypass).join(';')
211
- @options[:browser]['proxy-bypass-list'] = bypass unless bypass.empty?
194
+ @options[:browser_options]['proxy-bypass-list'] = bypass unless bypass.empty?
212
195
  browser.set_proxy_auth(user, password) if user || password
213
196
  end
214
197
 
@@ -344,34 +327,56 @@ module Capybara::Apparition
344
327
  client.timeout = sec
345
328
  end
346
329
 
347
- def within_frame(frame_selector)
348
- warn 'Driver#within_frame is deprecated, please use Session#within_frame'
330
+ def error_messages
331
+ console_messages('error')
332
+ end
349
333
 
350
- frame = case frame_selector
351
- when Capybara::Apparition::Node
352
- frame_selector
353
- when Integer
354
- find_css('iframe')[frame_selector]
355
- when String
356
- find_css("iframe[name='#{frame_selector}']")[0]
357
- else
358
- raise TypeError, 'Unknown frame selector'
359
- # command('FrameFocus')
360
- end
334
+ private
361
335
 
362
- switch_to_frame(frame)
363
- begin
364
- yield
365
- ensure
366
- switch_to_frame(:parent)
367
- end
336
+ def browser_options
337
+ @options[:browser_options]
368
338
  end
369
339
 
370
- def error_messages
371
- console_messages('error')
340
+ def generate_browser_options
341
+ # TODO: configure SSL options
342
+ # PhantomJS defaults to only using SSLv3, which since POODLE (Oct 2014)
343
+ # many sites have dropped from their supported protocols (eg PayPal,
344
+ # Braintree).
345
+ # list += ["--ignore-ssl-errors=yes"] unless list.grep(/ignore-ssl-errors/).any?
346
+ # list += ["--ssl-protocol=TLSv1"] unless list.grep(/ssl-protocol/).any?
347
+ # list += ["--remote-debugger-port=#{inspector.port}", "--remote-debugger-autorun=yes"] if inspector
348
+ # Note: Need to verify what Chrome command line options are valid for this
349
+ browser_options = {}
350
+ browser_options['remote-debugging-port'] = @options[:port] || 0
351
+ browser_options['remote-debugging-address'] = @options[:host] if @options[:host]
352
+ browser_options['window-size'] = @options[:window_size].join(',') if @options[:window_size]
353
+ if @options[:browser]
354
+ warn ':browser is deprecated, please pass as :browser_options instead.'
355
+ browser_options.merge! process_browser_options(@options[:browser])
356
+ end
357
+ browser_options.merge! process_browser_options(@options[:browser_options]) if @options[:browser_options]
358
+ if @options[:skip_image_loading]
359
+ browser_options['blink-settings'] = [browser_options['blink-settings'], 'imagesEnabled=false'].compact.join(',')
360
+ end
361
+ @options[:browser_options] = browser_options
372
362
  end
373
363
 
374
- private
364
+ def process_browser_options(options)
365
+ case options
366
+ when Array
367
+ options.compact.each_with_object({}) do |option, hsh|
368
+ if option.is_a? Hash
369
+ hsh.merge! process_browser_options(option)
370
+ else
371
+ hsh[option.to_s.tr('_', '-')] = nil
372
+ end
373
+ end
374
+ when Hash
375
+ options.each_with_object({}) { |(option, val), hsh| hsh[option.to_s.tr('_', '-')] = val }
376
+ else
377
+ raise ArgumentError, 'browser_options must be an Array or a Hash'
378
+ end
379
+ end
375
380
 
376
381
  def parse_raw_cookie(raw)
377
382
  parts = raw.split(/;\s*/)
@@ -5,49 +5,6 @@ module Capybara::Apparition
5
5
  class Launcher
6
6
  KILL_TIMEOUT = 2
7
7
 
8
- # Chromium command line options
9
- # https://peter.sh/experiments/chromium-command-line-switches/
10
- DEFAULT_BOOLEAN_OPTIONS = %w[
11
- disable-background-networking
12
- disable-background-timer-throttling
13
- disable-breakpad
14
- disable-client-side-phishing-detection
15
- disable-default-apps
16
- disable-dev-shm-usage
17
- disable-extensions
18
- disable-features=site-per-process
19
- disable-hang-monitor
20
- disable-infobars
21
- disable-popup-blocking
22
- disable-prompt-on-repost
23
- disable-sync
24
- disable-translate
25
- metrics-recording-only
26
- no-first-run
27
- safebrowsing-disable-auto-update
28
- enable-automation
29
- password-store=basic
30
- use-mock-keychain
31
- keep-alive-for-test
32
- ].freeze
33
- # Note: --no-sandbox is not needed if you properly setup a user in the container.
34
- # https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile#L35-L40
35
- # no-sandbox
36
- # disable-web-security
37
- DEFAULT_VALUE_OPTIONS = {
38
- 'window-size' => '1024,768',
39
- 'homepage' => 'about:blank',
40
- 'remote-debugging-address' => '127.0.0.1'
41
- }.freeze
42
- DEFAULT_OPTIONS = DEFAULT_BOOLEAN_OPTIONS.each_with_object({}) { |opt, hsh| hsh[opt] = nil }
43
- .merge(DEFAULT_VALUE_OPTIONS)
44
- .freeze
45
- HEADLESS_OPTIONS = {
46
- 'headless' => nil,
47
- 'hide-scrollbars' => nil,
48
- 'mute-audio' => nil
49
- }.freeze
50
-
51
8
  def self.start(*args)
52
9
  new(*args).tap(&:start)
53
10
  end
@@ -76,7 +33,7 @@ module Capybara::Apparition
76
33
 
77
34
  def initialize(headless:, **options)
78
35
  @path = ENV['BROWSER_PATH']
79
- @options = DEFAULT_OPTIONS.merge(options.fetch(:browser, {}))
36
+ @options = DEFAULT_OPTIONS.merge(options[:browser_options] || {})
80
37
  if headless
81
38
  @options.merge!(HEADLESS_OPTIONS)
82
39
  @options['disable-gpu'] = nil if Capybara::Apparition.windows?
@@ -212,6 +169,49 @@ module Capybara::Apparition
212
169
  end
213
170
  end
214
171
  end
172
+
173
+ # Chromium command line options
174
+ # https://peter.sh/experiments/chromium-command-line-switches/
175
+ DEFAULT_BOOLEAN_OPTIONS = %w[
176
+ disable-background-networking
177
+ disable-background-timer-throttling
178
+ disable-breakpad
179
+ disable-client-side-phishing-detection
180
+ disable-default-apps
181
+ disable-dev-shm-usage
182
+ disable-extensions
183
+ disable-features=site-per-process
184
+ disable-hang-monitor
185
+ disable-infobars
186
+ disable-popup-blocking
187
+ disable-prompt-on-repost
188
+ disable-sync
189
+ disable-translate
190
+ metrics-recording-only
191
+ no-first-run
192
+ safebrowsing-disable-auto-update
193
+ enable-automation
194
+ password-store=basic
195
+ use-mock-keychain
196
+ keep-alive-for-test
197
+ ].freeze
198
+ # Note: --no-sandbox is not needed if you properly setup a user in the container.
199
+ # https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile#L35-L40
200
+ # no-sandbox
201
+ # disable-web-security
202
+ DEFAULT_VALUE_OPTIONS = {
203
+ 'window-size' => '1024,768',
204
+ 'homepage' => 'about:blank',
205
+ 'remote-debugging-address' => '127.0.0.1'
206
+ }.freeze
207
+ DEFAULT_OPTIONS = DEFAULT_BOOLEAN_OPTIONS.each_with_object({}) { |opt, hsh| hsh[opt] = nil }
208
+ .merge(DEFAULT_VALUE_OPTIONS)
209
+ .freeze
210
+ HEADLESS_OPTIONS = {
211
+ 'headless' => nil,
212
+ 'hide-scrollbars' => nil,
213
+ 'mute-audio' => nil
214
+ }.freeze
215
215
  end
216
216
  end
217
217
  end
@@ -228,5 +228,8 @@ module Capybara
228
228
  "Chrome client died while processing #{@message}"
229
229
  end
230
230
  end
231
+
232
+ class InvalidResponseError < StandardError
233
+ end
231
234
  end
232
235
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ostruct'
4
+ require 'capybara/apparition/dev_tools_protocol/remote_object'
4
5
  require 'capybara/apparition/node/drag'
5
6
 
6
7
  module Capybara::Apparition
@@ -345,7 +346,6 @@ module Capybara::Apparition
345
346
  end
346
347
 
347
348
  def scroll_to(element, location, position = nil)
348
- # location, element = element, nil if element.is_a? Symbol
349
349
  if element.is_a? Capybara::Apparition::Node
350
350
  scroll_element_to_location(element, location)
351
351
  elsif location.is_a? Symbol
@@ -407,39 +407,13 @@ module Capybara::Apparition
407
407
  raise exception_details
408
408
  end
409
409
 
410
- result = response['result'] || response ['object']
411
- if result['type'] == 'object'
412
- if result['subtype'] == 'array'
413
- remote_object = @page.command('Runtime.getProperties',
414
- objectId: result['objectId'],
415
- ownProperties: true)
416
-
417
- return extract_properties_array(remote_object['result'])
418
- elsif result['subtype'] == 'node'
419
- return result
420
- elsif result['className'] == 'Object'
421
- remote_object = @page.command('Runtime.getProperties',
422
- objectId: result['objectId'],
423
- ownProperties: true)
424
- extract_properties_object(remote_object['result'])
425
- else
426
- result['value']
427
- end
428
- else
429
- result['value']
430
- end
410
+ DevToolsProtocol::RemoteObject.new(@page, response['result'] || response['object']).value
431
411
  end
432
412
 
433
413
  def set_text(value, clear: nil, **_unused)
434
414
  value = value.to_s
435
415
  if value.empty? && clear.nil?
436
- evaluate_on <<~JS
437
- () => {
438
- this.focus();
439
- this.value = '';
440
- this.dispatchEvent(new Event('change', { bubbles: true }));
441
- }
442
- JS
416
+ evaluate_on CLEAR_ELEMENT_JS
443
417
  elsif clear == :backspace
444
418
  # Clear field by sending the correct number of backspace keys.
445
419
  backspaces = [:backspace] * self.value.to_s.length
@@ -460,9 +434,7 @@ module Capybara::Apparition
460
434
  end
461
435
 
462
436
  def set_files(files)
463
- @page.command('DOM.setFileInputFiles',
464
- files: Array(files),
465
- objectId: id)
437
+ @page.command('DOM.setFileInputFiles', files: Array(files), objectId: id)
466
438
  end
467
439
 
468
440
  def set_date(value)
@@ -597,36 +569,6 @@ module Capybara::Apparition
597
569
  end
598
570
  private_constant :SettableValue
599
571
 
600
- def extract_properties_array(properties)
601
- properties.each_with_object([]) do |property, results|
602
- if property['enumerable']
603
- if property.dig('value', 'subtype') == 'node'
604
- results.push(property['value'])
605
- else
606
- # releasePromises.push(helper.releaseObject(@element._client, property.value))
607
- results.push(property.dig('value', 'value'))
608
- end
609
- end
610
- # await Promise.all(releasePromises);
611
- # id = (@page._elements.push(element)-1 for element from result)[0]
612
- #
613
- # new Apparition.Node @page, id
614
-
615
- # releasePromises = [helper.releaseObject(@element._client, remote_object)]
616
- end
617
- end
618
-
619
- def extract_properties_object(properties)
620
- properties.each_with_object({}) do |property, object|
621
- if property['enumerable']
622
- object[property['name']] = property['value']['value']
623
- else # rubocop:disable Style/EmptyElse
624
- # releasePromises.push(helper.releaseObject(@element._client, property.value))
625
- end
626
- # releasePromises = [helper.releaseObject(@element._client, remote_object)]
627
- end
628
- end
629
-
630
572
  ####################
631
573
  # JS snippets
632
574
  ####################
@@ -821,5 +763,13 @@ module Capybara::Apparition
821
763
  }, {})
822
764
  }
823
765
  JS
766
+
767
+ CLEAR_ELEMENT_JS = <<~JS
768
+ () => {
769
+ this.focus();
770
+ this.value = '';
771
+ this.dispatchEvent(new Event('change', { bubbles: true }));
772
+ }
773
+ JS
824
774
  end
825
775
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'capybara/apparition/dev_tools_protocol/remote_object'
3
4
  require 'capybara/apparition/page/frame_manager'
4
5
  require 'capybara/apparition/page/mouse'
5
6
  require 'capybara/apparition/page/keyboard'
@@ -194,42 +195,16 @@ module Capybara::Apparition
194
195
  end
195
196
 
196
197
  def execute(script, *args)
197
- wait_for_loaded
198
- _execute_script <<~JS, *args
199
- function(){
200
- #{script}
201
- }
202
- JS
198
+ eval_wrapped_script(EXECUTE_JS, script, args)
203
199
  nil
204
200
  end
205
201
 
206
202
  def evaluate(script, *args)
207
- wait_for_loaded
208
- _execute_script <<~JS, *args
209
- function(){
210
- let apparitionId=0;
211
- return (function ider(obj){
212
- if (obj && (typeof obj == 'object') && !obj.apparitionId){
213
- obj.apparitionId = ++apparitionId;
214
- Reflect.ownKeys(obj).forEach(key => ider(obj[key]))
215
- }
216
- return obj;
217
- })((function(){ return #{script} }).apply(this, arguments))
218
- }
219
- JS
203
+ eval_wrapped_script(EVALUATE_WITH_ID_JS, script, args)
220
204
  end
221
205
 
222
206
  def evaluate_async(script, _wait_time, *args)
223
- wait_for_loaded
224
- _execute_script <<~JS, *args
225
- function(){
226
- var args = Array.prototype.slice.call(arguments);
227
- return new Promise((resolve, reject)=>{
228
- args.push(resolve);
229
- (function(){ #{script} }).apply(this, args);
230
- });
231
- }
232
- JS
207
+ eval_wrapped_script(EVALUATE_ASYNC_JS, script, args)
233
208
  end
234
209
 
235
210
  def refresh
@@ -403,6 +378,11 @@ module Capybara::Apparition
403
378
 
404
379
  private
405
380
 
381
+ def eval_wrapped_script(wrapper, script, args)
382
+ wait_for_loaded
383
+ _execute_script format(wrapper, script: script), *args
384
+ end
385
+
406
386
  def frame_offset(frame)
407
387
  return { x: 0, y: 0 } if frame.id == main_frame.id
408
388
 
@@ -716,8 +696,7 @@ module Capybara::Apparition
716
696
  end
717
697
  end
718
698
 
719
- result = response['result']
720
- decode_result(result)
699
+ DevToolsProtocol::RemoteObject.new(self, response['result']).value
721
700
  end
722
701
 
723
702
  def manual_unexpected_modal(type)
@@ -767,72 +746,34 @@ module Capybara::Apparition
767
746
  continue_request(interception_id, authChallengeResponse: credentials_response)
768
747
  end
769
748
 
770
- def decode_result(result, object_cache = {})
771
- if result['type'] == 'object'
772
- if result['subtype'] == 'array'
773
- remote_object = command('Runtime.getProperties',
774
- objectId: result['objectId'],
775
- ownProperties: true)
776
-
777
- properties = remote_object['result'].reject { |prop| prop['name'] == 'apparitionId' }
778
- results = []
779
-
780
- properties.each do |property|
781
- next unless property['enumerable']
749
+ EVALUATE_WITH_ID_JS = <<~JS
750
+ function(){
751
+ let apparitionId=0;
752
+ return (function ider(obj){
753
+ if (obj && (typeof obj == 'object') && !(obj instanceof HTMLElement) && !obj.apparitionId){
754
+ obj.apparitionId = ++apparitionId;
755
+ Reflect.ownKeys(obj).forEach(key => ider(obj[key]))
756
+ }
757
+ return obj;
758
+ })((function(){ return %<script>s }).apply(this, arguments))
759
+ }
760
+ JS
782
761
 
783
- val = property['value']
784
- results.push(decode_result(val, object_cache))
785
- # TODO: Do we need to cleanup these resources?
786
- # await Promise.all(releasePromises);
787
- # id = (@page._elements.push(element)-1 for element from result)[0]
788
- #
789
- # new Apparition.Node @page, id
762
+ EVALUATE_ASYNC_JS = <<~JS
763
+ function(){
764
+ var args = Array.prototype.slice.call(arguments);
765
+ return new Promise((resolve, reject)=>{
766
+ args.push(resolve);
767
+ (function(){ %<script>s }).apply(this, args);
768
+ });
769
+ }
770
+ JS
790
771
 
791
- # releasePromises = [helper.releaseObject(@element._client, remoteObject)]
792
- end
793
- command('Runtime.releaseObject', objectId: result['objectId'])
794
- return results
795
- elsif result['subtype'] == 'node'
796
- return result
797
- elsif result['className'] == 'Object'
798
- remote_object = command('Runtime.getProperties',
799
- objectId: result['objectId'],
800
- ownProperties: true)
801
-
802
- # stable_id went away in Chrome 72 - we add our own id in evaluate
803
- # stable_id = remote_object['internalProperties']
804
- # &.find { |prop| prop['name'] == '[[StableObjectId]]' }
805
- # &.dig('value', 'value')
806
-
807
- # We could actually return cyclic objects here but Capybara would need to be updated to support
808
- # return object_cache[stable_id] if object_cache.key?(stable_id) # and update the cache to be a hash
809
-
810
- stable_id = remote_object['result']
811
- &.find { |prop| prop['name'] == 'apparitionId'}
812
- &.dig('value', 'value')
813
- return '(cyclic structure)' if object_cache.key?(stable_id)
814
-
815
- object_cache[stable_id] = {}
816
- properties = remote_object['result'].reject { |prop| prop['name'] == "apparitionId"}
817
-
818
- return properties.each_with_object(object_cache[stable_id]) do |property, memo|
819
- if property['enumerable']
820
- memo[property['name']] = decode_result(property['value'], object_cache)
821
- else # rubocop:disable Style/EmptyElse
822
- # TODO: Do we need to cleanup these resources?
823
- # releasePromises.push(helper.releaseObject(@element._client, property.value))
824
- end
825
- # TODO: Do we need to cleanup these resources?
826
- # releasePromises = [helper.releaseObject(@element._client, remote_object)]
827
- end
828
- elsif result['className'] == 'Window'
829
- return { object_id: result['objectId'] }
830
- end
831
- nil
832
- else
833
- result['value']
834
- end
835
- end
772
+ EXECUTE_JS = <<~JS
773
+ function(){
774
+ %<script>s
775
+ }
776
+ JS
836
777
 
837
778
  CSS_FIND_JS = <<~JS
838
779
  Array.from(document.querySelectorAll("%s"));
@@ -12,7 +12,7 @@ module Capybara::Apparition
12
12
  move_to x: x, y: y
13
13
  count.times do |num|
14
14
  @keyboard.with_keys(modifiers) do
15
- mouse_params = { x: x, y: y, button: button, count: num+1 }
15
+ mouse_params = { x: x, y: y, button: button, count: num + 1 }
16
16
  down mouse_params
17
17
  up mouse_params
18
18
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.0.5'
5
+ VERSION = '0.0.6'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apparition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
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-30 00:00:00.000000000 Z
11
+ date: 2019-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backports
@@ -227,6 +227,7 @@ files:
227
227
  - lib/capybara/apparition/console.rb
228
228
  - lib/capybara/apparition/cookie.rb
229
229
  - lib/capybara/apparition/cookie_jar.rb
230
+ - lib/capybara/apparition/dev_tools_protocol/remote_object.rb
230
231
  - lib/capybara/apparition/dev_tools_protocol/session.rb
231
232
  - lib/capybara/apparition/dev_tools_protocol/target.rb
232
233
  - lib/capybara/apparition/dev_tools_protocol/target_manager.rb