lebowski 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/History.md +17 -1
  2. data/Manifest.txt +8 -0
  3. data/README.md +6 -0
  4. data/lib/lebowski/foundation/application.rb +340 -74
  5. data/lib/lebowski/foundation/core.rb +23 -0
  6. data/lib/lebowski/foundation/dom_element.rb +15 -0
  7. data/lib/lebowski/foundation/errors/timeout.rb +5 -0
  8. data/lib/lebowski/foundation/mixins/collection_item_view_support.rb +5 -0
  9. data/lib/lebowski/foundation/mixins/define_paths_support.rb +318 -0
  10. data/lib/lebowski/foundation/mixins/delegate_support.rb +5 -0
  11. data/lib/lebowski/foundation/mixins/frame_application_context_support.rb +37 -0
  12. data/lib/lebowski/foundation/mixins/inline_text_field_support.rb +5 -0
  13. data/lib/lebowski/foundation/mixins/key_check.rb +5 -0
  14. data/lib/lebowski/foundation/mixins/list_item_view_support.rb +5 -0
  15. data/lib/lebowski/foundation/mixins/positioned_element.rb +24 -0
  16. data/lib/lebowski/foundation/mixins/stall_support.rb +5 -0
  17. data/lib/lebowski/foundation/mixins/user_actions.rb +37 -8
  18. data/lib/lebowski/foundation/mixins/wait_actions.rb +5 -0
  19. data/lib/lebowski/foundation/object_array.rb +96 -1
  20. data/lib/lebowski/foundation/proxy_factory.rb +2 -0
  21. data/lib/lebowski/foundation/proxy_object.rb +128 -130
  22. data/lib/lebowski/foundation/views/select_button.rb +69 -0
  23. data/lib/lebowski/foundation/views/view.rb +10 -0
  24. data/lib/lebowski/foundation/views/web.rb +26 -0
  25. data/lib/lebowski/foundation.rb +10 -0
  26. data/lib/lebowski/runtime/errors/remote_control_command_execution_error.rb +5 -0
  27. data/lib/lebowski/runtime/errors/remote_control_command_timeout_error.rb +5 -0
  28. data/lib/lebowski/runtime/errors/remote_control_error.rb +5 -0
  29. data/lib/lebowski/runtime/errors/selenium_server_error.rb +5 -0
  30. data/lib/lebowski/runtime/object_encoder.rb +5 -0
  31. data/lib/lebowski/runtime/sprout_core_driver.rb +5 -0
  32. data/lib/lebowski/runtime/sprout_core_extensions.rb +114 -0
  33. data/lib/lebowski/runtime.rb +5 -0
  34. data/lib/lebowski/scui/mixins/link_support.rb +32 -0
  35. data/lib/lebowski/scui/mixins/node_item_view_support.rb +50 -13
  36. data/lib/lebowski/scui/mixins/terminal_view_support.rb +30 -0
  37. data/lib/lebowski/scui/views/color_well.rb +48 -0
  38. data/lib/lebowski/scui/views/combo_box.rb +90 -87
  39. data/lib/lebowski/scui/views/content_editable.rb +422 -0
  40. data/lib/lebowski/scui/views/date_picker.rb +70 -58
  41. data/lib/lebowski/scui/views/linkit.rb +8 -0
  42. data/lib/lebowski/scui/views/select_field_tab.rb +30 -0
  43. data/lib/lebowski/scui.rb +18 -0
  44. data/lib/lebowski/version.rb +2 -2
  45. data/resources/user-extensions.js +293 -11
  46. metadata +69 -25
