druid-ts 1.1.3 → 1.1.4
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/ChangeLog +27 -0
- data/features/async.feature +6 -0
- data/features/div.feature +1 -0
- data/features/element.feature +4 -0
- data/features/hidden_field.feature +0 -2
- data/features/html/async.html +13 -0
- data/features/html/multi_elements.html +4 -0
- data/features/html/static_elements.html +10 -3
- data/features/link.feature +1 -0
- data/features/multi_elements.feature +135 -25
- data/features/select_list.feature +8 -0
- data/features/span.feature +2 -0
- data/features/step_definations/async_steps.rb +17 -0
- data/features/step_definations/element_steps.rb +6 -0
- data/features/step_definations/multi_elements_steps.rb +96 -0
- data/features/step_definations/select_list_steps.rb +12 -0
- data/features/step_definations/table_steps.rb +20 -3
- data/features/support/ajax_test_environment.rb +1 -1
- data/features/support/page.rb +7 -2
- data/features/table.feature +35 -0
- data/features/text_area.feature +0 -2
- data/features/text_field.feature +1 -2
- data/lib/druid.rb +31 -3
- data/lib/druid/accessors.rb +184 -146
- data/lib/druid/assist.rb +10 -2
- data/lib/druid/element_locators.rb +186 -102
- data/lib/druid/elements/div.rb +1 -1
- data/lib/druid/elements/element.rb +131 -96
- data/lib/druid/elements/hidden_field.rb +1 -5
- data/lib/druid/elements/link.rb +1 -1
- data/lib/druid/elements/select_list.rb +8 -0
- data/lib/druid/elements/span.rb +1 -1
- data/lib/druid/elements/table.rb +14 -3
- data/lib/druid/elements/table_row.rb +17 -2
- data/lib/druid/elements/text_area.rb +0 -8
- data/lib/druid/elements/text_field.rb +1 -1
- data/lib/druid/javascript/yui.rb +19 -0
- data/lib/druid/javascript_framework_facade.rb +3 -1
- data/lib/druid/nested_elements.rb +1 -1
- data/lib/druid/page_factory.rb +25 -0
- data/lib/druid/page_populator.rb +1 -0
- data/lib/druid/version.rb +1 -1
- data/spec/druid/accessors_spec.rb +189 -1
- data/spec/druid/druid_spec.rb +6 -0
- data/spec/druid/element_locators_spec.rb +276 -0
- data/spec/druid/elements/div_spec.rb +1 -1
- data/spec/druid/elements/element_spec.rb +11 -0
- data/spec/druid/elements/hidden_field_spec.rb +0 -5
- data/spec/druid/elements/link_spec.rb +1 -1
- data/spec/druid/elements/span_spec.rb +1 -1
- data/spec/druid/elements/text_area_spec.rb +0 -5
- data/spec/druid/elements/text_field_spec.rb +1 -1
- data/spec/druid/page_factory_spec.rb +20 -0
- data/spec/druid/page_populator_spec.rb +8 -4
- metadata +2 -1
data/lib/druid/elements/div.rb
CHANGED
@@ -17,91 +17,6 @@ module Druid
|
|
17
17
|
@driver = @element
|
18
18
|
end
|
19
19
|
|
20
|
-
# @private
|
21
|
-
def self.identifier_for identifier
|
22
|
-
if have_to_build_xpath(identifier)
|
23
|
-
how = :xpath
|
24
|
-
what = build_xpath_for(identifier)
|
25
|
-
return how => what
|
26
|
-
else
|
27
|
-
all_identities = {}
|
28
|
-
identifier.each do |key, value|
|
29
|
-
each = {key => value}
|
30
|
-
ident = identifier_for_element each, finders, mapping
|
31
|
-
all_identities[ident.keys.first] = ident.values.first
|
32
|
-
end
|
33
|
-
all_identities
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.have_to_build_xpath(identifier)
|
38
|
-
['table', 'span', 'div', 'td', 'li', 'ol', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'label'].include? identifier[:tag_name] and identifier[:name]
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.build_xpath_for identifier
|
42
|
-
tag_locator = identifier.delete(:tag_name)
|
43
|
-
idx = identifier.delete(:index)
|
44
|
-
identifier.delete(:tag_name)
|
45
|
-
xpath = ".//#{tag_locator}"
|
46
|
-
xpath << "[#{attribute_expression(identifier)}]" unless identifier.empty?
|
47
|
-
xpath << "[#{idx+1}]" if idx
|
48
|
-
xpath
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.attribute_expression(identifier)
|
52
|
-
identifier.map do |key, value|
|
53
|
-
if value.kind_of?(Array)
|
54
|
-
"(" + value.map { |v| equal_pair(key, v) }.join(" or ") + ")"
|
55
|
-
else
|
56
|
-
equal_pair(key, value)
|
57
|
-
end
|
58
|
-
end.join(" and ")
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.equal_pair(key, value)
|
62
|
-
if key == :label
|
63
|
-
"@id=//label[normalize-space()=#{xpath_string(value)}]/@for"
|
64
|
-
else
|
65
|
-
"#{lhs_for(key)}=#{xpath_string(value)}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.lhs_for(key)
|
70
|
-
case key
|
71
|
-
when :text, 'text'
|
72
|
-
'normalize-space()'
|
73
|
-
when :href
|
74
|
-
'normalize-space(@href)'
|
75
|
-
else
|
76
|
-
"@#{key.to_s.gsub("_", "-")}"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.xpath_string(value)
|
81
|
-
if value.include? "'"
|
82
|
-
parts = value.split("'", -1).map { |part| "'#{part}'" }
|
83
|
-
string = parts.join(%{,"'",})
|
84
|
-
"concat(#{string})"
|
85
|
-
else
|
86
|
-
"'#{value}'"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.identifier_for_element identifier, find_by, find_by_mapping
|
91
|
-
how, what = identifier.keys.first, identifier.values.first
|
92
|
-
return how => what if find_by.include? how
|
93
|
-
return find_by_mapping[how] => what if find_by_mapping[how]
|
94
|
-
return nil => what
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.finders
|
98
|
-
[:class, :id, :index, :name, :xpath]
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.mapping
|
102
|
-
{}
|
103
|
-
end
|
104
|
-
|
105
20
|
#
|
106
21
|
# Get the text for the element
|
107
22
|
#
|
@@ -229,6 +144,13 @@ module Druid
|
|
229
144
|
element.focus
|
230
145
|
end
|
231
146
|
|
147
|
+
#
|
148
|
+
# Flash the element by temporarily changing the background color
|
149
|
+
#
|
150
|
+
def flash
|
151
|
+
element.flash
|
152
|
+
end
|
153
|
+
|
232
154
|
#
|
233
155
|
# Returns parent element of current element.
|
234
156
|
def parent
|
@@ -241,19 +163,30 @@ module Druid
|
|
241
163
|
#
|
242
164
|
# Waits until the element is present
|
243
165
|
#
|
244
|
-
# @param [Integer] (
|
166
|
+
# @param [Integer] (defaults to: 5) seconds to wait before
|
167
|
+
# timing out
|
245
168
|
#
|
246
|
-
def when_present(timeout=
|
169
|
+
def when_present(timeout=Druid.default_element_wait)
|
247
170
|
element.wait_until_present(timeout)
|
248
171
|
self
|
249
172
|
end
|
250
173
|
|
174
|
+
#
|
175
|
+
# Waits until the element is not present
|
176
|
+
#
|
177
|
+
# @param [Integer] (defaults to: 5) seconds to wait before
|
178
|
+
# timing out
|
179
|
+
#
|
180
|
+
def when_not_present(timeout=Druid.default_element_wait)
|
181
|
+
element.wait_while_present(timeout)
|
182
|
+
end
|
183
|
+
|
251
184
|
#
|
252
185
|
# Waits until the element is visible
|
253
186
|
#
|
254
187
|
# @param [Interger] (default to:5) seconds to wait before timing out
|
255
188
|
#
|
256
|
-
def when_visible(timeout=
|
189
|
+
def when_visible(timeout=Druid.default_element_wait)
|
257
190
|
Watir::Wait.until(timeout, "Element was not visible in #{timeout} seconds") do
|
258
191
|
visible?
|
259
192
|
end
|
@@ -265,7 +198,7 @@ module Druid
|
|
265
198
|
#
|
266
199
|
# @param [Integer] (default to:5) seconds to wait before timing out
|
267
200
|
#
|
268
|
-
def when_not_visible(timeout=
|
201
|
+
def when_not_visible(timeout=Druid.default_element_wait)
|
269
202
|
Watir::Wait.while(timeout, "Element still visible after #{timeout} seconds") do
|
270
203
|
visible?
|
271
204
|
end
|
@@ -277,24 +210,126 @@ module Druid
|
|
277
210
|
#
|
278
211
|
# @param [Integer] (default to:5) seconds to wait before timing out
|
279
212
|
#
|
280
|
-
def wait_until(timeout=
|
213
|
+
def wait_until(timeout=Druid.default_element_wait, message=nil, &block)
|
281
214
|
Watir::Wait.until(timeout, message, &block)
|
282
215
|
end
|
283
216
|
|
217
|
+
|
218
|
+
# @private
|
219
|
+
def self.identifier_for identifier
|
220
|
+
if have_to_build_xpath(identifier)
|
221
|
+
how = :xpath
|
222
|
+
what = build_xpath_for(identifier)
|
223
|
+
return how => what
|
224
|
+
end
|
225
|
+
all_identities = {}
|
226
|
+
identifier.each do |key, value|
|
227
|
+
each = {key => value}
|
228
|
+
ident = identifier_for_element each, finders, mapping
|
229
|
+
all_identities[ident.keys.first] = ident.values.first
|
230
|
+
end
|
231
|
+
all_identities
|
232
|
+
# end
|
233
|
+
end
|
234
|
+
|
284
235
|
# @private
|
285
236
|
# delegate calls to driver element
|
286
237
|
def method_missing(m, *args, &block)
|
287
|
-
puts "*** DEPRECATION WARNING"
|
288
|
-
puts "*** You are calling a method named #{m} at #{caller[0]}."
|
289
|
-
puts "*** This method does not exist in druid so it is being passed to the driver."
|
290
|
-
puts "*** This feature will be removed in the near future."
|
291
|
-
puts "*** Please change your code to call the correct druid method."
|
292
|
-
puts "*** If you are using functionality that does not exist in druid please request it be added."
|
238
|
+
$stderr.puts "*** DEPRECATION WARNING"
|
239
|
+
$stderr.puts "*** You are calling a method named #{m} at #{caller[0]}."
|
240
|
+
$stderr.puts "*** This method does not exist in druid so it is being passed to the driver."
|
241
|
+
$stderr.puts "*** This feature will be removed in the near future."
|
242
|
+
$stderr.puts "*** Please change your code to call the correct druid method."
|
243
|
+
$stderr.puts "*** If you are using functionality that does not exist in druid please request it be added."
|
293
244
|
unless element.respond_to?(m)
|
294
245
|
raise NoMethodError, "undefined method `#{m}` for #{element.inspect}:#{element.class}"
|
295
246
|
end
|
296
247
|
element.__send__(m, *args, &block)
|
297
248
|
end
|
249
|
+
|
250
|
+
protected
|
251
|
+
|
252
|
+
def self.have_to_build_xpath(identifier)
|
253
|
+
['table', 'span', 'div', 'td', 'li', 'ol', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'label'].include? identifier[:tag_name] and identifier[:name]
|
254
|
+
end
|
255
|
+
|
256
|
+
def self.build_xpath_for identifier
|
257
|
+
tag_locator = identifier.delete(:tag_name)
|
258
|
+
idx = identifier.delete(:index)
|
259
|
+
if tag_locator == 'input' and identifier[:type] == 'submit'
|
260
|
+
identifier.delete(:type)
|
261
|
+
btn_ident = identifier.clone
|
262
|
+
if btn_ident[:value]
|
263
|
+
btn_ident[:text] = btn_ident[:value]
|
264
|
+
btn_ident.delete(:value)
|
265
|
+
end
|
266
|
+
xpath = ".//button"
|
267
|
+
xpath << "[#{attribute_expression(btn_ident)}]" unless btn_ident.empty?
|
268
|
+
xpath << "[#{idx+1}]" if idx
|
269
|
+
identifier[:type] = %w[button reset submit image]
|
270
|
+
xpath << " | .//input"
|
271
|
+
else
|
272
|
+
xpath = ".//#{tag_locator}"
|
273
|
+
end
|
274
|
+
xpath << "[#{attribute_expression(identifier)}]" unless identifier.empty?
|
275
|
+
xpath << "[#{idx+1}]" if idx
|
276
|
+
xpath
|
277
|
+
end
|
278
|
+
|
279
|
+
def self.attribute_expression(identifier)
|
280
|
+
identifier.map do |key, value|
|
281
|
+
if value.kind_of?(Array)
|
282
|
+
"(" + value.map { |v| equal_pair(key, v) }.join(" or ") + ")"
|
283
|
+
else
|
284
|
+
equal_pair(key, value)
|
285
|
+
end
|
286
|
+
end.join(" and ")
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.equal_pair(key, value)
|
290
|
+
if key == :label
|
291
|
+
"@id=//label[normalize-space()=#{xpath_string(value)}]/@for"
|
292
|
+
else
|
293
|
+
"#{lhs_for(key)}=#{xpath_string(value)}"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.lhs_for(key)
|
298
|
+
case key
|
299
|
+
when :text, 'text'
|
300
|
+
'normalize-space()'
|
301
|
+
when :href
|
302
|
+
'normalize-space(@href)'
|
303
|
+
else
|
304
|
+
"@#{key.to_s.gsub("_", "-")}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def self.xpath_string(value)
|
309
|
+
if value.include? "'"
|
310
|
+
parts = value.split("'", -1).map { |part| "'#{part}'" }
|
311
|
+
string = parts.join(%{,"'",})
|
312
|
+
"concat(#{string})"
|
313
|
+
else
|
314
|
+
"'#{value}'"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.identifier_for_element identifier, find_by, find_by_mapping
|
319
|
+
how, what = identifier.keys.first, identifier.values.first
|
320
|
+
return how => what if find_by.include? how
|
321
|
+
return find_by_mapping[how] => what if find_by_mapping[how]
|
322
|
+
return nil => what
|
323
|
+
end
|
324
|
+
|
325
|
+
def self.finders
|
326
|
+
[:class, :id, :index, :name, :xpath]
|
327
|
+
end
|
328
|
+
|
329
|
+
def self.mapping
|
330
|
+
{}
|
331
|
+
end
|
332
|
+
|
298
333
|
end
|
299
334
|
end
|
300
335
|
end
|
data/lib/druid/elements/link.rb
CHANGED
@@ -21,6 +21,14 @@ module Druid
|
|
21
21
|
element.select(value)
|
22
22
|
end
|
23
23
|
|
24
|
+
#
|
25
|
+
# Select the options whose value attribute matches the Given
|
26
|
+
# string
|
27
|
+
#
|
28
|
+
def select_value(value)
|
29
|
+
element.select_value(value)
|
30
|
+
end
|
31
|
+
|
24
32
|
#
|
25
33
|
# @return [Array<sTRING>] An array of strings representing the text value of the currently selected options.
|
26
34
|
#
|
data/lib/druid/elements/span.rb
CHANGED
data/lib/druid/elements/table.rb
CHANGED
@@ -3,13 +3,16 @@ module Druid
|
|
3
3
|
class Table < Element
|
4
4
|
#
|
5
5
|
# Return the Druid::Elements::Table for the index provided. Index
|
6
|
-
# is zero based.
|
6
|
+
# is zero based. If the index provided is a String then it
|
7
|
+
# will be matched with the text from any column. The text can be
|
8
|
+
# a substring of the full column text.
|
7
9
|
#
|
8
10
|
# @return [Druid::Elements::Table]
|
9
11
|
#
|
10
12
|
def [](idx)
|
11
|
-
|
12
|
-
|
13
|
+
idx = find_index_by_title(idx) if idx.kind_of?(String)
|
14
|
+
return nil unless idx
|
15
|
+
Druid::Elements::TableRow.new(element[idx])
|
13
16
|
end
|
14
17
|
#
|
15
18
|
# Returns the number of rows in the table.
|
@@ -42,6 +45,14 @@ module Druid
|
|
42
45
|
self[-1]
|
43
46
|
end
|
44
47
|
|
48
|
+
private
|
49
|
+
|
50
|
+
def find_index_by_title(row_title)
|
51
|
+
element.rows.find_index do |row|
|
52
|
+
row.cells.any? { |col| col.text.include? row_title}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
45
56
|
end
|
46
57
|
|
47
58
|
Druid::Elements.tag_to_class[:table] = Druid::Elements::Table
|
@@ -1,9 +1,16 @@
|
|
1
1
|
module Druid
|
2
2
|
module Elements
|
3
3
|
class TableRow < Element
|
4
|
+
|
5
|
+
#
|
6
|
+
# Return the Druid::Elements::TableCell for the index provided. Index
|
7
|
+
# is zero based. If the index provided is a String then it
|
8
|
+
# will be matched with the text from the columns in the first row.
|
9
|
+
#
|
4
10
|
def [](idx)
|
5
|
-
|
6
|
-
|
11
|
+
idx = find_index_by_title(idx) if idx.kind_of?(String)
|
12
|
+
return nil unless idx
|
13
|
+
Druid::Elements::TableCell.new(element[idx])
|
7
14
|
end
|
8
15
|
#
|
9
16
|
# Returns the number of rows in the table.
|
@@ -18,6 +25,14 @@ module Druid
|
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
28
|
+
private
|
29
|
+
|
30
|
+
def find_index_by_title(title)
|
31
|
+
table = element.parent
|
32
|
+
first_row = table[0]
|
33
|
+
first_row.cells.find_index { |column| column.text.include? title}
|
34
|
+
end
|
35
|
+
|
21
36
|
end
|
22
37
|
|
23
38
|
Druid::Elements.tag_to_class[:tr] = Druid::Elements::TableRow
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Druid
|
2
|
+
module Javascript
|
3
|
+
|
4
|
+
module YUI
|
5
|
+
#
|
6
|
+
# return the number of pending ajax requests
|
7
|
+
#
|
8
|
+
def self.pending_requests
|
9
|
+
"var inProgress=0
|
10
|
+
for(var i=0; i < YAHOO.util.Connect._transaction_id; i++) {
|
11
|
+
if(YAHOO.util.Connect.isCallInProgress(i))
|
12
|
+
inProgress++;
|
13
|
+
}
|
14
|
+
return inProgress;"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|