apparition 0.0.2 → 0.0.3

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