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 +4 -4
- data/lib/capybara/apparition/browser.rb +3 -1
- data/lib/capybara/apparition/driver.rb +1 -1
- data/lib/capybara/apparition/errors.rb +1 -0
- data/lib/capybara/apparition/inspector.rb +1 -1
- data/lib/capybara/apparition/node/drag.rb +1 -1
- data/lib/capybara/apparition/node.rb +60 -45
- data/lib/capybara/apparition/page.rb +29 -13
- data/lib/capybara/apparition/version.rb +1 -1
- data/lib/capybara/apparition.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4f76aefa6b5bebbab16d325e6f434846c2a426b74df9b8c0248465653124202
|
4
|
+
data.tar.gz: e9538e39a9c912471527fc456e801f0b3cc261bf042ddc82177d0e74e0769a33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
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 = {})
|
@@ -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(
|
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
|
-
|
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
|
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
|
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
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
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
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
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 =
|
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 =
|
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
|
-
|
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 =
|
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
|
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
|
-
|
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
|
data/lib/capybara/apparition.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2019-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|