@@ -0,0 +1,318 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
6
+ module Lebowski
7
+ module Foundation
8
+
9
+ module Mixins
10
+
11
+ #
12
+ # Mixin provides objects with behavior to define symbolic paths that can be used
13
+ # to help access remote objects
14
+ #
15
+ module DefinePathsSupport
16
+ include Lebowski::Foundation
17
+
18
+ #
19
+ # Defines symbolic path
20
+ #
21
+ # The path given must be a string. The path itself follows a standard dot-path
22
+ # notatition, such as the following examples:
23
+ #
24
+ # "foo"
25
+ # "foo.bar"
26
+ # "foo.bar.mah"
27
+ #
28
+ # You can optionally provide a relative path and an expected type. When a
29
+ # relative path is not provided, then the given path acts as a place holder, which
30
+ # can be useful to organize symbolic paths into groups. If a relative path
31
+ # is provided then it is used to access an actual object in the web browser.
32
+ #
33
+ # If an expected type is provided, then it will be used to check the type of
34
+ # the returned object whenever the defined symbolic path is used to access
35
+ # a remote object. if the object being proxied is not of the expectec type
36
+ # then an exception will be thrown
37
+ #
38
+ # Examples of how to define a path:
39
+ #
40
+ # obj.define_path 'foo' # foo acts as a place holder
41
+ # obj.define_path 'bar', 'x.y.x' # bar is a symolic path for 'x.y.x'
42
+ # obj.define_path 'foo.aaa', 'a.b.c' # aaa is a symbolic path for 'a.b.c'
43
+ # obj.define_path 'foo.bbb', 'm.n.o' # bbb is a symbolic path for 'm.n.o'
44
+ # obj.define_path 'stuff.xxx', 'h.j.k' # xxx is a symbolic path for 'h.j.k'. stuff is a place holder
45
+ # obj.define_path 'mah', 'bar.thing' # mah is a symbolic path for 'x.y.z.thing'. bar is automatically replaced
46
+ #
47
+ def define_path(path, rel_path=nil, expected_type=nil)
48
+ if (not path.kind_of?(String)) or path.empty?
49
+ raise ArgumentError.new "path must be a valid string"
50
+ end
51
+
52
+ current_path_part = root_defined_path_part
53
+
54
+ path_parts = path.split('.')
55
+ counter = 1
56
+ path_parts.each do |part|
57
+ if current_path_part.has_path_part? part
58
+ current_path_part = current_path_part[part]
59
+ else
60
+ if counter == path_parts.length
61
+ current_path_part = current_path_part.add_path_part part, rel_path, expected_type
62
+ else
63
+ current_path_part = current_path_part.add_path_part part
64
+ end
65
+ end
66
+ counter = counter.next
67
+ end
68
+
69
+ return current_path_part
70
+ end
71
+
72
+ #
73
+ # Defines relative symbolic paths for a given symbolic path that has been defined.
74
+ #
75
+ # Use when you are trying to define many symbolic paths that are all
76
+ # relative to another symbolic path that has already been defined. The following
77
+ # is an example of how it is used:
78
+ #
79
+ # obj.define_path 'foo', 'a.b.c' # first define the parent symbolic path
80
+ #
81
+ # obj.define_paths_for 'foo' do |path|
82
+ # # Paths defined are all relative to foo
83
+ # path.define_path 'bar', 'x.y.z'
84
+ # path.define_path 'mah', 'm.n.o'
85
+ # end
86
+ #
87
+ # x = obj['foo.bar'] # path will be converted to actual path 'a.b.c.x.y.z'
88
+ #
89
+ def define_paths_for(path, &block)
90
+ path_part = root_defined_path_part[path]
91
+ if path_part.nil?
92
+ raise ArgumentError.new "can not define paths for #{path} since it has not yet been defined"
93
+ end
94
+
95
+ yield path_part
96
+ end
97
+
98
+ #
99
+ # Checks if a given path has been defined
100
+ #
101
+ def path_defined?(path)
102
+ return (not root_defined_path_part[path].nil?)
103
+ end
104
+
105
+ #
106
+ # Gets a symbolic path object if it has been defined
107
+ #
108
+ def defined_path(path)
109
+ return root_defined_path_part[path]
110
+ end
111
+
112
+ #
113
+ # Returns the root symbolic path object for the given object
114
+ #
115
+ def defined_paths()
116
+ return root_defined_path_part
117
+ end
118
+
119
+ def root_defined_path_part()
120
+ if @root_defined_path_part.nil?
121
+ @root_defined_path_part = Support::DefinedPathPart.new
122
+ end
123
+ return @root_defined_path_part
124
+ end
125
+
126
+ def root_defined_path_part=(path)
127
+ if not path.kind_of? Support::DefinedPathPart
128
+ raise ArgumentInvalidTypeError.new 'part', part, DefinedPathPart
129
+ end
130
+ @root_defined_path_part = path
131
+ end
132
+
133
+ end
134
+
135
+ module Support
136
+
137
+ #
138
+ # Represents a part of a defined path. As an example, if 'foo.bar' was a defined
139
+ # path then the string would be split up an represented as two parts: foo and bar
140
+ # where foo is the parent of bar.
141
+ #
142
+ class DefinedPathPart
143
+ include Lebowski::Foundation
144
+ include DefinePathsSupport
145
+
146
+ attr_reader :name, :parent, :rel_path, :expected_type
147
+
148
+ def initialize(name=nil, parent=nil, rel_path=nil, expected_type=nil)
149
+ @name = name
150
+ @parent = parent
151
+ @rel_path = rel_path
152
+ @expected_type = expected_type
153
+ @child_path_parts = {}
154
+ end
155
+
156
+ #
157
+ # Returns the number of child parts this part has
158
+ #
159
+ def count()
160
+ return @child_path_parts.count
161
+ end
162
+
163
+ #
164
+ # Used to iterate over this part's child parts
165
+ #
166
+ def each(&block)
167
+ @child_path_parts.each do |key, value|
168
+ yield value
169
+ end
170
+ end
171
+
172
+ #
173
+ # Used access a descendent part based on the given string representing
174
+ # relative symbolic path to this part. As an example, if "foo.bar"
175
+ # was provided, the string would be split up and each part of the string
176
+ # would be traversed in order to find the last descendent part. If the
177
+ # given path can not be followed then nil is returned
178
+ #
179
+ def [](value)
180
+ return nil if value.nil?
181
+
182
+ if not value.kind_of? String
183
+ raise ArgumentInvalidTypeError.new 'value', value, String
184
+ end
185
+
186
+ current_path_part = self
187
+ path_parts = value.split('.')
188
+ counter = 1
189
+ path_parts.each do |part|
190
+ current_path_part = current_path_part.child_path_part(part)
191
+ return nil if current_path_part.nil?
192
+ end
193
+ return current_path_part
194
+ end
195
+
196
+ #
197
+ # Add as path part to this object. The part can optionally be
198
+ # associated with a relative path and expected type
199
+ #
200
+ def add_path_part(name, rel_path=nil, expected_type=nil)
201
+ if not name.kind_of? String
202
+ raise ArgumentInvalidTypeError.new 'name', name, String
203
+ end
204
+
205
+ if has_path_part? name
206
+ raise ArgumentError "path part #{name} has already been added"
207
+ end
208
+
209
+ rel_path_parts = (not rel_path.kind_of? String) ? [] : rel_path.split('.')
210
+
211
+ if (not rel_path_parts.empty?) and has_path_part?(rel_path_parts[0])
212
+ rel_path = ""
213
+ rel_path << self[rel_path_parts[0]].full_rel_path
214
+ if (rel_path_parts.length > 1)
215
+ rel_path << "." << rel_path_parts.last(rel_path_parts.length - 1).join('.')
216
+ end
217
+ end
218
+
219
+ path_part = create_path_part(name, self, rel_path, expected_type)
220
+
221
+ @child_path_parts[path_part.name] = path_part
222
+ return path_part
223
+ end
224
+
225
+ #
226
+ # Checks if this part is a root part
227
+ #
228
+ def is_root?()
229
+ return (name.nil? and parent.nil?)
230
+ end
231
+
232
+ #
233
+ # Checks if this part is just a placed holder.
234
+ #
235
+ def is_place_holder?()
236
+ return rel_path.nil?
237
+ end
238
+
239
+ def has_expected_type?()
240
+ return (not expected_type.nil?)
241
+ end
242
+
243
+ #
244
+ # Checks if this part has a child part matching the given value
245
+ #
246
+ def has_path_part?(part)
247
+ if part.kind_of? DefinedPathPart
248
+ part = part.name
249
+ elsif not part.kind_of? String
250
+ raise ArgumentInvalidTypeError.new 'part', part, String, DefinedPathPart
251
+ end
252
+
253
+ return @child_path_parts.has_key?(part)
254
+ end
255
+
256
+ #
257
+ # Will generate a full defined path for this part
258
+ #
259
+ def full_defined_path()
260
+ return nil if is_root?
261
+ return name if parent.is_root?
262
+ return "#{parent.full_defined_path}.#{name}"
263
+ end
264
+
265
+ #
266
+ # Will generate a full relative path for this part. The relative path
267
+ # generated is based on this part and all of its parent parts' relative
268
+ # paths.
269
+ #
270
+ def full_rel_path()
271
+ return nil if rel_path.nil?
272
+
273
+ path = nil
274
+ current_part = self
275
+ while not current_part.nil? do
276
+ if (not current_part.rel_path.nil?)
277
+ if path.nil?
278
+ path = current_part.rel_path
279
+ else
280
+ path = "#{current_part.rel_path}.#{path}"
281
+ end
282
+ end
283
+ current_part = current_part.parent
284
+ end
285
+
286
+ return path
287
+ end
288
+
289
+ def defined_paths()
290
+ return self
291
+ end
292
+
293
+ def to_s()
294
+ return "DefinedPathPart<name=#{name}, rel_path=#{rel_path}, full_defined_path=#{full_defined_path}>"
295
+ end
296
+
297
+ protected
298
+
299
+ def root_defined_path_part()
300
+ return self
301
+ end
302
+
303
+ def child_path_part(part)
304
+ return @child_path_parts[part]
305
+ end
306
+
307
+ def create_path_part(name, parent, rel_path, expected_type)
308
+ return DefinedPathPart.new name, parent, rel_path, expected_type
309
+ end
310
+
311
+ end
312
+
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+ end
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -0,0 +1,37 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
6
+ module Lebowski
7
+ module Foundation
8
+ module Mixins
9
+
10
+ #
11
+ # Mixin is used to provide support to an object that wants to provide a
12
+ # frame application that can be used to acquire application context
13
+ #
14
+ module FrameApplicationContextSupport
15
+ include Lebowski::Foundation
16
+
17
+ def frame()
18
+
19
+ if @frame_app.nil?
20
+ parent_app = Util.get_root_application_object(self)
21
+ @frame_app = FrameApplication.new({
22
+ :parent_app => parent_app,
23
+ :locator => frame_app_context_locator
24
+ })
25
+ end
26
+ return @frame_app
27
+ end
28
+
29
+ def frame_app_context_locator()
30
+ return ''
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
 
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -8,6 +13,25 @@ module Lebowski
8
13
  return Coords.new(0,0)
