lebowski 0.1.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.
- data/History.md +3 -0
- data/License.txt +20 -0
- data/Manifest.txt +84 -0
- data/README.md +146 -0
- data/Rakefile +42 -0
- data/bin/lebowski +26 -0
- data/bin/lebowski-spec +29 -0
- data/bin/lebowski-start-server +24 -0
- data/lib/lebowski.rb +15 -0
- data/lib/lebowski/core.rb +35 -0
- data/lib/lebowski/foundation.rb +52 -0
- data/lib/lebowski/foundation/application.rb +315 -0
- data/lib/lebowski/foundation/core.rb +61 -0
- data/lib/lebowski/foundation/core_query.rb +231 -0
- data/lib/lebowski/foundation/dom_element.rb +114 -0
- data/lib/lebowski/foundation/errors/argument_invalid_type.rb +31 -0
- data/lib/lebowski/foundation/errors/unexpected_type.rb +30 -0
- data/lib/lebowski/foundation/mixins/collection_item_view_support.rb +87 -0
- data/lib/lebowski/foundation/mixins/delegate_support.rb +22 -0
- data/lib/lebowski/foundation/mixins/inline_text_field_support.rb +29 -0
- data/lib/lebowski/foundation/mixins/key_check.rb +35 -0
- data/lib/lebowski/foundation/mixins/list_item_view_support.rb +36 -0
- data/lib/lebowski/foundation/mixins/positioned_element.rb +20 -0
- data/lib/lebowski/foundation/mixins/stall_support.rb +79 -0
- data/lib/lebowski/foundation/mixins/user_actions.rb +302 -0
- data/lib/lebowski/foundation/mixins/wait_actions.rb +44 -0
- data/lib/lebowski/foundation/object_array.rb +305 -0
- data/lib/lebowski/foundation/panes/alert.rb +117 -0
- data/lib/lebowski/foundation/panes/main.rb +20 -0
- data/lib/lebowski/foundation/panes/menu.rb +100 -0
- data/lib/lebowski/foundation/panes/modal.rb +21 -0
- data/lib/lebowski/foundation/panes/palette.rb +21 -0
- data/lib/lebowski/foundation/panes/pane.rb +24 -0
- data/lib/lebowski/foundation/panes/panel.rb +25 -0
- data/lib/lebowski/foundation/panes/picker.rb +43 -0
- data/lib/lebowski/foundation/panes/sheet.rb +21 -0
- data/lib/lebowski/foundation/proxy_factory.rb +87 -0
- data/lib/lebowski/foundation/proxy_object.rb +670 -0
- data/lib/lebowski/foundation/sc_object.rb +38 -0
- data/lib/lebowski/foundation/views/button.rb +20 -0
- data/lib/lebowski/foundation/views/checkbox.rb +63 -0
- data/lib/lebowski/foundation/views/collection.rb +304 -0
- data/lib/lebowski/foundation/views/container.rb +32 -0
- data/lib/lebowski/foundation/views/disclosure.rb +59 -0
- data/lib/lebowski/foundation/views/grid.rb +21 -0
- data/lib/lebowski/foundation/views/label.rb +30 -0
- data/lib/lebowski/foundation/views/list.rb +67 -0
- data/lib/lebowski/foundation/views/list_item.rb +280 -0
- data/lib/lebowski/foundation/views/menu_item.rb +27 -0
- data/lib/lebowski/foundation/views/radio.rb +32 -0
- data/lib/lebowski/foundation/views/segmented.rb +97 -0
- data/lib/lebowski/foundation/views/select_field.rb +139 -0
- data/lib/lebowski/foundation/views/support/simple_item_array.rb +249 -0
- data/lib/lebowski/foundation/views/text_field.rb +108 -0
- data/lib/lebowski/foundation/views/view.rb +108 -0
- data/lib/lebowski/runtime.rb +7 -0
- data/lib/lebowski/runtime/errors/remote_control_command_execution_error.rb +9 -0
- data/lib/lebowski/runtime/errors/remote_control_command_timeout_error.rb +9 -0
- data/lib/lebowski/runtime/errors/remote_control_error.rb +9 -0
- data/lib/lebowski/runtime/errors/selenium_server_error.rb +9 -0
- data/lib/lebowski/runtime/object_encoder.rb +123 -0
- data/lib/lebowski/runtime/sprout_core_driver.rb +14 -0
- data/lib/lebowski/runtime/sprout_core_extensions.rb +600 -0
- data/lib/lebowski/scui.rb +18 -0
- data/lib/lebowski/scui/mixins/node_item_view_support.rb +136 -0
- data/lib/lebowski/scui/mixins/terminal_view_support.rb +25 -0
- data/lib/lebowski/scui/views/combo_box.rb +119 -0
- data/lib/lebowski/scui/views/date_picker.rb +148 -0
- data/lib/lebowski/scui/views/linkit.rb +36 -0
- data/lib/lebowski/spec.rb +17 -0
- data/lib/lebowski/spec/core.rb +21 -0
- data/lib/lebowski/spec/matchers/be.rb +63 -0
- data/lib/lebowski/spec/matchers/has.rb +40 -0
- data/lib/lebowski/spec/matchers/match_supporters/has_object_function.rb +67 -0
- data/lib/lebowski/spec/matchers/match_supporters/has_predicate_with_no_prefix.rb +50 -0
- data/lib/lebowski/spec/matchers/match_supporters/has_predicate_with_prefix_has.rb +50 -0
- data/lib/lebowski/spec/matchers/match_supporters/match_supporter.rb +29 -0
- data/lib/lebowski/spec/matchers/method_missing.rb +24 -0
- data/lib/lebowski/spec/operators/operator.rb +20 -0
- data/lib/lebowski/spec/operators/that.rb +116 -0
- data/lib/lebowski/spec/util.rb +26 -0
- data/lib/lebowski/version.rb +17 -0
- data/resources/selenium-server.jar +0 -0
- data/resources/user-extensions.js +1421 -0
- metadata +198 -0
@@ -0,0 +1,114 @@
|
|
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
|
+
#
|
10
|
+
# Represents a DOM element. Primarily used by the CoreQuery object. Use this
|
11
|
+
# object to acquire details about a given element.
|
12
|
+
#
|
13
|
+
class DOMElement
|
14
|
+
include Lebowski::Foundation::Mixins::UserActions
|
15
|
+
|
16
|
+
attr_reader :handle,
|
17
|
+
:index
|
18
|
+
|
19
|
+
#
|
20
|
+
# Create an instance.
|
21
|
+
#
|
22
|
+
# @param handle {Number} the handle used by a core query object
|
23
|
+
# @param index {Number} the index to the element in the core query object
|
24
|
+
# @param driver {object} used to communicate with the selenium server
|
25
|
+
#
|
26
|
+
def initialize(handle, index, driver)
|
27
|
+
@handle = handle
|
28
|
+
@index = index
|
29
|
+
@driver = driver
|
30
|
+
end
|
31
|
+
|
32
|
+
def action_locator_args()
|
33
|
+
return [@handle, @index]
|
34
|
+
end
|
35
|
+
|
36
|
+
def action_target()
|
37
|
+
return :core_query_element
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns the classes of the element as a string
|
42
|
+
#
|
43
|
+
def classes()
|
44
|
+
return @driver.get_sc_core_query_element_classes(@handle, @index)
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Checks if this DOM element has a given CSS class
|
49
|
+
#
|
50
|
+
# @return true if the element has the class, otherwise false is returned
|
51
|
+
#
|
52
|
+
def has_class?(klass)
|
53
|
+
return has_classes? [klass]
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Checks if this DOM element has a set of given CSS classes
|
58
|
+
#
|
59
|
+
# @return true if the element has all teh given classes, otherwise false is returned
|
60
|
+
#
|
61
|
+
def has_classes?(klasses)
|
62
|
+
klasses1 = klasses.kind_of?(Array) ? klasses : klasses.split
|
63
|
+
klasses2 = classes.split
|
64
|
+
for k in klasses1 do
|
65
|
+
if not klasses2.find_index(k)
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Returns the raw HTML of this element as a string
|
74
|
+
#
|
75
|
+
def html()
|
76
|
+
return @driver.get_sc_core_query_element_html(@handle, @index)
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Returns the text of this element
|
81
|
+
#
|
82
|
+
def text()
|
83
|
+
return @driver.get_sc_core_query_element_text(@handle, @index)
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Returns the HTML tag of this element (e.g. IMG, A, DIV)
|
88
|
+
#
|
89
|
+
def tag()
|
90
|
+
return @driver.get_sc_core_query_element_tag(@handle, @index)
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Used to get the value of specific attribute belonging to the element
|
95
|
+
#
|
96
|
+
# @param val {String} the name of the attribute on the element
|
97
|
+
#
|
98
|
+
def attribute(val)
|
99
|
+
return @driver.get_sc_core_query_element_attribute(@handle, @index, val)
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# If the method can not be found then assume we are trying to get the value
|
104
|
+
# of an attribute on the element.
|
105
|
+
#
|
106
|
+
def method_missing(sym, *args, &block)
|
107
|
+
return attribute(sym.to_s) if not sym.to_s =~ /\?$/
|
108
|
+
super
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,31 @@
|
|
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
|
+
class ArgumentInvalidTypeError < Exception
|
10
|
+
|
11
|
+
def initialize(arg_name, value, *expected_types)
|
12
|
+
|
13
|
+
raise ArgumentError.new "invalid argument name supplied: #{arg_name}" if arg_name.nil?
|
14
|
+
|
15
|
+
message = "argument '#{arg_name}' is an invalid type: #{value} (#{value.class})."
|
16
|
+
|
17
|
+
if not expected_types.nil?
|
18
|
+
message << " Accepted types: "
|
19
|
+
expected_types.each do |type|
|
20
|
+
message << type.to_s << ", "
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
super(message)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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
|
+
class UnexpectedTypeError < Exception
|
10
|
+
|
11
|
+
def initialize(path, expected_type, result_type, value)
|
12
|
+
|
13
|
+
if value.kind_of?(Lebowski::Foundation::SCObject)
|
14
|
+
value = value.sc_class
|
15
|
+
end
|
16
|
+
|
17
|
+
if expected_type.kind_of?(Class) and expected_type.ancestors.member?(Lebowski::Foundation::SCObject)
|
18
|
+
expected_type = expected_type.represented_sc_class
|
19
|
+
end
|
20
|
+
|
21
|
+
message = "Did not get expected type '#{expected_type}' for path '#{path}'. Instead got #{result_type}: #{value}"
|
22
|
+
|
23
|
+
super(message)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
#
|
6
|
+
# Mixin is used to provide colletion item view support to any view that
|
7
|
+
# that will be an item view for a collection view
|
8
|
+
#
|
9
|
+
module CollectionItemViewSupport
|
10
|
+
|
11
|
+
def has_collection_item_view_support()
|
12
|
+
return true
|
13
|
+
end
|
14
|
+
|
15
|
+
def index()
|
16
|
+
return @parent.item_views.index_of self
|
17
|
+
end
|
18
|
+
|
19
|
+
def next_item_view(offset=nil)
|
20
|
+
idx = @parent.item_views.index_of self
|
21
|
+
return nil if idx < 0
|
22
|
+
items_count = @parent.item_views.count
|
23
|
+
offset = offset.nil? ? 1 : offset
|
24
|
+
return nil if (idx + offset) >= items_count
|
25
|
+
return @parent.item_views[idx + offset]
|
26
|
+
end
|
27
|
+
|
28
|
+
def previous_item_view(offset=nil)
|
29
|
+
idx = @parent.item_views.index_of self
|
30
|
+
return nil if idx < 0
|
31
|
+
offset = offset.nil? ? 1 : offset
|
32
|
+
return nil if (idx - offset) < 0
|
33
|
+
return @parent.item_views[idx - offset]
|
34
|
+
end
|
35
|
+
|
36
|
+
def click()
|
37
|
+
self.scroll_to_visible
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def selected?()
|
42
|
+
return self['isSelected']
|
43
|
+
end
|
44
|
+
|
45
|
+
def select()
|
46
|
+
self.click if (self['isSelected'] == false)
|
47
|
+
end
|
48
|
+
|
49
|
+
def select_add()
|
50
|
+
if self['isSelected'] == false
|
51
|
+
self.scroll_to_visible
|
52
|
+
self.key_down :meta_key
|
53
|
+
self.click
|
54
|
+
self.key_up :meta_key
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def deselect()
|
59
|
+
if self['isSelected'] == true
|
60
|
+
self.scroll_to_visible
|
61
|
+
self.key_down :meta_key
|
62
|
+
self.click
|
63
|
+
self.key_up :meta_key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def can_drag_before?()
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
def can_drag_after?()
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
|
75
|
+
def apply_drag_before(source)
|
76
|
+
# no-op
|
77
|
+
end
|
78
|
+
|
79
|
+
def apply_drag_after(source)
|
80
|
+
# no-op
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
module DelegateSupport
|
6
|
+
|
7
|
+
def get_delegate_property(key, *delegates)
|
8
|
+
val = self[key]
|
9
|
+
return val if (not val.nil?)
|
10
|
+
return nil if (delegates.length == 0)
|
11
|
+
delegates.each do |del|
|
12
|
+
val = self["#{del}.#{key}"]
|
13
|
+
return val if (val != :undefined and not val.nil?)
|
14
|
+
end
|
15
|
+
return nil
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
|
4
|
+
module Mixins
|
5
|
+
|
6
|
+
class InlineTextFieldError < Exception
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Mixin adds support for any view that makes use of the inline text field view
|
12
|
+
# (SC.InlineTextFieldView)
|
13
|
+
#
|
14
|
+
module InlineTextFieldSupport
|
15
|
+
|
16
|
+
def edit_inline_text_field(value)
|
17
|
+
pane = self['pane', 'SC.Pane']
|
18
|
+
inline_text_field = pane.child_views.find_first('SC.InlineTextFieldView')
|
19
|
+
if inline_text_field.nil?
|
20
|
+
raise InlineTextFieldError.new "Was unable to locate the inline text field view to edit"
|
21
|
+
end
|
22
|
+
inline_text_field.type value
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
module KeyCheck
|
6
|
+
|
7
|
+
#
|
8
|
+
# Check if a key is pressed down. Note that the key is not specific to any object. So the
|
9
|
+
# following scenario is valid:
|
10
|
+
#
|
11
|
+
# objA.key_down? 'a' # => false
|
12
|
+
# objB.key_down 'a'
|
13
|
+
# objA.key_down? 'a' # => true
|
14
|
+
#
|
15
|
+
def key_down?(key)
|
16
|
+
return @driver.key_down? key
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Check if a key is pressed down. Note that the key is not specific to any object. So the
|
21
|
+
# following scenario is valid:
|
22
|
+
#
|
23
|
+
# objA.key_up? 'a' # => true
|
24
|
+
# objB.key_down 'a'
|
25
|
+
# objA.key_up? 'a' # => false
|
26
|
+
#
|
27
|
+
def key_up?(key)
|
28
|
+
return @driver.key_up? key
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
#
|
6
|
+
# Mixin provides support to any view that will act as a list item view
|
7
|
+
# for a list view.
|
8
|
+
#
|
9
|
+
module ListItemViewSupport
|
10
|
+
include CollectionItemViewSupport
|
11
|
+
|
12
|
+
def can_drag_before?()
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
|
16
|
+
def can_drag_after?()
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply_drag_before(source)
|
21
|
+
source.drag_to self
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply_drag_after(source)
|
25
|
+
source.drag_to self, 0, row_height
|
26
|
+
end
|
27
|
+
|
28
|
+
def row_height()
|
29
|
+
return @parent["rowHeightForContentIndex.#{index}"]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
#
|
6
|
+
# Mixin provides support to objects that need to stall an
|
7
|
+
# action. This is needed in many cases where a user action is
|
8
|
+
# being performed. If an action is performed to quickly then
|
9
|
+
# SproutCore may not respond correctly and therefore cause
|
10
|
+
# unexpected behavior in the application
|
11
|
+
#
|
12
|
+
module StallSupport
|
13
|
+
|
14
|
+
DEFAULT_STALL = 0.2
|
15
|
+
|
16
|
+
DEFAULT_KEY_STALLS = {
|
17
|
+
:click => 0.2,
|
18
|
+
:double_click => 0.5,
|
19
|
+
:select => 0.5
|
20
|
+
}
|
21
|
+
|
22
|
+
@@adjusted_default_stall = DEFAULT_STALL
|
23
|
+
|
24
|
+
@@adjusted_default_key_stalls = {}
|
25
|
+
|
26
|
+
def self.adjust_all_stalls(stall)
|
27
|
+
return if stall.nil? or stall <= 0
|
28
|
+
@@adjusted_default_stall = stall
|
29
|
+
DEFAULT_KEY_STALLS.each_key do |key|
|
30
|
+
@@adjusted_default_key_stalls[key] = stall
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.adjust_default_stall(stall)
|
35
|
+
return if stall.nil? or stall <= 0
|
36
|
+
@@adjusted_default_stall = stall
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.adjust_default_key_stall(key, stall)
|
40
|
+
return if stall.nil? or stall <= 0
|
41
|
+
@@adjusted_default_key_stalls[key] = stall
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.reset()
|
45
|
+
@@adjusted_default_stall = DEFAULT_STALL
|
46
|
+
@@adjusted_default_key_stalls.clear
|
47
|
+
end
|
48
|
+
|
49
|
+
def stall(key, stall=nil)
|
50
|
+
if stall.nil?
|
51
|
+
sleep StallSupport.default_key_stall(key)
|
52
|
+
elsif stall <= 0
|
53
|
+
sleep StallSupport.default_stall
|
54
|
+
else
|
55
|
+
sleep stall
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def self.default_stall()
|
62
|
+
return @@adjusted_default_stall
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.default_key_stall(key)
|
66
|
+
value = @@adjusted_default_key_stalls[key]
|
67
|
+
if value.nil?
|
68
|
+
value = DEFAULT_KEY_STALLS[key]
|
69
|
+
return default_stall if value.nil?
|
70
|
+
return value
|
71
|
+
end
|
72
|
+
return value
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|