apparition 0.0.2 → 0.0.3

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: 9e8fee05c8a55aecbed96ec2f5f1c7d36ffdea00488281be36fe4e6ac85ab9a4
4
- data.tar.gz: 781e519f382127f2dfd6be4bda8a0b674d185bfdc8d1072962c5136cae773a1c
3
+ metadata.gz: e4f76aefa6b5bebbab16d325e6f434846c2a426b74df9b8c0248465653124202
4
+ data.tar.gz: e9538e39a9c912471527fc456e801f0b3cc261bf042ddc82177d0e74e0769a33
5
5
  SHA512:
6
- metadata.gz: 96e43542fe127e373cb1f5167c4023922e4a0428b11fa11c13797e1dec0f304fad8ae6422e1c887891317d064905a1a54174c4696d989ad2741a18e6c278e901
7
- data.tar.gz: 2667120038d46b9fc874f8009c9820fc6fee86e6a02e753ffcbd16c60398928bb1f1b8ad2cdbf2640d883de94920e2d569e6e127b433866c39809cc712cb34bd
6
+ metadata.gz: 9f187d2d4b1185e2fe5460adf9435daec58d008789e69bca907df06bdc20f59b1b8808ac4f346ef1c7d00d4caa62a6fe7aaf033a9e3287299a007e8c9c7493fb
7
+ data.tar.gz: 443d5076e6b92f8c051a261663a8dc93a3ae2b0a75d87943579b762927b0f8d4e42a527b3c047c4ae937bf001198f7e14ebd8f4ea77de7ffd1ec04d4e096ad65
@@ -133,7 +133,9 @@ module Capybara::Apparition
133
133
 
134
134
  def close_window(handle)
135
135
  @current_page_handle = nil if @current_page_handle == handle
136
- @targets.delete(handle).close
136
+ win_target = @targets.delete(handle)
137
+ warn "Window was already closed unexpectedly" if win_target.nil?
138
+ win_target&.close
137
139
  end
138
140
 
139
141
  def within_window(locator)
@@ -286,7 +286,7 @@ module Capybara::Apparition
286
286
  end
287
287
 
288
288
  def invalid_element_errors
289
- [Capybara::Apparition::ObsoleteNode, Capybara::Apparition::MouseEventFailed]
289
+ [Capybara::Apparition::ObsoleteNode, Capybara::Apparition::MouseEventFailed, Capybara::Apparition::WrongWorld]
290
290
  end
291
291
 
292
292
  def accept_modal(type, options = {})
@@ -172,6 +172,7 @@ module Capybara
172
172
  'It may be overlapping the element you are trying to interact with. '
173
173
  end
174
174
  end
175
+ ClickFailed = MouseEventFailed
175
176
 
176
177
  class MouseEventImpossible < MouseEventFailed
177
178
  def name
@@ -7,7 +7,7 @@ module Capybara::Apparition
7
7
  DEFAULT_PORT = 9664
8
8
 
9
9
  def self.detect_browser
10
- @browser ||= BROWSERS.find { |name| browser_binary_exists?(name) }
10
+ @browser ||= BROWSERS.find { |name| browser_binary_exists?(name) } # rubocop:disable Naming/MemoizedInstanceVariableName
11
11
  end
12
12
 
13
13
  attr_reader :port
@@ -44,7 +44,7 @@ module Capybara::Apparition
44
44
  def html5_drag_to(element)
45
45
  driver.execute_script MOUSEDOWN_TRACKER
46
46
  scroll_if_needed
47
- @page.mouse.move_to(element.visible_center).down
47
+ @page.mouse.move_to(visible_center).down
48
48
  if driver.evaluate_script('window.capybara_mousedown_prevented')
49
49
  element.scroll_if_needed
50
50
  @page.mouse.move_to(element.visible_center).up
@@ -79,16 +79,7 @@ module Capybara::Apparition
79
79
  def [](name)
80
80
  # Although the attribute matters, the property is consistent. Return that in
81
81
  # preference to the attribute for links and images.