9
14
  end
10
15
 
16
+ def width()
17
+ return 0
18
+ end
19
+
20
+ def height()
21
+ return 0
22
+ end
23
+
24
+ def position_relative_to(obj)
25
+ if not obj.kind_of? PositionedElement
26
+ raise ArgumentInvalidTypeError.new "obj", obj, PositionedElement
27
+ end
28
+
29
+ x = position.x - obj.position.x
30
+ y = position.y - obj.position.y
31
+
32
+ return Coords.new(x, y)
33
+ end
34
+
11
35
  def scroll_to_visible()
12
36
 
13
37
  end
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8
  module Mixins
@@ -186,16 +191,24 @@ module Lebowski
186
191
  @driver.sc_focus action_target, *action_locator_args
187
192
  end
188
193
 
189
- def drag(x, y, relative_to=nil)
194
+ def drag(x, y, *params)
190
195
  if (not x.kind_of? Integer) or (not y.kind_of? Integer)
191
196
  raise ArgumentError.new "Must supply valid x-y coordinates: x = #{x}, y = #{y}"
192
197
  end
193
198
 
194
- relative_to = relative_to.kind_of?(Hash) ? relative_to[:relative_to] : relative_to
199
+ relative_to = nil
200
+ mouse_offset_x = 0
201
+ mouse_offset_y = 0
202
+
203
+ if params.length > 0 and params[0].kind_of?(Hash)
204
+ relative_to = params[0][:relative_to]
205
+ mouse_offset_x = get_mouse_offset(params[0][:mouse_offset_x], :x)
206
+ mouse_offset_y = get_mouse_offset(params[0][:mouse_offset_y], :y)
207
+ end
195
208
 
