druid-ts 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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