82
- return evaluate_on ELEMENT_PROP_OR_ATTR_JS, value: name
83
- # if ((tag_name == 'img') && (name == 'src')) || ((tag_name == 'a') && (name == 'href'))
84
- # # if attribute exists get the property
85
- # return attribute(name) && property(name)
86
- # end
87
- #
88
- # value = property(name)
89
- # value = attribute(name) if value.nil? || value.is_a?(Hash)
90
- #
91
- # value
82
+ evaluate_on ELEMENT_PROP_OR_ATTR_JS, value: name
92
83
  end
93
84
 
94
85
  def attributes
@@ -165,6 +156,7 @@ module Capybara::Apparition
165
156
  raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['click']) if pos.nil?
166
157
 
167
158
  test = mouse_event_test(pos)
159
+ raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['click']) if test.nil?
168
160
  raise ::Capybara::Apparition::MouseEventFailed.new(self, 'args' => ['click', test.selector, pos]) unless test.success
169
161
 
170
162
  @page.mouse.click_at pos.merge(button: button, count: count, modifiers: keys)
@@ -248,7 +240,9 @@ module Capybara::Apparition
248
240
 
249
241
  frame_offset = @page.current_frame_offset
250
242
 
251
- if (rect['width'].zero? || rect['height'].zero?) && (tag_name == 'area')
243
+ if rect['width'].zero? || rect['height'].zero?
244
+ return nil unless tag_name == 'area'
245
+
252
246
  map = find('xpath', 'ancestor::map').first
253
247
  img = find('xpath', "//img[@usemap='##{map[:name]}']").first
254
248
  return nil unless img.visible?
@@ -280,7 +274,9 @@ module Capybara::Apparition
280
274
 
281
275
  frame_offset = @page.current_frame_offset
282
276
 
283
- if (rect['width'].zero? || rect['height'].zero?) && (tag_name == 'area')
277
+ if rect['width'].zero? || rect['height'].zero?
278
+ return nil unless tag_name == 'area'
279
+
284
280
  map = find('xpath', 'ancestor::map').first
285
281
  img = find('xpath', "//img[@usemap='##{map[:name]}']").first
286
282
  return nil unless img.visible?
@@ -489,37 +485,54 @@ module Capybara::Apparition
489
485
  end
490
486
 
491
487
  def mouse_event_test(x:, y:)
492
- frame_offset = @page.current_frame_offset
493
- # return { status: 'failure' } if x < 0 || y < 0
494
- result = evaluate_on(<<~JS, { value: x - frame_offset[:x] }, value: y - frame_offset[:y])
495
- function(x,y){
496
- const hit_node = document.elementFromPoint(x,y);
497
- if ((hit_node == this) || this.contains(hit_node))
498
- return { status: 'success' };
499
-
500
- const getSelector = function(element){
501
- if (element == null)
502
- return 'Element out of bounds';
503
-
504
- let selector = '';
505
- if (element.tagName != 'HTML')
506
- selector = getSelector(element.parentNode) + ' ';
507
- selector += element.tagName.toLowerCase();
508
- if (element.id)
509
- selector += `#${element.id}`;
510
-
511
- for (let className of element.classList){
512
- if (className != '')
513
- selector += `.${className}`;
514
- }
515
- return selector;
488
+ r_o = @page.element_from_point(x: x, y: y)
489
+ return nil unless r_o && r_o['objectId']
490
+
491
+ hit_node = Capybara::Apparition::Node.new(driver, @page, r_o['objectId'])
492
+ result = begin
493
+ evaluate_on(<<~JS, objectId: hit_node.id)
494
+ function(hit_node){
495
+ if ((hit_node == this) || this.contains(hit_node))
496
+ return { status: 'success' };
497
+ return { status: 'failure' };
516
498
  }
517
-
518
- return { status: 'failure', selector: getSelector(hit_node) };
519
- }
520
- JS
521
-
522
- OpenStruct.new(success: result['status'] == 'success', selector: result['selector'])
499
+ JS
500
+ rescue WrongWorld
501
+ { 'status': 'failure' }
502
+ end
503
+ OpenStruct.new(success: result['status'] == 'success', selector: r_o['description'])
504
+
505
+ # frame_offset = @page.current_frame_offset
506
+ # # return { status: 'failure' } if x < 0 || y < 0
507
+ # result = evaluate_on(<<~JS, { value: x - frame_offset[:x] }, value: y - frame_offset[:y])
508
+ # function(x,y){
509
+ # const hit_node = document.elementFromPoint(x,y);
510
+ # if ((hit_node == this) || this.contains(hit_node))
511
+ # return { status: 'success' };
512
+ #
513
+ # const getSelector = function(element){
514
+ # if (element == null)
515
+ # return 'Element out of bounds';
516
+ #
517
+ # let selector = '';
518
+ # if (element.tagName != 'HTML')
519
+ # selector = getSelector(element.parentNode) + ' ';
520
+ # selector += element.tagName.toLowerCase();
521
+ # if (element.id)
522
+ # selector += `#${element.id}`;
523
+ #
524
+ # for (let className of element.classList){
525
+ # if (className != '')
526
+ # selector += `.${className}`;
527
+ # }
528
+ # return selector;
529
+ # }
530
+ #
531
+ # return { status: 'failure', selector: getSelector(hit_node) };
532
+ # }
533
+ # JS
534
+ #
535
+ # OpenStruct.new(success: result['status'] == 'success', selector: result['selector'])
523
536
  end
524
537
 
525
538
  def scroll_element_to_location(element, location)
@@ -615,7 +628,7 @@ module Capybara::Apparition
615
628
  properties.each_with_object({}) do |property, object|
616
629
  if property['enumerable']
617
630
  object[property['name']] = property['value']['value']
618
- else
631
+ else # rubocop:disable Style/EmptyElse
619
632
  # releasePromises.push(helper.releaseObject(@element._client, property.value))
620
633
  end
621
634
  # releasePromises = [helper.releaseObject(@element._client, remote_object)]
@@ -749,11 +762,13 @@ module Capybara::Apparition
749
762
  return false;
750
763
  }