196
209
  self.scroll_to_visible
197
- mouse_down_at 0, 0
198
- mouse_move_at 0, 0
210
+ mouse_down_at mouse_offset_x, mouse_offset_y
211
+ mouse_move_at mouse_offset_x, mouse_offset_y
199
212
  relative_to.scroll_to_visible if relative_to.kind_of?(PositionedElement)
200
213
 
201
214
  rel_x = 0
@@ -215,8 +228,8 @@ module Lebowski
215
228
  end
216
229
  end
217
230
 
218
- rel_x = rel_x + x
219
- rel_y = rel_y + y
231
+ rel_x = rel_x + x + mouse_offset_x
232
+ rel_y = rel_y + y + mouse_offset_y
220
233
 
221
234
  mouse_move_at rel_x, rel_y
222
235
  mouse_up_at rel_x, rel_y
@@ -224,7 +237,7 @@ module Lebowski
224
237
  stall :drag
225
238
  end
226
239
 
227
- def drag_to(source, offset_x=nil, offset_y=nil)
240
+ def drag_to(source, offset_x=nil, offset_y=nil, *params)
228
241
  if not (source.kind_of? PositionedElement or source == :window)
229
242
  raise ArgumentError.new "source must be an positioned element: #{source.class}"
230
243
  end
@@ -232,7 +245,13 @@ module Lebowski
232
245
  offset_x = offset_x.nil? ? 0 : offset_x
