lebowski 0.1.1 → 0.2.0

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 (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