watir-webdriver 0.9.1 → 0.9.2
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/.gitignore +3 -0
- data/.travis.yml +7 -3
- data/CHANGES.md +6 -0
- data/Rakefile +17 -5
- data/lib/watir-webdriver.rb +16 -6
- data/lib/watir-webdriver/after_hooks.rb +2 -2
- data/lib/watir-webdriver/browser.rb +5 -5
- data/lib/watir-webdriver/cell_container.rb +4 -10
- data/lib/watir-webdriver/element_collection.rb +28 -7
- data/lib/watir-webdriver/elements/button.rb +0 -18
- data/lib/watir-webdriver/elements/cell.rb +17 -0
- data/lib/watir-webdriver/elements/checkbox.rb +0 -3
- data/lib/watir-webdriver/elements/element.rb +37 -10
- data/lib/watir-webdriver/elements/file_field.rb +0 -3
- data/lib/watir-webdriver/elements/hidden.rb +0 -3
- data/lib/watir-webdriver/elements/html_elements.rb +0 -219
- data/lib/watir-webdriver/elements/iframe.rb +29 -19
- data/lib/watir-webdriver/elements/row.rb +17 -0
- data/lib/watir-webdriver/elements/svg_elements.rb +0 -120
- data/lib/watir-webdriver/elements/table.rb +1 -1
- data/lib/watir-webdriver/elements/table_cell.rb +0 -28
- data/lib/watir-webdriver/elements/table_row.rb +1 -30
- data/lib/watir-webdriver/elements/text_area.rb +0 -17
- data/lib/watir-webdriver/elements/text_field.rb +2 -8
- data/lib/watir-webdriver/generator/base/visitor.rb +1 -10
- data/lib/watir-webdriver/locators.rb +22 -0
- data/lib/watir-webdriver/locators/button/locator.rb +38 -0
- data/lib/watir-webdriver/locators/button/selector_builder.rb +27 -0
- data/lib/watir-webdriver/locators/button/selector_builder/xpath.rb +29 -0
- data/lib/watir-webdriver/locators/button/validator.rb +14 -0
- data/lib/watir-webdriver/locators/cell/locator.rb +17 -0
- data/lib/watir-webdriver/locators/cell/selector_builder.rb +24 -0
- data/lib/watir-webdriver/locators/element/locator.rb +249 -0
- data/lib/watir-webdriver/locators/element/selector_builder.rb +147 -0
- data/lib/watir-webdriver/locators/element/selector_builder/css.rb +65 -0
- data/lib/watir-webdriver/locators/element/selector_builder/xpath.rb +72 -0
- data/lib/watir-webdriver/locators/element/validator.rb +22 -0
- data/lib/watir-webdriver/locators/row/locator.rb +17 -0
- data/lib/watir-webdriver/locators/row/selector_builder.rb +29 -0
- data/lib/watir-webdriver/locators/text_area/locator.rb +13 -0
- data/lib/watir-webdriver/locators/text_area/selector_builder.rb +22 -0
- data/lib/watir-webdriver/locators/text_field/locator.rb +42 -0
- data/lib/watir-webdriver/locators/text_field/selector_builder.rb +34 -0
- data/lib/watir-webdriver/locators/text_field/selector_builder/xpath.rb +19 -0
- data/lib/watir-webdriver/locators/text_field/validator.rb +20 -0
- data/lib/watir-webdriver/row_container.rb +3 -9
- data/lib/watir-webdriver/version.rb +1 -1
- data/lib/watir-webdriver/wait.rb +6 -3
- data/spec/always_locate_spec.rb +2 -1
- data/spec/element_locator_spec.rb +1 -1
- data/spec/element_spec.rb +8 -40
- data/spec/implementation.rb +52 -45
- data/spec/locator_spec_helper.rb +8 -2
- data/support/travis.sh +17 -6
- metadata +25 -10
- data/lib/watir-webdriver/locators/button_locator.rb +0 -85
- data/lib/watir-webdriver/locators/child_cell_locator.rb +0 -32
- data/lib/watir-webdriver/locators/child_row_locator.rb +0 -37
- data/lib/watir-webdriver/locators/element_locator.rb +0 -470
- data/lib/watir-webdriver/locators/text_area_locator.rb +0 -24
- data/lib/watir-webdriver/locators/text_field_locator.rb +0 -93
@@ -1,34 +1,6 @@
|
|
1
1
|
module Watir
|
2
2
|
class TableCell < HTMLElement
|
3
|
-
# @private
|
4
|
-
attr_writer :locator_class
|
5
|
-
|
6
3
|
alias_method :colspan, :col_span
|
7
4
|
alias_method :rowspan, :row_span
|
8
|
-
|
9
|
-
def locator_class
|
10
|
-
@locator_class || super
|
11
|
-
end
|
12
5
|
end # TableCell
|
13
|
-
|
14
|
-
class TableCellCollection < ElementCollection
|
15
|
-
attr_writer :locator_class
|
16
|
-
|
17
|
-
def locator_class
|
18
|
-
@locator_class || super
|
19
|
-
end
|
20
|
-
|
21
|
-
def elements
|
22
|
-
# we do this craziness since the xpath used will find direct child rows
|
23
|
-
# before any rows inside thead/tbody/tfoot...
|
24
|
-
elements = super
|
25
|
-
|
26
|
-
if locator_class == ChildCellLocator
|
27
|
-
elements = elements.sort_by { |row| row.attribute(:cellIndex).to_i }
|
28
|
-
end
|
29
|
-
|
30
|
-
elements
|
31
|
-
end
|
32
|
-
|
33
|
-
end # TableCellCollection
|
34
6
|
end # Watir
|
@@ -2,43 +2,14 @@ module Watir
|
|
2
2
|
class TableRow < HTMLElement
|
3
3
|
include CellContainer
|
4
4
|
|
5
|
-
# @private
|
6
|
-
attr_writer :locator_class
|
7
|
-
|
8
5
|
#
|
9
6
|
# Get the n'th cell (<th> or <td>) of this row
|
10
7
|
#
|
11
|
-
# @return Watir::
|
8
|
+
# @return Watir::Cell
|
12
9
|
#
|
13
10
|
|
14
11
|
def [](idx)
|
15
12
|
cell(:index, idx)
|
16
13
|
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def locator_class
|
21
|
-
@locator_class || super
|
22
|
-
end
|
23
14
|
end # TableRow
|
24
|
-
|
25
|
-
class TableRowCollection < ElementCollection
|
26
|
-
attr_writer :locator_class
|
27
|
-
|
28
|
-
def elements
|
29
|
-
# we do this craziness since the xpath used will find direct child rows
|
30
|
-
# before any rows inside thead/tbody/tfoot...
|
31
|
-
elements = super
|
32
|
-
|
33
|
-
if locator_class == ChildRowLocator and @parent.kind_of? Table
|
34
|
-
elements = elements.sort_by { |row| row.attribute(:rowIndex).to_i }
|
35
|
-
end
|
36
|
-
|
37
|
-
elements
|
38
|
-
end
|
39
|
-
|
40
|
-
def locator_class
|
41
|
-
@locator_class || super
|
42
|
-
end
|
43
|
-
end # TableRowCollection
|
44
15
|
end # Watir
|
@@ -1,22 +1,5 @@
|
|
1
1
|
module Watir
|
2
2
|
class TextArea < HTMLElement
|
3
3
|
include UserEditable
|
4
|
-
|
5
|
-
private
|
6
|
-
|
7
|
-
def locator_class
|
8
|
-
TextAreaLocator
|
9
|
-
end
|
10
|
-
|
11
4
|
end # TextArea
|
12
|
-
|
13
|
-
class TextAreaCollection < ElementCollection
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def locator_class
|
18
|
-
TextAreaLocator
|
19
|
-
end
|
20
|
-
|
21
|
-
end # TextAreaCollection
|
22
5
|
end # Watir
|
@@ -2,15 +2,13 @@ module Watir
|
|
2
2
|
class TextField < Input
|
3
3
|
include UserEditable
|
4
4
|
|
5
|
+
NON_TEXT_TYPES = %w[file radio checkbox submit reset image button hidden datetime date month week time datetime-local range color]
|
6
|
+
|
5
7
|
inherit_attributes_from Watir::TextArea
|
6
8
|
remove_method :type # we want Input#type here, which was overriden by TextArea's attributes
|
7
9
|
|
8
10
|
private
|
9
11
|
|
10
|
-
def locator_class
|
11
|
-
TextFieldLocator
|
12
|
-
end
|
13
|
-
|
14
12
|
def selector_string
|
15
13
|
selector = @selector.dup
|
16
14
|
selector[:type] = '(any text type)'
|
@@ -32,10 +30,6 @@ module Watir
|
|
32
30
|
class TextFieldCollection < InputCollection
|
33
31
|
private
|
34
32
|
|
35
|
-
def locator_class
|
36
|
-
TextFieldLocator
|
37
|
-
end
|
38
|
-
|
39
33
|
def element_class
|
40
34
|
TextField
|
41
35
|
end
|
@@ -97,16 +97,7 @@ module Watir
|
|
97
97
|
@already_defined << name
|
98
98
|
name = Util.classify(classify_regexp, name)
|
99
99
|
|
100
|
-
[:class, "#{name}Collection", [:const, :ElementCollection]
|
101
|
-
[:scope,
|
102
|
-
[:defn, :element_class,
|
103
|
-
[:args],
|
104
|
-
[:scope,
|
105
|
-
[:block, [:const, name]]
|
106
|
-
]
|
107
|
-
]
|
108
|
-
]
|
109
|
-
]
|
100
|
+
[:class, "#{name}Collection", [:const, :ElementCollection]]
|
110
101
|
end
|
111
102
|
|
112
103
|
def attribute_calls(attributes)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'watir-webdriver/locators/element/locator'
|
2
|
+
require 'watir-webdriver/locators/element/selector_builder'
|
3
|
+
require 'watir-webdriver/locators/element/validator'
|
4
|
+
|
5
|
+
require 'watir-webdriver/locators/button/locator'
|
6
|
+
require 'watir-webdriver/locators/button/selector_builder'
|
7
|
+
require 'watir-webdriver/locators/button/selector_builder/xpath'
|
8
|
+
require 'watir-webdriver/locators/button/validator'
|
9
|
+
|
10
|
+
require 'watir-webdriver/locators/cell/locator'
|
11
|
+
require 'watir-webdriver/locators/cell/selector_builder'
|
12
|
+
|
13
|
+
require 'watir-webdriver/locators/row/locator'
|
14
|
+
require 'watir-webdriver/locators/row/selector_builder'
|
15
|
+
|
16
|
+
require 'watir-webdriver/locators/text_area/locator'
|
17
|
+
require 'watir-webdriver/locators/text_area/selector_builder'
|
18
|
+
|
19
|
+
require 'watir-webdriver/locators/text_field/locator'
|
20
|
+
require 'watir-webdriver/locators/text_field/selector_builder'
|
21
|
+
require 'watir-webdriver/locators/text_field/selector_builder/xpath'
|
22
|
+
require 'watir-webdriver/locators/text_field/validator'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Button
|
4
|
+
class Locator < Element::Locator
|
5
|
+
def locate_all
|
6
|
+
find_all_by_multiple
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def wd_find_first_by(how, what)
|
12
|
+
if how == :tag_name
|
13
|
+
how = :xpath
|
14
|
+
what = ".//button | .//input[#{selector_builder.xpath_builder.attribute_expression(:input, type: Watir::Button::VALID_TYPES)}]"
|
15
|
+
end
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def can_convert_regexp_to_contains?
|
21
|
+
# regexp conversion won't work with the complex xpath selector
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches_selector?(element, selector)
|
26
|
+
if selector.key?(:value)
|
27
|
+
copy = selector.dup
|
28
|
+
value = copy.delete(:value)
|
29
|
+
|
30
|
+
super(element, copy) && (value === fetch_value(element, :value) || value === fetch_value(element, :text))
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Button
|
4
|
+
class SelectorBuilder < Element::SelectorBuilder
|
5
|
+
def build_wd_selector(selectors)
|
6
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
7
|
+
|
8
|
+
selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
|
9
|
+
|
10
|
+
button_attr_exp = xpath_builder.attribute_expression(:button, selectors)
|
11
|
+
|
12
|
+
selectors[:type] = Watir::Button::VALID_TYPES
|
13
|
+
input_attr_exp = xpath_builder.attribute_expression(:input, selectors)
|
14
|
+
|
15
|
+
xpath = ".//button"
|
16
|
+
xpath << "[#{button_attr_exp}]" unless button_attr_exp.empty?
|
17
|
+
xpath << " | .//input"
|
18
|
+
xpath << "[#{input_attr_exp}]"
|
19
|
+
|
20
|
+
p build_wd_selector: xpath if $DEBUG
|
21
|
+
|
22
|
+
[:xpath, xpath]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Button
|
4
|
+
class SelectorBuilder
|
5
|
+
class XPath < Element::SelectorBuilder::XPath
|
6
|
+
def lhs_for(building, key)
|
7
|
+
if building == :input && key == :text
|
8
|
+
"@value"
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def equal_pair(building, key, value)
|
17
|
+
if building == :button && key == :value
|
18
|
+
# :value should look for both node text and @value attribute
|
19
|
+
text = XpathSupport.escape(value)
|
20
|
+
"(text()=#{text} or @value=#{text})"
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Button
|
4
|
+
class Validator < Element::Validator
|
5
|
+
def validate(element, selector)
|
6
|
+
return unless %w[input button].include?(element.tag_name.downcase)
|
7
|
+
return if element.tag_name.downcase == "input" && !Watir::Button::VALID_TYPES.include?(element.attribute(:type))
|
8
|
+
|
9
|
+
element
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Cell
|
4
|
+
class SelectorBuilder < Element::SelectorBuilder
|
5
|
+
def build_wd_selector(selectors)
|
6
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
7
|
+
|
8
|
+
expressions = %w[./th ./td]
|
9
|
+
attr_expr = xpath_builder.attribute_expression(nil, selectors)
|
10
|
+
|
11
|
+
unless attr_expr.empty?
|
12
|
+
expressions.map! { |e| "#{e}[#{attr_expr}]" }
|
13
|
+
end
|
14
|
+
|
15
|
+
xpath = expressions.join(" | ")
|
16
|
+
|
17
|
+
p build_wd_selector: xpath if $DEBUG
|
18
|
+
|
19
|
+
[:xpath, xpath]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Element
|
4
|
+
class Locator
|
5
|
+
attr_reader :selector_builder
|
6
|
+
attr_reader :element_validator
|
7
|
+
|
8
|
+
WD_FINDERS = [
|
9
|
+
:class,
|
10
|
+
:class_name,
|
11
|
+
:css,
|
12
|
+
:id,
|
13
|
+
:link,
|
14
|
+
:link_text,
|
15
|
+
:name,
|
16
|
+
:partial_link_text,
|
17
|
+
:tag_name,
|
18
|
+
:xpath
|
19
|
+
]
|
20
|
+
|
21
|
+
# Regular expressions that can be reliably converted to xpath `contains`
|
22
|
+
# expressions in order to optimize the .
|
23
|
+
CONVERTABLE_REGEXP = %r{
|
24
|
+
\A
|
25
|
+
([^\[\]\\^$.|?*+()]*) # leading literal characters
|
26
|
+
[^|]*? # do not try to convert expressions with alternates
|
27
|
+
([^\[\]\\^$.|?*+()]*) # trailing literal characters
|
28
|
+
\z
|
29
|
+
}x
|
30
|
+
|
31
|
+
def initialize(parent, selector, selector_builder, element_validator)
|
32
|
+
@parent = parent # either element or browser
|
33
|
+
@selector = selector.dup
|
34
|
+
@selector_builder = selector_builder
|
35
|
+
@element_validator = element_validator
|
36
|
+
end
|
37
|
+
|
38
|
+
def locate
|
39
|
+
e = by_id and return e # short-circuit if :id is given
|
40
|
+
|
41
|
+
if @selector.size == 1
|
42
|
+
element = find_first_by_one
|
43
|
+
else
|
44
|
+
element = find_first_by_multiple
|
45
|
+
end
|
46
|
+
|
47
|
+
# This actually only applies when finding by xpath/css - browser.text_field(:xpath, "//input[@type='radio']")
|
48
|
+
# We don't need to validate the element if we built the xpath ourselves.
|
49
|
+
# It is also used to alter behavior of methods locating more than one type of element
|
50
|
+
# (e.g. text_field locates both input and textarea)
|
51
|
+
element_validator.validate(element, @selector) if element
|
52
|
+
rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::StaleElementReferenceError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def locate_all
|
57
|
+
if @selector.size == 1
|
58
|
+
find_all_by_one
|
59
|
+
else
|
60
|
+
find_all_by_multiple
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def by_id
|
67
|
+
return unless id = @selector[:id] and id.is_a? String
|
68
|
+
|
69
|
+
selector = @selector.dup
|
70
|
+
selector.delete(:id)
|
71
|
+
|
72
|
+
tag_name = selector.delete(:tag_name)
|
73
|
+
return unless selector.empty? # multiple attributes
|
74
|
+
|
75
|
+
element = @parent.wd.find_element(:id, id)
|
76
|
+
return if tag_name && !element_validator.validate(element, selector)
|
77
|
+
|
78
|
+
element
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_first_by_one
|
82
|
+
how, what = @selector.to_a.first
|
83
|
+
selector_builder.check_type(how, what)
|
84
|
+
|
85
|
+
if WD_FINDERS.include?(how)
|
86
|
+
wd_find_first_by(how, what)
|
87
|
+
else
|
88
|
+
find_first_by_multiple
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_first_by_multiple
|
93
|
+
selector = selector_builder.normalized_selector
|
94
|
+
|
95
|
+
idx = selector.delete(:index)
|
96
|
+
how, what = selector_builder.build(selector)
|
97
|
+
|
98
|
+
if how
|
99
|
+
# could build xpath/css for selector
|
100
|
+
if idx
|
101
|
+
@parent.wd.find_elements(how, what)[idx]
|
102
|
+
else
|
103
|
+
@parent.wd.find_element(how, what)
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# can't use xpath, probably a regexp in there
|
107
|
+
if idx
|
108
|
+
wd_find_by_regexp_selector(selector, :select)[idx]
|
109
|
+
else
|
110
|
+
wd_find_by_regexp_selector(selector, :find)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_all_by_one
|
116
|
+
how, what = @selector.to_a.first
|
117
|
+
selector_builder.check_type how, what
|
118
|
+
|
119
|
+
if WD_FINDERS.include?(how)
|
120
|
+
wd_find_all_by(how, what)
|
121
|
+
else
|
122
|
+
find_all_by_multiple
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def find_all_by_multiple
|
127
|
+
selector = selector_builder.normalized_selector
|
128
|
+
|
129
|
+
if selector.key? :index
|
130
|
+
raise ArgumentError, "can't locate all elements by :index"
|
131
|
+
end
|
132
|
+
|
133
|
+
how, what = selector_builder.build(selector)
|
134
|
+
if how
|
135
|
+
@parent.wd.find_elements(how, what)
|
136
|
+
else
|
137
|
+
wd_find_by_regexp_selector(selector, :select)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def wd_find_all_by(how, what)
|
142
|
+
if what.is_a? String
|
143
|
+
@parent.wd.find_elements(how, what)
|
144
|
+
else
|
145
|
+
all_elements.select { |element| fetch_value(element, how) =~ what }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def fetch_value(element, how)
|
150
|
+
case how
|
151
|
+
when :text
|
152
|
+
element.text
|
153
|
+
when :tag_name
|
154
|
+
element.tag_name.downcase
|
155
|
+
when :href
|
156
|
+
(href = element.attribute(:href)) && href.strip
|
157
|
+
else
|
158
|
+
element.attribute(how.to_s.tr("_", "-").to_sym)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def all_elements
|
163
|
+
@parent.wd.find_elements(xpath: ".//*")
|
164
|
+
end
|
165
|
+
|
166
|
+
def wd_find_first_by(how, what)
|
167
|
+
if what.is_a? String
|
168
|
+
@parent.wd.find_element(how, what)
|
169
|
+
else
|
170
|
+
all_elements.find { |element| fetch_value(element, how) =~ what }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def wd_find_by_regexp_selector(selector, method = :find)
|
175
|
+
parent = @parent.wd
|
176
|
+
rx_selector = delete_regexps_from(selector)
|
177
|
+
|
178
|
+
if rx_selector.key?(:label) && selector_builder.should_use_label_element?
|
179
|
+
label = label_from_text(rx_selector.delete(:label)) || return
|
180
|
+
if (id = label.attribute(:for))
|
181
|
+
selector[:id] = id
|
182
|
+
else
|
183
|
+
parent = label
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
how, what = selector_builder.build(selector)
|
188
|
+
|
189
|
+
unless how
|
190
|
+
raise Error, "internal error: unable to build WebDriver selector from #{selector.inspect}"
|
191
|
+
end
|
192
|
+
|
193
|
+
if how == :xpath && can_convert_regexp_to_contains?
|
194
|
+
rx_selector.each do |key, value|
|
195
|
+
next if key == :tag_name || key == :text
|
196
|
+
|
197
|
+
predicates = regexp_selector_to_predicates(key, value)
|
198
|
+
what = "(#{what})[#{predicates.join(' and ')}]" unless predicates.empty?
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
elements = parent.find_elements(how, what)
|
203
|
+
elements.__send__(method) { |el| matches_selector?(el, rx_selector) }
|
204
|
+
end
|
205
|
+
|
206
|
+
def delete_regexps_from(selector)
|
207
|
+
rx_selector = {}
|
208
|
+
|
209
|
+
selector.dup.each do |how, what|
|
210
|
+
next unless what.is_a?(Regexp)
|
211
|
+
rx_selector[how] = what
|
212
|
+
selector.delete how
|
213
|
+
end
|
214
|
+
|
215
|
+
rx_selector
|
216
|
+
end
|
217
|
+
|
218
|
+
def label_from_text(label_exp)
|
219
|
+
# TODO: this won't work correctly if @wd is a sub-element
|
220
|
+
@parent.wd.find_elements(:tag_name, 'label').find do |el|
|
221
|
+
matches_selector?(el, text: label_exp)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def matches_selector?(element, selector)
|
226
|
+
selector.all? do |how, what|
|
227
|
+
what === fetch_value(element, how)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def can_convert_regexp_to_contains?
|
232
|
+
true
|
233
|
+
end
|
234
|
+
|
235
|
+
def regexp_selector_to_predicates(key, re)
|
236
|
+
return [] if re.casefold?
|
237
|
+
|
238
|
+
match = re.source.match(CONVERTABLE_REGEXP)
|
239
|
+
return [] unless match
|
240
|
+
|
241
|
+
lhs = selector_builder.xpath_builder.lhs_for(nil, key)
|
242
|
+
match.captures.reject(&:empty?).map do |literals|
|
243
|
+
"contains(#{lhs}, #{XpathSupport.escape(literals)})"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|