capybara 3.19.0 → 3.20.0
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 +4 -4
- data/History.md +27 -2
- data/README.md +1 -1
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/node/actions.rb +3 -2
- data/lib/capybara/node/element.rb +11 -0
- data/lib/capybara/node/finders.rb +4 -1
- data/lib/capybara/queries/selector_query.rb +19 -5
- data/lib/capybara/selector/definition/label.rb +27 -10
- data/lib/capybara/selector/definition/link.rb +3 -2
- data/lib/capybara/selector.rb +2 -2
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +15 -2
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +1 -1
- data/lib/capybara/selenium/node.rb +25 -1
- data/lib/capybara/selenium/nodes/safari_node.rb +19 -6
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/spec/session/all_spec.rb +23 -0
- data/lib/capybara/spec/session/click_link_spec.rb +11 -0
- data/lib/capybara/spec/session/node_spec.rb +78 -5
- data/lib/capybara/spec/session/selectors_spec.rb +8 -0
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/frame_one.erb +1 -0
- data/lib/capybara/spec/views/obscured.erb +9 -9
- data/lib/capybara/version.rb +1 -1
- data/spec/sauce_spec_chrome.rb +1 -0
- data/spec/selenium_spec_chrome.rb +17 -2
- data/spec/selenium_spec_chrome_remote.rb +4 -2
- data/spec/selenium_spec_edge.rb +4 -2
- data/spec/selenium_spec_firefox.rb +4 -11
- data/spec/selenium_spec_firefox_remote.rb +4 -2
- data/spec/selenium_spec_ie.rb +5 -6
- data/spec/selenium_spec_safari.rb +7 -12
- data/spec/server_spec.rb +4 -2
- data/spec/shared_selenium_node.rb +29 -0
- metadata +23 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '087a3e5a863f14cabebd8344fa0e2f04cb5c48c386014e5fd46eab2e715a8040'
|
|
4
|
+
data.tar.gz: 2ea4bc5aec32f6a7bd63856d922264d29d9629f4c6af71867d30b963d2f04697
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cbc11a7fe022eb230aa9e9342d26b88619cb3cb65931b89487ff448575e6cb794e7460679bd1c37c336bdd65229ca72b4e489b5fbe1a5e2ea7ff92945bb1a1ca
|
|
7
|
+
data.tar.gz: 0a3103be3113216c40efa1cb22cc261141ed940e205c6e9e9483233c5e672079da5b6950aa4f1bf6871524a6f803eb400ed735f48e13429f57eaa9e8376ae367
|
data/History.md
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
|
+
# Version 3.20.0
|
|
2
|
+
Release date: 2019-05-14
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
* `Node#obscured?` to check viewport presence and element overlap
|
|
6
|
+
* `:obscured` system filter to check whether elements are obscured in finders, assertions, and expectations
|
|
7
|
+
* :label selector :for option can be a regexp
|
|
8
|
+
* Significantly smaller `isDisplayed`/`getAttribute` atoms for selenium driver. If these produce issues you can disable their use
|
|
9
|
+
by setting an environment variable named 'DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS' (Please also report any issues).
|
|
10
|
+
* `href: false` option with `find_link`/`click_link`/:link selector ignores `href` presence/absence
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
* Workaround Safari issue with send_keys not correctly using top level modifiers
|
|
15
|
+
* Workaround Safari not retrying click due to incorrect error type
|
|
16
|
+
* Fix Safari attach_file block mode when clicking elements associated to the file input
|
|
17
|
+
* Workaround Safari issue with repeated hover
|
|
18
|
+
|
|
19
|
+
# Version 3.19.1
|
|
20
|
+
Release date: 2019-05-11
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
* Fix access to specializations when Selenium::Driver is subclassed [James Mead]
|
|
25
|
+
|
|
1
26
|
# Version 3.19.0
|
|
2
27
|
Release date: 2019-05-09
|
|
3
28
|
|
|
4
29
|
### Added
|
|
5
30
|
|
|
6
31
|
|
|
7
|
-
* Syntactic sugar `#once`, `#twice`, `#thrice`, `#
|
|
8
|
-
`have_selector`, `have_css`, `have_xpath`, and `have_text` RSpec matchers
|
|
32
|
+
* Syntactic sugar `#once`, `#twice`, `#thrice`, `#exactly`, `#at_least`, `#at_most`, and `#times`
|
|
33
|
+
added to `have_selector`, `have_css`, `have_xpath`, and `have_text` RSpec matchers
|
|
9
34
|
* Support for multiple expression types in Selector definitions
|
|
10
35
|
* Reduced wirecalls for common actions in Selenium driver
|
|
11
36
|
|
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
8
8
|
[](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
|
|
9
9
|
|
|
10
|
-
**Note** You are viewing the README for the 3.
|
|
10
|
+
**Note** You are viewing the README for the 3.20.x version of Capybara.
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
Capybara helps you test web applications by simulating how a real user would
|
data/lib/capybara/driver/node.rb
CHANGED
|
@@ -191,7 +191,7 @@ module Capybara
|
|
|
191
191
|
# @macro waiting_behavior
|
|
192
192
|
#
|
|
193
193
|
# @param value [String] Which option to select
|
|
194
|
-
# @param from [String] The id, Capybara.test_id
|
|
194
|
+
# @param from [String] The id, Capybara.test_id attribute, name or label of the select box
|
|
195
195
|
#
|
|
196
196
|
# @return [Capybara::Node::Element] The option element selected
|
|
197
197
|
def select(value = nil, from: nil, **options)
|
|
@@ -393,9 +393,10 @@ module Capybara
|
|
|
393
393
|
JS
|
|
394
394
|
|
|
395
395
|
CAPTURE_FILE_ELEMENT_SCRIPT = <<~'JS'
|
|
396
|
-
document.addEventListener('click', function(e){
|
|
396
|
+
document.addEventListener('click', function file_catcher(e){
|
|
397
397
|
if (e.target.matches("input[type='file']")) {
|
|
398
398
|
window._capybara_clicked_file_input = e.target;
|
|
399
|
+
this.removeEventListener('click', file_catcher);
|
|
399
400
|
e.preventDefault();
|
|
400
401
|
}
|
|
401
402
|
})
|
|
@@ -290,6 +290,17 @@ module Capybara
|
|
|
290
290
|
synchronize { base.visible? }
|
|
291
291
|
end
|
|
292
292
|
|
|
293
|
+
##
|
|
294
|
+
#
|
|
295
|
+
# Whether or not the element is currently in the viewport and it (or descendants)
|
|
296
|
+
# would be considered clickable at the elements center point.
|
|
297
|
+
#
|
|
298
|
+
# @return [Boolean] Whether the elements center is obscured.
|
|
299
|
+
#
|
|
300
|
+
def obscured?
|
|
301
|
+
synchronize { base.obscured? }
|
|
302
|
+
end
|
|
303
|
+
|
|
293
304
|
##
|
|
294
305
|
#
|
|
295
306
|
# Whether or not the element is checked.
|
|
@@ -31,6 +31,9 @@ module Capybara
|
|
|
31
31
|
# * :all - same as false; finds visible and invisible elements.
|
|
32
32
|
# * :hidden - only finds invisible elements.
|
|
33
33
|
# * :visible - same as true; only finds visible elements.
|
|
34
|
+
# @option options [Boolean] obscured Only find elements with the specified obscured state:
|
|
35
|
+
# * true - only find elements whose centerpoint is not in the viewport or is obscured by another non-descendant element.
|
|
36
|
+
# * false - only find elements whose centerpoint is in the viewport and is not obscured by other non-descendant elements.
|
|
34
37
|
# @option options [String, Regexp] id Only find elements with an id that matches the value passed
|
|
35
38
|
# @option options [String, Array<String>, Regexp] class Only find elements with matching class/classes.
|
|
36
39
|
# + Absence of a class can be checked by prefixing the class name with !
|
|
@@ -139,7 +142,7 @@ module Capybara
|
|
|
139
142
|
#
|
|
140
143
|
# @macro waiting_behavior
|
|
141
144
|
#
|
|
142
|
-
# @option options [String,Regexp,nil] href Value to match against the links href, if nil finds link placeholders (<a> elements with no href attribute)
|
|
145
|
+
# @option options [String,Regexp,nil] href Value to match against the links href, if nil finds link placeholders (<a> elements with no href attribute), if false ignores the href
|
|
143
146
|
# @option options [String, Regexp] id Match links with the id provided
|
|
144
147
|
# @option options [String] title Match links with the title provided
|
|
145
148
|
# @option options [String] alt Match links with a contained img element whose alt matches
|
|
@@ -4,7 +4,8 @@ module Capybara
|
|
|
4
4
|
module Queries
|
|
5
5
|
class SelectorQuery < Queries::BaseQuery
|
|
6
6
|
attr_reader :expression, :selector, :locator, :options
|
|
7
|
-
VALID_KEYS = COUNT_KEYS +
|
|
7
|
+
VALID_KEYS = COUNT_KEYS +
|
|
8
|
+
%i[text id class style visible obscured exact exact_text normalize_ws match wait filter_set]
|
|
8
9
|
VALID_MATCH = %i[first smart prefer_exact one].freeze
|
|
9
10
|
|
|
10
11
|
def initialize(*args,
|
|
@@ -386,7 +387,7 @@ module Capybara
|
|
|
386
387
|
def matches_system_filters?(node)
|
|
387
388
|
applied_filters << :system
|
|
388
389
|
|
|
389
|
-
|
|
390
|
+
matches_visibility_filters?(node) &&
|
|
390
391
|
matches_id_filter?(node) &&
|
|
391
392
|
matches_class_filter?(node) &&
|
|
392
393
|
matches_style_filter?(node) &&
|
|
@@ -443,14 +444,27 @@ module Capybara
|
|
|
443
444
|
matches_text_exactly?(node, exact_text)
|
|
444
445
|
end
|
|
445
446
|
|
|
446
|
-
def
|
|
447
|
-
|
|
447
|
+
def matches_visibility_filters?(node)
|
|
448
|
+
obscured = options[:obscured]
|
|
449
|
+
return (visible != :hidden) && (node.initial_cache[:visible] != false) && !node.obscured? if obscured == false
|
|
450
|
+
|
|
451
|
+
vis = case visible
|
|
448
452
|
when :visible then
|
|
449
453
|
node.initial_cache[:visible] || (node.initial_cache[:visible].nil? && node.visible?)
|
|
450
454
|
when :hidden then
|
|
451
455
|
(node.initial_cache[:visible] == false) || (node.initial_cache[:visbile].nil? && !node.visible?)
|
|
452
|
-
else
|
|
456
|
+
else
|
|
457
|
+
true
|
|
453
458
|
end
|
|
459
|
+
|
|
460
|
+
vis && case obscured
|
|
461
|
+
when true
|
|
462
|
+
node.obscured?
|
|
463
|
+
when false
|
|
464
|
+
!node.obscured?
|
|
465
|
+
else
|
|
466
|
+
true
|
|
467
|
+
end
|
|
454
468
|
end
|
|
455
469
|
|
|
456
470
|
def matches_text_exactly?(node, value)
|
|
@@ -11,10 +11,9 @@ Capybara.add_selector(:label, locator_type: [String, Symbol]) do
|
|
|
11
11
|
end
|
|
12
12
|
if options.key?(:for)
|
|
13
13
|
if (for_option = options[:for].is_a?(Capybara::Node::Element) ? options[:for][:id] : options[:for])
|
|
14
|
-
with_attr = XPath.
|
|
15
|
-
labelable_elements = %i[button input keygen meter output progress select textarea]
|
|
14
|
+
with_attr = builder(XPath.self).add_attribute_conditions(for: for_option)
|
|
16
15
|
wrapped = !XPath.attr(:for) &
|
|
17
|
-
XPath.descendant(*labelable_elements)
|
|
16
|
+
builder(XPath.self.descendant(*labelable_elements)).add_attribute_conditions(id: for_option)
|
|
18
17
|
xpath = xpath[with_attr | wrapped]
|
|
19
18
|
end
|
|
20
19
|
end
|
|
@@ -22,22 +21,40 @@ Capybara.add_selector(:label, locator_type: [String, Symbol]) do
|
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
node_filter(:for) do |node, field_or_value|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
case field_or_value
|
|
25
|
+
when Capybara::Node::Element
|
|
26
|
+
if (for_val = node[:for])
|
|
27
|
+
field_or_value[:id] == for_val
|
|
28
|
+
else
|
|
29
|
+
field_or_value.find_xpath('./ancestor::label[1]').include? node.base
|
|
30
|
+
end
|
|
31
|
+
when Regexp
|
|
32
|
+
if (for_val = node[:for])
|
|
33
|
+
field_or_value.match? for_val
|
|
34
|
+
else
|
|
35
|
+
node.find_xpath(XPath.descendant(*labelable_elements).to_s)
|
|
36
|
+
.any? { |n| field_or_value.match? n[:id] }
|
|
37
|
+
end
|
|
30
38
|
else
|
|
31
|
-
|
|
39
|
+
# Non element/regexp values were handled through the expression filter
|
|
40
|
+
true
|
|
32
41
|
end
|
|
33
42
|
end
|
|
34
43
|
|
|
35
44
|
describe_expression_filters do |**options|
|
|
36
45
|
next unless options.key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
if options[:for].is_a? Regexp
|
|
48
|
+
" for element with id matching #{options[:for].inspect}"
|
|
49
|
+
else
|
|
50
|
+
" for element with id of \"#{options[:for]}\""
|
|
51
|
+
end
|
|
39
52
|
end
|
|
40
53
|
describe_node_filters do |**options|
|
|
41
54
|
" for element #{options[:for]}" if options[:for]&.is_a?(Capybara::Node::Element)
|
|
42
55
|
end
|
|
56
|
+
|
|
57
|
+
def labelable_elements
|
|
58
|
+
%i[button input keygen meter output progress select textarea]
|
|
59
|
+
end
|
|
43
60
|
end
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Capybara.add_selector(:link, locator_type: [String, Symbol]) do
|
|
4
4
|
xpath do |locator, href: true, alt: nil, title: nil, **|
|
|
5
|
-
xpath =
|
|
5
|
+
xpath = XPath.descendant(:a)
|
|
6
|
+
xpath = builder(xpath).add_attribute_conditions(href: href) unless href == false
|
|
6
7
|
|
|
7
8
|
unless locator.nil?
|
|
8
9
|
locator = locator.to_s
|
|
@@ -35,7 +36,7 @@ Capybara.add_selector(:link, locator_type: [String, Symbol]) do
|
|
|
35
36
|
desc = +''
|
|
36
37
|
if (href = options[:href])
|
|
37
38
|
desc << " with href #{'matching ' if href.is_a? Regexp}#{href.inspect}"
|
|
38
|
-
elsif options.key?(:href) # is nil
|
|
39
|
+
elsif options.key?(:href) && href != false # is nil specified?
|
|
39
40
|
desc << ' with no href attribute'
|
|
40
41
|
end
|
|
41
42
|
desc << " with download attribute#{" #{download}" if download.is_a? String}" if download
|
data/lib/capybara/selector.rb
CHANGED
|
@@ -48,7 +48,7 @@ require 'capybara/selector/definition'
|
|
|
48
48
|
# * :title (String) — Matches the title attribute
|
|
49
49
|
# * :alt (String) — Matches the alt attribute of a contained img element
|
|
50
50
|
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
|
51
|
-
# * :href (String, Regexp, nil) — Matches the normalized href of the link, if nil will find <a> elements with no href attribute
|
|
51
|
+
# * :href (String, Regexp, nil, false) — Matches the normalized href of the link, if nil will find <a> elements with no href attribute, if false ignores href
|
|
52
52
|
# * :style (String, Regexp, Hash)
|
|
53
53
|
#
|
|
54
54
|
# * **:button** - Find buttons ( input [of type submit, reset, image, button] or button elements )
|
|
@@ -146,7 +146,7 @@ require 'capybara/selector/definition'
|
|
|
146
146
|
# * **:label** - Find label elements
|
|
147
147
|
# * Locator: Match id or text contents
|
|
148
148
|
# * Filters:
|
|
149
|
-
# * :for (Element, String) — The element or id of the element associated with the label
|
|
149
|
+
# * :for (Element, String, Regexp) — The element or id of the element associated with the label
|
|
150
150
|
#
|
|
151
151
|
# * **:table** - Find table elements
|
|
152
152
|
# * Locator: id or caption text of table
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){function u(e){var t=e.tagName.toUpperCase();if("OPTION"==t)return!0;if("INPUT"!=t)return!1;var r=e.type.toLowerCase();return"checkbox"==r||"radio"==r}function s(e){var t="selected",r=e.type&&e.type.toLowerCase();return"checkbox"!=r&&"radio"!=r||(t="checked"),!!e[t]}function c(e,t){var r=e.getAttributeNode(t);return r&&r.specified?r.value:null}var i=["allowfullscreen","allowpaymentrequest","allowusermedia","async","autofocus","autoplay","checked","compact","complete","controls","declare","default","defaultchecked","defaultselected","defer","disabled","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","nomodule","noresize","noshade","novalidate","nowrap","open","paused","playsinline","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","truespeed","typemustmatch","willvalidate"],d={"class":"className",readonly:"readOnly"};return function f(e,t){var r=null,a=t.toLowerCase();if("style"==a)return(r=e.style)&&"string"!=typeof r&&(r=r.cssText),r;if(("selected"==a||"checked"==a)&&u(e))return s(e)?"true":null;if(tagName=e.tagName.toUpperCase(),"IMG"==tagName&&"src"==a||"A"==tagName&&"href"==a)return(r=c(e,a))&&(r=e[a]),r;if("spellcheck"==a){if(null===!(r=c(e,a))){if("false"==r.toLowerCase())return"false";if("true"==r.toLowerCase())return"true"}return e[a]+""}var l,n=d[t]||t;if(i.some(function(e){e==a}))return(r=!(null===(r=c(e,a)))||e[n])?"true":null;try{l=e[n]}catch(o){}return null!=(r=null==l||"object"==typeof l||"function"==typeof l?c(e,t):l)?r.toString():null}})()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){function f(t,e,n){function r(t){var e=x(t);if(0<e.height&&0<e.width)return!0;if("PATH"==t.tagName.toUpperCase()&&(0<e.height||0<e.width)){var n=window.getComputedStyle(t)["stroke-width"];return!!n&&0<parseInt(n,10)}return"hidden"!=window.getComputedStyle(t).overflow&&Array.prototype.slice.call(t.childNodes).some(function(t){return t.nodeType==Node.TEXT_NODE||t.nodeType==Node.ELEMENT_NODE&&r(t)})}function i(t){return C(t)==T.HIDDEN&&Array.prototype.slice.call(t.childNodes).every(function(t){return t.nodeType!=Node.ELEMENT_NODE||i(t)||!r(t)})}var o=t.tagName.toUpperCase();if("BODY"==o)return!0;var a=D(t);if(a&&a.tagName&&"DETAILS"==a.tagName.toUpperCase()&&!a.open&&"SUMMARY"!=o)return!1;if("OPTION"==o||"OPTGROUP"==o){var u=v(t,function(t){return"SELECT"==t.tagName.toUpperCase()});return!!u&&f(u,!0,n)}var l=c(t);if(l)return!!l.image&&0<l.rect.width&&0<l.rect.height&&f(l.image,e,n);if("INPUT"==o&&"hidden"==t.type.toLowerCase())return!1;if("NOSCRIPT"==o)return!1;var d=window.getComputedStyle(t).visibility;return"collapse"!=d&&"hidden"!=d&&(!!n(t)&&(!(!e&&0==h(t))&&(!!r(t)&&!i(t))))}function E(t){var e=x(t);return{left:e.left,right:e.left+e.width,top:e.top,bottom:e.top+e.height}}function D(t){return t.parentElement}function C(t){function e(t){function e(t){if(t==u)return!0;var e=window.getComputedStyle(t),n=e.display;return 0!=n.indexOf("inline")&&"contents"!=n&&("absolute"!=r||"static"!=e.position)}var r=window.getComputedStyle(t).position;if("fixed"==r)return i=!0,t==u?null:u;for(var n=D(t);n&&!e(n);)n=D(n);return n}function n(t){var e=t;if("visible"==d)if(t==u&&l)e=l;else if(t==l)return{x:"visible",y:"visible"};var n=window.getComputedStyle(e),r={x:n["overflow-x"],y:n["overflow-y"]};return t==u&&(r.x="visible"==r.x?"auto":r.x,r.y="visible"==r.y?"auto":r.y),r}function r(t){return t==u?{x:window.scrollX,y:window.scrollY}:{x:t.scrollLeft,y:t.scrollTop}}for(var i,o=E(t),a=t.ownerDocument,u=a.documentElement,l=a.body,d=window.getComputedStyle(u).overflow,f=e(t);f;f=e(f)){var h=n(f);if("visible"!=h.x||"visible"!=h.y){var s=x(f);if(0==s.width||0==s.height)return T.HIDDEN;var p=o.right<s.left,c=o.bottom<s.top;if(p&&"hidden"==h.x||c&&"hidden"==h.y)return T.HIDDEN;if(p&&"visible"!=h.x||c&&"visible"!=h.y){var v=r(f),g=o.right<s.left-v.x,w=o.bottom<s.top-v.y;return g&&"visible"!=h.x||w&&"visible"!=h.x?T.HIDDEN:C(f)==T.HIDDEN?T.HIDDEN:T.SCROLL}var N=o.left>=s.left+s.width,m=o.top>=s.top+s.height;if(N&&"hidden"==h.x||m&&"hidden"==h.y)return T.HIDDEN;if(N&&"visible"!=h.x||m&&"visible"!=h.y){if(i){var y=r(f);if(o.left>=u.scrollWidth-y.x||o.right>=u.scrollHeight-y.y)return T.HIDDEN}return C(f)==T.HIDDEN?T.HIDDEN:T.SCROLL}}}return T.NONE}function o(t){var e=t.document.documentElement;return{width:e.clientWidth,height:e.clientHeight}}function p(t,e,n,r){return{left:t,top:e,width:n,height:r}}function x(t){var e,n=c(t);if(n)return n.rect;if("HTML"==t.tagName.toUpperCase()){t.ownerDocument;var r=o(window);return p(0,0,r.width,r.height)}try{e=t.getBoundingClientRect()}catch(i){return p(0,0,0,0)}return p(e.left,e.top,e.right-e.left,e.bottom-e.top)}function h(t){var e=1,n=window.getComputedStyle(t).opacity;n&&(e=Number(n));var r=D(t);return r&&r.nodeType==Node.ELEMENT_NODE&&(e*=h(r)),e}function s(t){var e=t.shape.toLowerCase(),n=t.coords.split(",");if("rect"==e&&4==n.length){var r=n[0],i=n[1];return p(r,i,n[2]-r,n[3]-i)}if("circle"==e&&3==n.length){var o=n[0],a=n[1],u=n[2];return p(o-u,a-u,2*u,2*u)}if("poly"==e&&2<n.length){for(var l=n[0],d=n[1],f=l,h=d,s=2;s+1<n.length;s+=2)l=Math.min(l,n[s]),f=Math.max(f,n[s]),d=Math.min(d,n[s+1]),h=Math.max(h,n[s+1]);return p(l,d,f-l,h-d)}return p(0,0,0,0)}function c(t){var e=t.tagName.toUpperCase(),n="MAP"==e;if(!n&&"AREA"!=e)return null;var r=n?t:"MAP"==D(t).tagName.toUpperCase()?D(t):null,i=null,o=null;if(r&&r.name&&((i=r.ownerDocument.querySelector("*[usemap='#"+r.name+"']"))&&(o=x(i),!n&&"default"!=t.shape.toLowerCase()))){var a=s(t),u=Math.min(Math.max(a.left,0),o.width),l=Math.min(Math.max(a.top,0),o.height),d=Math.min(a.width,o.width-u),f=Math.min(a.height,o.height-l);o=p(u+o.left,l+o.top,d,f)}return{image:i,rect:o||p(0,0,0,0)}}function v(t,e){for(t&&(t=D(t));t;){if(e(t))return t;t=D(t)}return null}function r(t){var e=t.parentNode;if(e&&e.shadowRoot&&t.assignedSlot!==undefined)return t.assignedSlot?t.assignedSlot.parentNode:null;if(t.getDestinationInsertionPoints){var n=t.getDestinationInsertionPoints();if(0<n.length)return n[n.length-1]}return e}var T={NONE:"none",HIDDEN:"hidden",SCROLL:"scroll"};return function i(t,e){function n(t){if("none"==window.getComputedStyle(t).display)return!1;var e=r(t);if("function"==typeof ShadowRoot&&e instanceof ShadowRoot){if(e.host.shadowRoot!==e)return!1;e=e.host}return!(!e||e.nodeType!=Node.DOCUMENT_NODE&&e.nodeType!=Node.DOCUMENT_FRAGMENT_NODE)||e&&n(e)}return f(t,!!e,n)}})()
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
(function(){
|
|
2
|
+
var BOOLEAN_PROPERTIES = [
|
|
3
|
+
"allowfullscreen",
|
|
4
|
+
"allowpaymentrequest",
|
|
5
|
+
"allowusermedia",
|
|
6
|
+
"async",
|
|
7
|
+
"autofocus",
|
|
8
|
+
"autoplay",
|
|
9
|
+
"checked",
|
|
10
|
+
"compact",
|
|
11
|
+
"complete",
|
|
12
|
+
"controls",
|
|
13
|
+
"declare",
|
|
14
|
+
"default",
|
|
15
|
+
"defaultchecked",
|
|
16
|
+
"defaultselected",
|
|
17
|
+
"defer",
|
|
18
|
+
"disabled",
|
|
19
|
+
"ended",
|
|
20
|
+
"formnovalidate",
|
|
21
|
+
"hidden",
|
|
22
|
+
"indeterminate",
|
|
23
|
+
"iscontenteditable",
|
|
24
|
+
"ismap",
|
|
25
|
+
"itemscope",
|
|
26
|
+
"loop",
|
|
27
|
+
"multiple",
|
|
28
|
+
"muted",
|
|
29
|
+
"nohref",
|
|
30
|
+
"nomodule",
|
|
31
|
+
"noresize",
|
|
32
|
+
"noshade",
|
|
33
|
+
"novalidate",
|
|
34
|
+
"nowrap",
|
|
35
|
+
"open",
|
|
36
|
+
"paused",
|
|
37
|
+
"playsinline",
|
|
38
|
+
"pubdate",
|
|
39
|
+
"readonly",
|
|
40
|
+
"required",
|
|
41
|
+
"reversed",
|
|
42
|
+
"scoped",
|
|
43
|
+
"seamless",
|
|
44
|
+
"seeking",
|
|
45
|
+
"selected",
|
|
46
|
+
"truespeed",
|
|
47
|
+
"typemustmatch",
|
|
48
|
+
"willvalidate"
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
var PROPERTY_ALIASES = {
|
|
52
|
+
"class": "className",
|
|
53
|
+
"readonly": "readOnly"
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function isSelectable(element){
|
|
57
|
+
var tagName = element.tagName.toUpperCase();
|
|
58
|
+
|
|
59
|
+
if (tagName == "OPTION"){
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (tagName == "INPUT") {
|
|
64
|
+
var type = element.type.toLowerCase();
|
|
65
|
+
return type == "checkbox" || type == "radio";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isSelected(element){
|
|
72
|
+
var propertyName = "selected";
|
|
73
|
+
var type = element.type && element.type.toLowerCase();
|
|
74
|
+
if ("checkbox" == type || "radio" == type) {
|
|
75
|
+
propertyName = "checked";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return !!element[propertyName];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getAttributeValue(element, name){
|
|
82
|
+
var attr = element.getAttributeNode(name);
|
|
83
|
+
return (attr && attr.specified) ? attr.value : null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return function get(element, attribute){
|
|
87
|
+
var value = null;
|
|
88
|
+
var name = attribute.toLowerCase();
|
|
89
|
+
|
|
90
|
+
if ("style" == name) {
|
|
91
|
+
value = element.style;
|
|
92
|
+
|
|
93
|
+
if (value && (typeof value != "string")) {
|
|
94
|
+
value = value.cssText;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (("selected" == name || "checked" == name) &&
|
|
101
|
+
isSelectable(element)) {
|
|
102
|
+
return isSelected(element) ? "true" : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
tagName = element.tagName.toUpperCase();
|
|
106
|
+
|
|
107
|
+
// The property is consistent. Return that in preference to the attribute for links and images.
|
|
108
|
+
if (((tagName == "IMG") && name == "src") ||
|
|
109
|
+
((tagName == "A") && name == "href")) {
|
|
110
|
+
value = getAttributeValue(element, name);
|
|
111
|
+
if (value) {
|
|
112
|
+
// We want the full URL if present
|
|
113
|
+
value = element[name];
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if ("spellcheck" == name) {
|
|
119
|
+
value = getAttributeValue(element, name);
|
|
120
|
+
if (!value === null) {
|
|
121
|
+
if (value.toLowerCase() == "false") {
|
|
122
|
+
return "false";
|
|
123
|
+
} else if (value.toLowerCase() == "true") {
|
|
124
|
+
return "true";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// coerce the property value to a string
|
|
128
|
+
return element[name] + "";
|
|
129
|
+
}
|
|
130
|
+
var propName = PROPERTY_ALIASES[attribute] || attribute;
|
|
131
|
+
if (BOOLEAN_PROPERTIES.some(function(prop){ prop == name })) {
|
|
132
|
+
value = getAttributeValue(element, name);
|
|
133
|
+
value = !(value === null) || element[propName];
|
|
134
|
+
return value ? "true" : null;
|
|
135
|
+
}
|
|
136
|
+
var property;
|
|
137
|
+
try {
|
|
138
|
+
property = element[propName]
|
|
139
|
+
} catch (e) {
|
|
140
|
+
// Leaves property undefined or null
|
|
141
|
+
}
|
|
142
|
+
// 1- Call getAttribute if getProperty fails,
|
|
143
|
+
// i.e. property is null or undefined.
|
|
144
|
+
// This happens for event handlers in Firefox.
|
|
145
|
+
// For example, calling getProperty for 'onclick' would
|
|
146
|
+
// fail while getAttribute for 'onclick' will succeed and
|
|
147
|
+
// return the JS code of the handler.
|
|
148
|
+
//
|
|
149
|
+
// 2- When property is an object we fall back to the
|
|
150
|
+
// actual attribute instead.
|
|
151
|
+
// See issue http://code.google.com/p/selenium/issues/detail?id=966
|
|
152
|
+
if ((property == null) || (typeof property == "object") || (typeof property == "function")) {
|
|
153
|
+
value = getAttributeValue(element, attribute);
|
|
154
|
+
} else {
|
|
155
|
+
value = property;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// The empty string is a valid return value.
|
|
159
|
+
return value != null ? value.toString() : null;
|
|
160
|
+
};
|
|
161
|
+
})()
|