233
246
  offset_y = offset_y.nil? ? 0 : offset_y
234
247
 
235
- drag offset_x, offset_y, source
248
+ params2 = { :relative_to => source }
249
+ if params.length > 0 and params[0].kind_of? Hash
250
+ params2[:mouse_offset_x] = params[0][:mouse_offset_x]
251
+ params2[:mouse_offset_y] = params[0][:mouse_offset_y]
252
+ end
253
+
254
+ drag offset_x, offset_y, params2
236
255
  end
237
256
 
238
257
  def drag_on_to(source)
@@ -295,6 +314,16 @@ module Lebowski
295
314
  raise ArgumentError.new "#{name} must have collection item view support (#{CollectionItemViewSupport})"
296
315
  end
297
316
  end
317
+
318
+ def get_mouse_offset(offset, coord)
319
+ return 0 if offset.nil?
320
+ if offset == :center
321
+ return (width / 2).floor if (coord == :x)
322
+ return (height / 2).floor if (coord == :y)
323
+ end
324
+ return offset if (offset.kind_of? Integer and offset >= 0)
325
+ raise ArgumentError.new "Invalid offset value: #{offset}"
326
+ end
298
327
 
299
328
  end
300
329
  end
@@ -1,3 +1,8 @@
1
+ # ==========================================================================
2
+ # Project: Lebowski Framework - The SproutCore Test Automation Framework
3
+ # License: Licensed under MIT license (see License.txt)
4
+ # ==========================================================================
5
+
1
6
  module Lebowski
2
7
  module Foundation
3
8