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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +27 -0
  3. data/features/async.feature +6 -0
  4. data/features/div.feature +1 -0
  5. data/features/element.feature +4 -0
  6. data/features/hidden_field.feature +0 -2
  7. data/features/html/async.html +13 -0
  8. data/features/html/multi_elements.html +4 -0
  9. data/features/html/static_elements.html +10 -3
  10. data/features/link.feature +1 -0
  11. data/features/multi_elements.feature +135 -25
  12. data/features/select_list.feature +8 -0
  13. data/features/span.feature +2 -0
  14. data/features/step_definations/async_steps.rb +17 -0
  15. data/features/step_definations/element_steps.rb +6 -0
  16. data/features/step_definations/multi_elements_steps.rb +96 -0
  17. data/features/step_definations/select_list_steps.rb +12 -0
  18. data/features/step_definations/table_steps.rb +20 -3
  19. data/features/support/ajax_test_environment.rb +1 -1
  20. data/features/support/page.rb +7 -2
  21. data/features/table.feature +35 -0
  22. data/features/text_area.feature +0 -2
  23. data/features/text_field.feature +1 -2
  24. data/lib/druid.rb +31 -3
  25. data/lib/druid/accessors.rb +184 -146
  26. data/lib/druid/assist.rb +10 -2
  27. data/lib/druid/element_locators.rb +186 -102
  28. data/lib/druid/elements/div.rb +1 -1
  29. data/lib/druid/elements/element.rb +131 -96
  30. data/lib/druid/elements/hidden_field.rb +1 -5
  31. data/lib/druid/elements/link.rb +1 -1
  32. data/lib/druid/elements/select_list.rb +8 -0
  33. data/lib/druid/elements/span.rb +1 -1
  34. data/lib/druid/elements/table.rb +14 -3
  35. data/lib/druid/elements/table_row.rb +17 -2
  36. data/lib/druid/elements/text_area.rb +0 -8
  37. data/lib/druid/elements/text_field.rb +1 -1
  38. data/lib/druid/javascript/yui.rb +19 -0
  39. data/lib/druid/javascript_framework_facade.rb +3 -1
  40. data/lib/druid/nested_elements.rb +1 -1
  41. data/lib/druid/page_factory.rb +25 -0
  42. data/lib/druid/page_populator.rb +1 -0
  43. data/lib/druid/version.rb +1 -1
  44. data/spec/druid/accessors_spec.rb +189 -1
  45. data/spec/druid/druid_spec.rb +6 -0
  46. data/spec/druid/element_locators_spec.rb +276 -0
  47. data/spec/druid/elements/div_spec.rb +1 -1
  48. data/spec/druid/elements/element_spec.rb +11 -0
  49. data/spec/druid/elements/hidden_field_spec.rb +0 -5
  50. data/spec/druid/elements/link_spec.rb +1 -1
  51. data/spec/druid/elements/span_spec.rb +1 -1
  52. data/spec/druid/elements/text_area_spec.rb +0 -5
  53. data/spec/druid/elements/text_field_spec.rb +1 -1
  54. data/spec/druid/page_factory_spec.rb +20 -0
  55. data/spec/druid/page_populator_spec.rb +8 -4
  56. metadata +2 -1
@@ -3,7 +3,7 @@ module Druid
3
3
  class Div < Element
4
4
 
5
5
  def self.finders
6
- [:class, :id, :text, :index, :xpath]
6
+ super + [:text, :title]
7
7
  end
8
8
  end
9
9
 
@@ -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] (default to:5) seconds to wait before timing out
166
+ # @param [Integer] (defaults to: 5) seconds to wait before
167
+ # timing out
245
168
  #
246
- def when_present(timeout=5)
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=5)
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=5)
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=5, message=nil, &block)
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
@@ -7,11 +7,7 @@ module Druid
7
7
  end
8
8
 
9
9
  def self.finders
10
- super + [:tag_name, :text, :value]
11
- end
12
-
13
- def self.mapping
14
- super.merge({:css => :tag_name})
10
+ super + [:text, :value]
15
11
  end
16
12
 
17
13
  end
@@ -5,7 +5,7 @@ module Druid
5
5
  protected
6
6
 
7
7
  def self.finders
8
- super + [:href, :text, :css]
8
+ super + [:href, :text, :css, :title]
9
9
  end
10
10
 
11
11
  def self.mapping
@@ -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
  #
@@ -3,7 +3,7 @@ module Druid
3
3
  class Span < Element
4
4
 
5
5
  def self.finders
6
- [:class, :id, :index, :xpath, :text]
6
+ [:class, :id, :index, :xpath, :text, :title]
7
7
  end
8
8
 
9
9
  end
@@ -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
- table_row = element[idx]
12
- Druid::Elements::TableRow.new(table_row)
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
- table_cell = element[idx]
6
- Druid::Elements::TableCell.new(table_cell)
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
@@ -2,14 +2,6 @@ module Druid
2
2
  module Elements
3
3
  class TextArea < Element
4
4
 
5
- def self.finders
6
- super + [:tag_name]
7
- end
8
-
9
- def self.mapping
10
- super.merge({:css => :tag_name})
11
- end
12
-
13
5
  #
14
6
  # Set the value of the TextArea
15
7
  #
@@ -3,7 +3,7 @@ module Druid
3
3
  class TextField < Element
4
4
 
5
5
  def self.finders
6
- super + [:css, :tag_name, :text, :title]
6
+ super + [:text, :title, :label]
7
7
  end
8
8
 
9
9
  #
@@ -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