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,315 @@
|
|
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
|
+
# This class represents a SproutCore-based application. In order to interact with the
|
11
|
+
# actual application you must create an instance of this class and start it. Once
|
12
|
+
# started, you are then free to access any object or view that has been created by
|
13
|
+
# the application within the web browser.
|
14
|
+
#
|
15
|
+
class Application < Lebowski::Foundation::SCObject
|
16
|
+
include Lebowski
|
17
|
+
include Lebowski::Foundation
|
18
|
+
include Lebowski::Foundation::Panes
|
19
|
+
include Lebowski::Foundation::Mixins::KeyCheck
|
20
|
+
|
21
|
+
SAFARI = '*safari'
|
22
|
+
FIREFOX = '*firefox'
|
23
|
+
CHROME = '*chrome'
|
24
|
+
|
25
|
+
DEFAULT_BROWSER = FIREFOX
|
26
|
+
DEFAULT_SELENIUM_SERVER_HOST = 'localhost'
|
27
|
+
DEFAULT_SELENIUM_SERVER_PORT = 4444
|
28
|
+
DEFAULT_APP_SERVER_HOST = 'localhost'
|
29
|
+
DEFAULT_APP_SERVER_PORT = 4020
|
30
|
+
DEFAULT_TIMEOUT_IN_SECONDS = 240
|
31
|
+
|
32
|
+
attr_reader :app_name,
|
33
|
+
:app_root_path,
|
34
|
+
:host,
|
35
|
+
:port,
|
36
|
+
:base_url,
|
37
|
+
:session_id,
|
38
|
+
:browser,
|
39
|
+
:app_is_loaded_flag
|
40
|
+
|
41
|
+
#
|
42
|
+
# Creates an Application instance that will allow you to interact with a
|
43
|
+
# SproutCore-based application.
|
44
|
+
#
|
45
|
+
# Initialization requires a hash input containing parameters to set up
|
46
|
+
# the application instance. At minimum, the following are required
|
47
|
+
#
|
48
|
+
# app_root_path => The root URL path to the SproutCore-based application (e.g. /my_app)
|
49
|
+
# app_name => The name of the application's root object (e.g. MyApp)
|
50
|
+
#
|
51
|
+
# In addition to the two required params, the following optional params can
|
52
|
+
# also be supplied:
|
53
|
+
#
|
54
|
+
# selenium_server_host => The name of the host the selenium server is running on (default is localhost)
|
55
|
+
# selenium_server_port => The port the selenium server is listening on (default is 4444)
|
56
|
+
# app_server_host => The name of the server hosting the web application (defalt is localhost)
|
57
|
+
# app_server_port => The port on the server to access the web application (default is 4020)
|
58
|
+
# browser => The web browser to load the web application in to (default is SAFARI)
|
59
|
+
#
|
60
|
+
# Example:
|
61
|
+
#
|
62
|
+
# Lebowski::Foundation::Application.new \
|
63
|
+
# :app_root_path => "/hello_world",
|
64
|
+
# :app_name => "HelloWorldApp"
|
65
|
+
#
|
66
|
+
def initialize(params)
|
67
|
+
super()
|
68
|
+
|
69
|
+
if params.nil?
|
70
|
+
raise ArgumentError.new "must supply parameters to create application instance"
|
71
|
+
end
|
72
|
+
|
73
|
+
if not params.kind_of?(Hash)
|
74
|
+
raise ArgumentError.new "must supply a hash containing parameters"
|
75
|
+
end
|
76
|
+
|
77
|
+
@host = get_selenium_server_host(params)
|
78
|
+
@port = get_selenium_server_port(params)
|
79
|
+
@browser = get_browser(params)
|
80
|
+
|
81
|
+
@app_root_path = get_app_root_path(params)
|
82
|
+
raise ArgumentError.new "Application root path is required - :app_root_path" if @app_root_path.nil?
|
83
|
+
|
84
|
+
@app_name = get_app_name(params)
|
85
|
+
raise ArgumentError.new "Application name is required - :app_name" if @app_name.nil?
|
86
|
+
|
87
|
+
@rel_path = @app_name
|
88
|
+
@app_is_loaded_flag = get_app_is_loaded_flag(params)
|
89
|
+
@timeout_in_seconds = get_timeout_in_second(params)
|
90
|
+
@base_url = get_application_base_url(params)
|
91
|
+
@session_id = get_session_id(params)
|
92
|
+
|
93
|
+
@driver = Lebowski::Runtime::SproutCoreDriver.new \
|
94
|
+
:host => @host,
|
95
|
+
:port => @port,
|
96
|
+
:browser => @browser,
|
97
|
+
:url => @base_url,
|
98
|
+
:timeout_in_second => @timeout_in_seconds
|
99
|
+
|
100
|
+
@started = false
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Responsible for starting the application. The application will create
|
105
|
+
# an internal driver that is used to actually communicate with the
|
106
|
+
# selenium server.
|
107
|
+
#
|
108
|
+
# You can optionally supply a block used to wait until some condition
|
109
|
+
# has been satisfied before going on and running the rest of your script.
|
110
|
+
# Example:
|
111
|
+
#
|
112
|
+
# application.start do |it|
|
113
|
+
# it['appIsLoaded'] == true
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# If the condition does not become true before timing out then an exception
|
117
|
+
# will be thrown. You can adjust the timeout like so,
|
118
|
+
#
|
119
|
+
# application.start(20) do |it|
|
120
|
+
# it['appIsLoaded'] == true
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
def start(timeout=nil, &block)
|
124
|
+
return if started?
|
125
|
+
|
126
|
+
begin
|
127
|
+
if @session_id.nil?
|
128
|
+
@driver.start
|
129
|
+
else
|
130
|
+
@driver.session_id = @session_id
|
131
|
+
end
|
132
|
+
|
133
|
+
@driver.set_application_name @app_name
|
134
|
+
@driver.open_sc_application @app_root_path, @timeout_in_seconds
|
135
|
+
@started = true
|
136
|
+
rescue Exception => ex
|
137
|
+
err_message = "Error connecting to selenium server: #{ex.message}\n"
|
138
|
+
err_message << "Confirm that selenium server is running on #{@selenium_server_host}:#{@selenium_server_port}"
|
139
|
+
raise Runtime::SeleniumServerError.new err_message
|
140
|
+
end
|
141
|
+
|
142
|
+
if block_given?
|
143
|
+
begin
|
144
|
+
wait_until(timeout, &block)
|
145
|
+
rescue TimeoutError => toe
|
146
|
+
err_message = "Unable to start application. Wait condition was not met before timeout. #{toe.message}"
|
147
|
+
raise TimeoutError.new err_message
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def end()
|
154
|
+
return if (not started?)
|
155
|
+
|
156
|
+
begin
|
157
|
+
@driver.stop
|
158
|
+
@started = false
|
159
|
+
rescue Exception => ex
|
160
|
+
err_message = "Error disconnecting from selenium server: #{ex.message}\n"
|
161
|
+
err_message << "Confirm that selenium server is running on #{@selenium_server_host}:#{@selenium_server_port}"
|
162
|
+
raise Runtime::SeleniumServerError.new err_message
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def started?()
|
167
|
+
return @started
|
168
|
+
end
|
169
|
+
|
170
|
+
def window()
|
171
|
+
@window = Window.new(@driver) if @window.nil?
|
172
|
+
return @window
|
173
|
+
end
|
174
|
+
|
175
|
+
def abs_path()
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
|
179
|
+
def root_object(name, expected_type=nil)
|
180
|
+
return self['$' + name, expected_type]
|
181
|
+
end
|
182
|
+
|
183
|
+
alias_method :framework, :root_object
|
184
|
+
|
185
|
+
def main_pane(expected_type=nil)
|
186
|
+
return self['$SC.RootResponder.responder.mainPane', expected_type]
|
187
|
+
end
|
188
|
+
|
189
|
+
def key_pane(expected_type=nil)
|
190
|
+
return self['$SC.RootResponder.responder.keyPane', expected_type]
|
191
|
+
end
|
192
|
+
|
193
|
+
def responding_panes()
|
194
|
+
if @responding_panes.nil?
|
195
|
+
@responding_panes = ObjectArray.new self, '$SC.RootResponder.responder.panes'
|
196
|
+
end
|
197
|
+
return @responding_panes
|
198
|
+
end
|
199
|
+
|
200
|
+
def define_root_object(key, name, expected_type=nil)
|
201
|
+
return define(key, '$' + name, expected_type)
|
202
|
+
end
|
203
|
+
|
204
|
+
alias_method :define_framework, :define_root_object
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def get_selenium_client(params)
|
209
|
+
return params[:driver]
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_selenium_server_host(params)
|
213
|
+
client = get_selenium_client(params)
|
214
|
+
return client.host if (not client.nil?)
|
215
|
+
return DEFAULT_SELENIUM_SERVER_HOST if params[:selenium_server_host].nil?
|
216
|
+
return params[:selenium_server_host]
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_selenium_server_port(params)
|
220
|
+
client = get_selenium_client(params)
|
221
|
+
return client.port if (not client.nil?)
|
222
|
+
return DEFAULT_SELENIUM_SERVER_PORT if params[:selenium_server_port].nil?
|
223
|
+
return params[:selenium_server_port].to_i
|
224
|
+
end
|
225
|
+
|
226
|
+
def get_app_server_host(params)
|
227
|
+
return DEFAULT_APP_SERVER_HOST if params[:app_server_host].nil?
|
228
|
+
return params[:app_server_host]
|
229
|
+
end
|
230
|
+
|
231
|
+
def get_app_server_port(params)
|
232
|
+
return DEFAULT_APP_SERVER_PORT if params[:app_server_port].nil?
|
233
|
+
return params[:app_server_port].to_i
|
234
|
+
end
|
235
|
+
|
236
|
+
def get_application_base_url(params)
|
237
|
+
client = get_selenium_client(params)
|
238
|
+
return client.browser_url if (not client.nil?)
|
239
|
+
return "http://#{get_app_server_host(params)}:#{get_app_server_port(params)}"
|
240
|
+
end
|
241
|
+
|
242
|
+
def get_session_id(params)
|
243
|
+
client = get_selenium_client(params)
|
244
|
+
return client.session_id if (not client.nil?)
|
245
|
+
return nil
|
246
|
+
end
|
247
|
+
|
248
|
+
def get_browser(params)
|
249
|
+
client = get_selenium_client(params)
|
250
|
+
return client.browser_string if (not client.nil?)
|
251
|
+
|
252
|
+
browser = params[:browser]
|
253
|
+
case (browser)
|
254
|
+
when :firefox
|
255
|
+
return FIREFOX
|
256
|
+
when :safari
|
257
|
+
return SAFARI
|
258
|
+
else
|
259
|
+
return DEFAULT_BROWSER
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def get_app_root_path(params)
|
264
|
+
return params[:app_root_path]
|
265
|
+
end
|
266
|
+
|
267
|
+
def get_app_name(params)
|
268
|
+
return params[:app_name]
|
269
|
+
end
|
270
|
+
|
271
|
+
def get_app_is_loaded_flag(params)
|
272
|
+
return params[:app_is_loaded_flag]
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_timeout_in_second(params)
|
276
|
+
return DEFAULT_TIMEOUT_IN_SECONDS if params[:timeout_in_seconds].nil?
|
277
|
+
return params[:timeout_in_seconds].to_i
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# Represents the browser window the application has been loaded into
|
284
|
+
#
|
285
|
+
class Window
|
286
|
+
|
287
|
+
def initialize(driver)
|
288
|
+
@driver = driver
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
# Moves the browser window
|
293
|
+
#
|
294
|
+
def move_to(x, y)
|
295
|
+
@driver.sc_window_move_to(x,y)
|
296
|
+
end
|
297
|
+
|
298
|
+
#
|
299
|
+
# Resizes the browser window
|
300
|
+
#
|
301
|
+
def resize_to(width, height)
|
302
|
+
@driver.sc_window_resize_to(width, height)
|
303
|
+
end
|
304
|
+
|
305
|
+
#
|
306
|
+
# Maximizes the browser window
|
307
|
+
#
|
308
|
+
def maximize()
|
309
|
+
@driver.sc_window_maximize
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Lebowski
|
2
|
+
module Foundation
|
3
|
+
|
4
|
+
# A SproutCore error instance (SC.Error)
|
5
|
+
SC_T_ERROR = 'error'
|
6
|
+
|
7
|
+
# Null value
|
8
|
+
SC_T_NULL = 'null'
|
9
|
+
|
10
|
+
# Undefined value
|
11
|
+
SC_T_UNDEFINED = 'undefined'
|
12
|
+
|
13
|
+
# A function
|
14
|
+
SC_T_FUNCTION = 'function'
|
15
|
+
|
16
|
+
# Number primitive
|
17
|
+
SC_T_NUMBER = 'number'
|
18
|
+
|
19
|
+
# Boolean primitive
|
20
|
+
SC_T_BOOL = 'boolean'
|
21
|
+
|
22
|
+
# An instance of Array
|
23
|
+
SC_T_ARRAY = 'array'
|
24
|
+
|
25
|
+
# String primitive
|
26
|
+
SC_T_STRING = 'string'
|
27
|
+
|
28
|
+
# A JavaScript object not inheriting from SC.Object
|
29
|
+
SC_T_HASH = 'hash'
|
30
|
+
|
31
|
+
# A SproutCore class (created using SC.Object.extend())
|
32
|
+
SC_T_CLASS = 'class'
|
33
|
+
|
34
|
+
# A SproutCore object instance
|
35
|
+
SC_T_OBJECT = 'object'
|
36
|
+
|
37
|
+
SC_MIXED_STATE = '__MIXED__'
|
38
|
+
|
39
|
+
# Constants used by the collection view. see SproutCore file collection_content.js
|
40
|
+
SC_LEAF_NODE = 0x0020
|
41
|
+
SC_BRANCH_OPEN = 0x0011
|
42
|
+
SC_BRANCH_CLOSED = 0x0012
|
43
|
+
|
44
|
+
module Util
|
45
|
+
|
46
|
+
def assert_is_object(value, name)
|
47
|
+
if not value.kind_of? Lebowski::Foundation::ProxyObject
|
48
|
+
raise ArgumentInvalidTypeError.new name, value, Lebowski::Foundation::ProxyObject
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def assert_is_view(value, name)
|
53
|
+
if not value.kind_of? Lebowski::Foundation::Views::View
|
54
|
+
raise ArgumentInvalidTypeError.new name, value, Lebowski::Foundation::Views::View
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,231 @@
|
|
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 SproutCore Core Query object. This proxy provides a subset of the
|
11
|
+
# functionality that the actual core query object has.
|
12
|
+
#
|
13
|
+
# The core query is obtained through a view object and requires a CSS selector.
|
14
|
+
# Based on the associated view and given selector, the core query object will
|
15
|
+
# then contain zero or more DOM elements that match the selector starting from
|
16
|
+
# the view's layer (read: root DOM element).
|
17
|
+
#
|
18
|
+
# For feature and integration testing, the use of the core query object may be
|
19
|
+
# too low-level. Rather, this object is handy for custom views that override
|
20
|
+
# the render method. By creating a proxy to the custom view you can then use
|
21
|
+
# this object to do some fine grained checks that you don't want to expose
|
22
|
+
# to the casual tester, for instance.
|
23
|
+
#
|
24
|
+
class CoreQuery
|
25
|
+
|
26
|
+
INVALID_HANDLE = -1
|
27
|
+
|
28
|
+
attr_reader :selector, # The CSS selector
|
29
|
+
:handle, # The handle to the remote core query object
|
30
|
+
:abs_path # The absolute path to the view this object comes from
|
31
|
+
|
32
|
+
#
|
33
|
+
# Creates an instance. Once created, it will have a handle to the remote
|
34
|
+
# core query object in order to perform subsequent calls. Call the done()
|
35
|
+
# method when this object is no longer used
|
36
|
+
#
|
37
|
+
# @param abs_path {String} a property path to the view the core query object will come from
|
38
|
+
# @param selector {String} a CSS selector. See SproutCore's CoreQuery object for more details
|
39
|
+
# @param driver {Object} driver to communicate with the selenium server
|
40
|
+
#
|
41
|
+
def initialize(abs_path, selector, driver)
|
42
|
+
@abs_path = abs_path
|
43
|
+
@selector = selector.nil? ? "" : selector
|
44
|
+
@driver = driver
|
45
|
+
@handle = INVALID_HANDLE
|
46
|
+
@size = 0
|
47
|
+
|
48
|
+
@handle = @driver.get_sc_core_query(abs_path, selector)
|
49
|
+
@size = @driver.get_sc_core_query_size(@handle) if has_handle?
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Returns the number of elements found by this core query object
|
54
|
+
#
|
55
|
+
def size()
|
56
|
+
return @size if has_handle?
|
57
|
+
return -1
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Checks if this object has a handle to the remote core query object
|
62
|
+
#
|
63
|
+
def has_handle?()
|
64
|
+
return (not @handle == INVALID_HANDLE)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Will clean up this object when no longer used
|
69
|
+
#
|
70
|
+
def done()
|
71
|
+
@driver.sc_core_query_done(@handle)
|
72
|
+
@handle = INVALID_HANDLE
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Get an element at a given index. Returns an instance of DOMElement
|
77
|
+
#
|
78
|
+
# @param index {Number} returns element if this object has a handle and
|
79
|
+
# the index is within range
|
80
|
+
#
|
81
|
+
def [](index)
|
82
|
+
if has_handle? and (index > -1) and (index <= (@size - 1))
|
83
|
+
return Lebowski::Foundation::DOMElement.new @handle, index, @driver
|
84
|
+
end
|
85
|
+
return nil
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Used to iterate through each element in this object. The block provided
|
90
|
+
# will be provided to argments: the element and its index. You can use this
|
91
|
+
# method as follows:
|
92
|
+
#
|
93
|
+
# core_query.each do |element, index |
|
94
|
+
# ...
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
def each(&block)
|
98
|
+
return if (not has_handle? or not block_given? or size <= 0)
|
99
|
+
|
100
|
+
for i in 0..size - 1 do
|
101
|
+
elem = Lebowski::Foundation::DOMElement.new @handle, i, @driver
|
102
|
+
yield elem, i
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Used to fetch elements from this object. The block provided
|
108
|
+
# is used to return an element that will be added to the array
|
109
|
+
# of elements to be returned. If the block does not return an
|
110
|
+
# element then the element will not be added to the resulting
|
111
|
+
# array. As an example:
|
112
|
+
#
|
113
|
+
# elements = core_query.fetch { |element, index| element if element.text == 'foo' }
|
114
|
+
#
|
115
|
+
# The result array will then contain all elements in the core query
|
116
|
+
# object that have text equal to 'foo'. if no elements match then
|
117
|
+
# an empty array is returned.
|
118
|
+
#
|
119
|
+
# The block provided is to have the following setup:
|
120
|
+
#
|
121
|
+
# do |element, index| OR { |element, index| ... }
|
122
|
+
# ...
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
def fetch(&block)
|
126
|
+
return [] if not block_given?
|
127
|
+
elems = []
|
128
|
+
each do |elem, index|
|
129
|
+
result = yield elem, index
|
130
|
+
elems << result if not result.nil?
|
131
|
+
end
|
132
|
+
return elems
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Used to perform a check on the elements from this core query. The
|
137
|
+
# block provided is used to return true or false based of if the
|
138
|
+
# given element passed some condition. In addition to the block
|
139
|
+
# supplied to this method, you also pass in a condition about the
|
140
|
+
# check being perform, which can be one of the following:
|
141
|
+
#
|
142
|
+
# :all - Check that all elements meet the block's checks
|
143
|
+
# :any - Check that one or more elements meet the block's checks
|
144
|
+
# :none - Check that no elements meet the block's checks
|
145
|
+
# :one - Check that there is only one element that meets the block's checks
|
146
|
+
#
|
147
|
+
# If no condition argument is gien this :all is the default.
|
148
|
+
#
|
149
|
+
# Here is an example of how to use this method:
|
150
|
+
#
|
151
|
+
# meets_condition = core_query.check :all, do |elem, index|
|
152
|
+
# if elem.text == 'foo'
|
153
|
+
# true # element passes check
|
154
|
+
# else
|
155
|
+
# false # element does not pass check
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# @see #all?
|
160
|
+
# @see #any?
|
161
|
+
# @see #none?
|
162
|
+
# @see #one?
|
163
|
+
#
|
164
|
+
def check(condition=nil, &block)
|
165
|
+
return false if not block_given?
|
166
|
+
counter = 0
|
167
|
+
each do |elem, index|
|
168
|
+
result = yield elem, index
|
169
|
+
counter = counter + 1 if result == true
|
170
|
+
end
|
171
|
+
|
172
|
+
case condition
|
173
|
+
when :all
|
174
|
+
return counter == size
|
175
|
+
when :any
|
176
|
+
return counter > 0
|
177
|
+
when :none
|
178
|
+
return counter == 0
|
179
|
+
when :one
|
180
|
+
return counter == 1
|
181
|
+
else
|
182
|
+
return counter == size
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Used to check if all of the element for this core query meet
|
188
|
+
# the conditions for the given block
|
189
|
+
#
|
190
|
+
# @see #check
|
191
|
+
#
|
192
|
+
def all?(&block)
|
193
|
+
check :all &block
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Used to check if any of the element for this core query meet
|
198
|
+
# the conditions for the given block
|
199
|
+
#
|
200
|
+
# @see #check
|
201
|
+
#
|
202
|
+
def any?(&block)
|
203
|
+
check :any &block
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# Used to check if none of the element for this core query meet
|
208
|
+
# the conditions for the given block
|
209
|
+
#
|
210
|
+
# @see #check
|
211
|
+
#
|
212
|
+
def none?(&block)
|
213
|
+
check :none &block
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Used to check if there is only one element for this core query that
|
218
|
+
# meets the conditions for the given block
|
219
|
+
#
|
220
|
+
# @see #check
|
221
|
+
#
|
222
|
+
def one?(&block)
|
223
|
+
check :one &block
|
224
|
+
end
|
225
|
+
|
226
|
+
alias_method :element, :[]
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|