751
764
  }
752
-
765
+ var forced_visible = false;
753
766
  while (el) {
754
767
  const style = window.getComputedStyle(el);
768
+ if (style.visibility == 'visible')
769
+ forced_visible = true;
755
770
  if ((style.display == 'none') ||
756
- (style.visibility == 'hidden') ||
771
+ ((style.visibility == 'hidden') && !forced_visible) ||
757
772
  (parseFloat(style.opacity) == 0)) {
758
773
  return false;
759
774
  }
@@ -43,7 +43,7 @@ module Capybara::Apparition
43
43
  @modal_messages = []
44
44
  @frames = Capybara::Apparition::FrameManager.new(id)
45
45
  @response_headers = {}
46
- @status_code = nil
46
+ @status_code = 0
47
47
  @url_blacklist = []
48
48
  @url_whitelist = []
49
49
  @auth_attempts = []
@@ -68,7 +68,7 @@ module Capybara::Apparition
68
68
  @modals.clear
69
69
  @modal_messages.clear
70
70
  @response_headers = {}
71
- @status_code = nil
71
+ @status_code = 0
72
72
  @auth_attempts = []
73
73
  @perm_headers = {}
74
74
  end
@@ -112,11 +112,7 @@ module Capybara::Apparition
112
112
  end
113
113
 
114
114
  def current_frame_offset
115
- return { x: 0, y: 0 } if current_frame.id == main_frame.id
116
-
117
- result = command('DOM.getBoxModel', objectId: current_frame.element_id)
118
- x, y = result['model']['content']
119
- { x: x, y: y }
115
+ frame_offset(current_frame)
120
116
  end
121
117
 
122
118
  def render(options)
@@ -233,7 +229,6 @@ module Capybara::Apparition
233
229
  until cf.usable? || (allow_obsolete && cf.obsolete?) || @js_error
234
230
  if timer.expired?
235
231
  puts 'Timedout waiting for page to be loaded'
236
- # byebug
237
232
  raise TimeoutError.new('wait_for_loaded')
238
233
  end
239
234
  sleep 0.05
@@ -255,7 +250,7 @@ module Capybara::Apparition
255
250
 
256
251
  def visit(url)
257
252
  wait_for_loaded
258
- @status_code = nil
253
+ @status_code = 0
259
254
  navigate_opts = { url: url, transitionType: 'reload' }
260
255
  navigate_opts[:referrer] = extra_headers['Referer'] if extra_headers['Referer']
261
256
  response = command('Page.navigate', navigate_opts)
@@ -273,6 +268,17 @@ module Capybara::Apparition
273
268
  _raw_evaluate('window.location.href', context_id: main_frame.context_id)
274
269
  end
275
270
 
271
+ def element_from_point(x:, y:)
272
+ r_o = _raw_evaluate("document.elementFromPoint(#{x}, #{y})", context_id: main_frame.context_id)
273
+ while r_o && (r_o['description'] =~ /^iframe/)
274
+ frame_node = command('DOM.describeNode', objectId: r_o['objectId'])
275
+ frame = @frames.get(frame_node.dig('node', 'frameId'))
276
+ fo = frame_offset(frame)
277
+ r_o = _raw_evaluate("document.elementFromPoint(#{x - fo[:x]}, #{y - fo[:y]})", context_id: frame.context_id)
278
+ end
279
+ r_o
280
+ end
281
+
276
282
  def frame_url
277
283
  wait_for_loaded
278
284
  _raw_evaluate('window.location.href')
@@ -361,6 +367,14 @@ module Capybara::Apparition
361
367
 
362
368
  private
363
369
 
370
+ def frame_offset(frame)
371
+ return { x: 0, y: 0 } if frame.id == main_frame.id
372
+
373
+ result = command('DOM.getBoxModel', objectId: frame.element_id)
374
+ x, y = result['model']['content']
375
+ { x: x, y: y }
376
+ end
377
+
364
378
  def register_event_handlers
365
379
  @session.on 'Page.javascriptDialogOpening' do |params|
366
380
  type = params['type'].to_sym
@@ -437,7 +451,7 @@ module Capybara::Apparition
437
451
  # end
438
452
  # end
439
453
 
440
- @session.on('Page.domContentEventFired') do |params|
454
+ @session.on('Page.domContentEventFired') do
441
455
  # TODO: Really need something better than this
442
456
  main_frame.loaded! if @status_code != 200
443
457
  end
@@ -497,7 +511,9 @@ module Capybara::Apparition
497
511
  @session.on 'Network.loadingFailed' do |params|
498
512
  req = @network_traffic.find { |request| request.request_id == params['requestId'] }
499
513
  req&.blocked_params = params if params['blockedReason']
500
- puts "Loading Failed - request: #{params['requestId']} : #{params['errorText']}" if params['type'] == 'Document'
514
+ if params['type'] == 'Document'
515
+ puts "Loading Failed - request: #{params['requestId']} : #{params['errorText']}" if ENV['DEBUG']
516
+ end
501
517
  end
502
518
 
503
519
  @session.on 'Network.requestIntercepted' do |params|
@@ -546,7 +562,7 @@ module Capybara::Apparition
546
562
  def process_intercepted_request(interception_id, request, navigation)
547
563
  headers, url = request.values_at('headers', 'url')
548
564
 
549
- unless @temp_headers.empty? || navigation
565
+ unless @temp_headers.empty? || navigation # rubocop:disable Style/IfUnlessModifier
550
566
  headers.delete_if { |name, value| @temp_headers[name] == value }
551
567
  end
552
568
  unless @temp_no_redirect_headers.empty? || !navigation
@@ -711,7 +727,7 @@ module Capybara::Apparition
711
727
  return properties.each_with_object(object_cache[stable_id]) do |property, memo|
712
728
  if property['enumerable']
713
729
  memo[property['name']] = decode_result(property['value'], object_cache)
714
- else
730
+ else # rubocop:disable Style/EmptyElse
715
731
  # TODO: Do we need to cleanup these resources?
716
732
  # releasePromises.push(helper.releaseObject(@element._client, property.value))
717
733
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.0.2'
5
+ VERSION = '0.0.3'
6
6
  end
7
7
  end
@@ -16,5 +16,5 @@ module Capybara
16
16
  end
17
17
 
18
18
  Capybara.register_driver :apparition do |app|
19
- Capybara::Apparition::Driver.new(app)
19
+ Capybara::Apparition::Driver.new(app, headless: true)
20
20
  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.2
4
+ version: 0.0.3
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-26 00:00:00.000000000 Z
11
+ date: 2019-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara