apparition 0.0.5 → 0.0.6

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: 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