/
locator.rb
163 lines (134 loc) · 4.45 KB
/
locator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
module Watigiri
class Element
attr_reader :element, :selector
def initialize(element:, selector:)
@element = element
@selector = selector
end
def tag_name
element.name.downcase
end
end
module Locators
module LocatorHelpers
def locate
@nokogiri = @selector.delete(:nokogiri)
return super unless @nokogiri || regex?
# :inner_html should be using `#fragment`, but can't because of
# https://github.com/sparklemotion/nokogiri/issues/572
method = @query_scope.is_a?(Watir::Browser) ? :html : :inner_html
@query_scope.doc ||= Nokogiri::HTML(@query_scope.send(method)).tap { |d| d.css('script').remove }
element = using_watir(:first)
return if element.nil?
@nokogiri ? element.element : nokogiri_to_selenium(element)
end
# Is only used when there is no regex, index or visibility locators
def locate_element(how, what, _driver_scope = @query_scope.wd)
return super unless @nokogiri
el = @query_scope.doc.send("at_#{how}", what)
Watigiri::Element.new element: el, selector: {how => what}
end
# "how" can only be :css or :xpath
def locate_elements(how, what, _scope = @query_scope.wd)
return super unless @nokogiri || regex?
@query_scope.doc.send(how, what).map do |el|
Watigiri::Element.new element: el, selector: {how => what}
end
end
def fetch_value(element, how)
element = update_element(element)
return if element.nil?
case how
when :text
element.inner_text
when :tag_name
element.name.to_s.downcase
when :href
element.attribute('href')&.to_s
else
element.attribute(how.to_s.tr('_', '-')).to_s
end
end
def nokogiri_to_selenium(element)
return element if element.is_a?(Selenium::WebDriver::Element)
tag = element.tag_name
index = @query_scope.doc.xpath(".//#{tag}").find_index { |el| el == element.element }
Watir::Element.new(@query_scope, index: index, tag_name: tag).wd
end
def regex?
return @regex unless @regex.nil?
return false unless (@selector.keys & %i[adjacent visible label text visible_text]).empty?
@regex = @selector.values.any? { |v| v.is_a?(Regexp) }
end
def update_element(element)
if !(@nokogiri || regex?) || element.is_a?(Selenium::WebDriver::Element)
nil
elsif element.is_a?(Watigiri::Element)
element.element
else
element
end
end
end
class Element
class Locator < Watir::Locators::Element::Locator
include LocatorHelpers
end
end
class Button
class Locator < Watir::Locators::Button::Locator
include LocatorHelpers
end
end
class Cell
class Locator < Watir::Locators::Cell::Locator
include LocatorHelpers
# Don't use for rows
def regex?
false
end
end
end
class Row
class Locator < Watir::Locators::Row::Locator
include LocatorHelpers
# Don't use for rows
def regex?
false
end
end
end
class TextArea
class Locator < Watir::Locators::TextArea::Locator
include LocatorHelpers
def regex?
return false unless (@selector.keys & %i[adjacent visible label text visible_text]).empty?
@selector.any? { |k, v| v.is_a?(Regexp) && k != :value }
end
end
end
class TextField
class Locator < Watir::Locators::TextField::Locator
include LocatorHelpers
def matches_selector?(element, rx_selector)
return super if element.is_a? Selenium::WebDriver::Element
rx_selector = rx_selector.dup
tag_name = element.tag_name
%i[text value label].each do |key|
next unless rx_selector.key?(key)
correct_key = tag_name == 'input' ? :value : :text
rx_selector[correct_key] = rx_selector.delete(key)
end
rx_selector.all? do |how, what|
val = fetch_value(element, how)
what == val || val =~ /#{what}/
end
end
def regex?
return false unless (@selector.keys & %i[adjacent visible label text visible_text]).empty?
@selector.any? { |k, v| v.is_a?(Regexp) && k != :value }
end
end
end
end
end