rdp-rautomation 0.6.3.1
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/.document +5 -0
- data/.rspec +2 -0
- data/.yardopts +6 -0
- data/History.rdoc +103 -0
- data/LICENSE +20 -0
- data/README.rdoc +114 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/ext/AutoItX/AutoItX.chm +0 -0
- data/ext/AutoItX/AutoItX3.dll +0 -0
- data/ext/IAccessibleDLL/IAccessibleDLL.sln +20 -0
- data/ext/IAccessibleDLL/IAccessibleDLL.suo +0 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.cpp +30 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj +102 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.filters +42 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.user +3 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/ReadMe.txt +48 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/dllmain.cpp +19 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.cpp +8 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.h +22 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/table_support.cpp +282 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/targetver.h +8 -0
- data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
- data/ext/ListViewExplorer/ListViewExplorer.sln +20 -0
- data/ext/ListViewExplorer/ListViewExplorer.suo +0 -0
- data/ext/ListViewExplorer/ListViewExplorer/ListViewExplorer.cpp +174 -0
- data/ext/ListViewExplorer/ListViewExplorer/ListViewExplorer.vcxproj +95 -0
- data/ext/ListViewExplorer/ListViewExplorer/ListViewExplorer.vcxproj.filters +42 -0
- data/ext/ListViewExplorer/ListViewExplorer/ListViewExplorer.vcxproj.user +3 -0
- data/ext/ListViewExplorer/ListViewExplorer/ReadMe.txt +40 -0
- data/ext/ListViewExplorer/ListViewExplorer/stdafx.cpp +8 -0
- data/ext/ListViewExplorer/ListViewExplorer/stdafx.h +17 -0
- data/ext/ListViewExplorer/ListViewExplorer/table_support.cpp +250 -0
- data/ext/ListViewExplorer/ListViewExplorer/table_support.h +2 -0
- data/ext/ListViewExplorer/ListViewExplorer/targetver.h +8 -0
- data/ext/UiaDll/Release/UiaDll.dll +0 -0
- data/ext/UiaDll/UiaDll.sln +20 -0
- data/ext/UiaDll/UiaDll.suo +0 -0
- data/ext/UiaDll/UiaDll/ReadMe.txt +48 -0
- data/ext/UiaDll/UiaDll/UiaDll.cpp +205 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj +104 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +42 -0
- data/ext/UiaDll/UiaDll/dllmain.cpp +39 -0
- data/ext/UiaDll/UiaDll/globals.h +3 -0
- data/ext/UiaDll/UiaDll/stdafx.cpp +8 -0
- data/ext/UiaDll/UiaDll/stdafx.h +19 -0
- data/ext/UiaDll/UiaDll/targetver.h +8 -0
- data/ext/WindowsForms/bin/WindowsForms.exe +0 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms.sln +20 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms.suo +0 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/AboutBox.Designer.cs +80 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/AboutBox.cs +103 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/AboutBox.resx +120 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/DataEntryForm.Designer.cs +187 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/DataEntryForm.cs +46 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/DataEntryForm.resx +120 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +377 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/MainFormWindow.cs +78 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/MainFormWindow.resx +120 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/PersonForm.Designer.cs +119 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/PersonForm.cs +34 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/PersonForm.resx +120 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Program.cs +21 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Properties/AssemblyInfo.cs +36 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Properties/Resources.Designer.cs +71 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Properties/Resources.resx +117 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Properties/Settings.Designer.cs +30 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/Properties/Settings.settings +7 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/SimpleElementsForm.Designer.cs +93 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/SimpleElementsForm.cs +19 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/SimpleElementsForm.resx +120 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/WindowsForms.csproj +123 -0
- data/ext/WindowsForms/src/WindowsForms/WindowsForms/bin/Release/WindowsForms.exe +0 -0
- data/lib/rautomation.rb +6 -0
- data/lib/rautomation/adapter/autoit.rb +5 -0
- data/lib/rautomation/adapter/autoit/button.rb +59 -0
- data/lib/rautomation/adapter/autoit/locators.rb +22 -0
- data/lib/rautomation/adapter/autoit/text_field.rb +61 -0
- data/lib/rautomation/adapter/autoit/window.rb +184 -0
- data/lib/rautomation/adapter/helper.rb +20 -0
- data/lib/rautomation/adapter/win_ffi.rb +21 -0
- data/lib/rautomation/adapter/win_ffi/button.rb +25 -0
- data/lib/rautomation/adapter/win_ffi/button_helper.rb +24 -0
- data/lib/rautomation/adapter/win_ffi/checkbox.rb +19 -0
- data/lib/rautomation/adapter/win_ffi/constants.rb +94 -0
- data/lib/rautomation/adapter/win_ffi/control.rb +79 -0
- data/lib/rautomation/adapter/win_ffi/functions.rb +333 -0
- data/lib/rautomation/adapter/win_ffi/keystroke_converter.rb +67 -0
- data/lib/rautomation/adapter/win_ffi/label.rb +21 -0
- data/lib/rautomation/adapter/win_ffi/list_box.rb +60 -0
- data/lib/rautomation/adapter/win_ffi/locators.rb +22 -0
- data/lib/rautomation/adapter/win_ffi/ms_uia/uia_dll.rb +36 -0
- data/lib/rautomation/adapter/win_ffi/radio.rb +19 -0
- data/lib/rautomation/adapter/win_ffi/select_list.rb +87 -0
- data/lib/rautomation/adapter/win_ffi/table.rb +57 -0
- data/lib/rautomation/adapter/win_ffi/text_field.rb +52 -0
- data/lib/rautomation/adapter/win_ffi/window.rb +226 -0
- data/lib/rautomation/button.rb +55 -0
- data/lib/rautomation/element_collections.rb +47 -0
- data/lib/rautomation/text_field.rb +60 -0
- data/lib/rautomation/wait_helper.rb +23 -0
- data/lib/rautomation/window.rb +234 -0
- data/spec/adapter/win_ffi/button_spec.rb +41 -0
- data/spec/adapter/win_ffi/checkbox_spec.rb +48 -0
- data/spec/adapter/win_ffi/keystroke_converter_spec.rb +47 -0
- data/spec/adapter/win_ffi/label_spec.rb +21 -0
- data/spec/adapter/win_ffi/listbox_spec.rb +52 -0
- data/spec/adapter/win_ffi/radio_spec.rb +37 -0
- data/spec/adapter/win_ffi/select_list_spec.rb +66 -0
- data/spec/adapter/win_ffi/table_spec.rb +39 -0
- data/spec/adapter/win_ffi/text_field_spec.rb +23 -0
- data/spec/adapter/win_ffi/window_spec.rb +43 -0
- data/spec/button_spec.rb +68 -0
- data/spec/buttons_spec.rb +21 -0
- data/spec/spec_helper.rb +96 -0
- data/spec/text_field_spec.rb +65 -0
- data/spec/text_fields_spec.rb +22 -0
- data/spec/window_spec.rb +122 -0
- data/spec/windows_spec.rb +55 -0
- metadata +207 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module RAutomation
|
|
2
|
+
class Button
|
|
3
|
+
# @private
|
|
4
|
+
# This constructor is meant to be accessed only through {Window#button} method.
|
|
5
|
+
def initialize(window, locators)
|
|
6
|
+
@window = window
|
|
7
|
+
@locators = locators
|
|
8
|
+
@button = @window.button(@locators)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Performs a click on the button.
|
|
12
|
+
# By default click is considered successful if the button doesn't exist after clicking (e.g. window has closed)
|
|
13
|
+
# @yield [button] optional block specifying successful clicking condition.
|
|
14
|
+
# @yieldparam [Button] button which is being clicked on.
|
|
15
|
+
# @yieldreturn [Boolean] true if clicking on the button is successful, false otherwise.
|
|
16
|
+
# @raise [UnknownButtonException] if the button doesn't exist.
|
|
17
|
+
def click
|
|
18
|
+
wait_until_exists
|
|
19
|
+
if block_given?
|
|
20
|
+
@button.click {yield self}
|
|
21
|
+
else
|
|
22
|
+
@button.click
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Retrieves the value (text) of the button, usually the visible text.
|
|
27
|
+
# @return [String] the value (text) of the button.
|
|
28
|
+
# @raise [UnknownButtonException] if the button doesn't exist.
|
|
29
|
+
def value
|
|
30
|
+
wait_until_exists
|
|
31
|
+
@button.value
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Checks if the button exists.
|
|
35
|
+
# @return [Boolean] true if button exists, false otherwise.
|
|
36
|
+
def exists?
|
|
37
|
+
@button.exists?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias_method :exist?, :exists?
|
|
41
|
+
|
|
42
|
+
# Allows to execute specific {Adapter} methods not part of the public API.
|
|
43
|
+
def method_missing(name, *args)
|
|
44
|
+
@button.send(name, *args)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def wait_until_exists
|
|
50
|
+
WaitHelper.wait_until {exists?}
|
|
51
|
+
rescue WaitHelper::TimeoutError
|
|
52
|
+
raise UnknownButtonException, "Button #{@locators.inspect} doesn't exist on window #{@window.locators.inspect}!"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module RAutomation
|
|
2
|
+
# @private
|
|
3
|
+
module ElementCollections
|
|
4
|
+
# Creates collection classes and methods for elements.
|
|
5
|
+
# @param [Array<Symbol>] elements for which to create collection classes
|
|
6
|
+
# and methods.
|
|
7
|
+
def has_many(*elements)
|
|
8
|
+
elements.each do |element|
|
|
9
|
+
class_name_plural = element.to_s.split("_").map {|e| e.capitalize}.join
|
|
10
|
+
class_name = class_name_plural.chop
|
|
11
|
+
adapter_class = self.to_s.scan(/(.*)::/).flatten.first
|
|
12
|
+
clazz = RAutomation.constants.include?(class_name) ? RAutomation : class_eval(adapter_class)
|
|
13
|
+
clazz.class_eval %Q{
|
|
14
|
+
class #{class_name_plural}
|
|
15
|
+
include Enumerable
|
|
16
|
+
|
|
17
|
+
def initialize(window, locators)
|
|
18
|
+
@window = window
|
|
19
|
+
@locators = locators
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def each
|
|
23
|
+
i = -1
|
|
24
|
+
while true
|
|
25
|
+
args = [@window, @locators.merge(:index => i += 1)].compact
|
|
26
|
+
object = #{clazz}::#{class_name}.new(*args)
|
|
27
|
+
break unless object.exists?
|
|
28
|
+
yield object
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def method_missing(name, *args)
|
|
33
|
+
ary = self.to_a
|
|
34
|
+
ary.respond_to?(name) ? ary.send(name, *args) : super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class_eval %Q{
|
|
40
|
+
def #{element}(locators = {})
|
|
41
|
+
#{class_name_plural}.new(@window, locators)
|
|
42
|
+
end
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module RAutomation
|
|
2
|
+
class TextField
|
|
3
|
+
# @private
|
|
4
|
+
# This constructor is meant to be accessed only through {Window#text_field} method.
|
|
5
|
+
def initialize(window, locators) #:nodoc:
|
|
6
|
+
@window = window
|
|
7
|
+
@locators = locators
|
|
8
|
+
@text_field = @window.text_field(@locators)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Sets text of the text field.
|
|
12
|
+
# @param [String] text of the field to set.
|
|
13
|
+
# @raise [UnknownTextFieldException] if the text field doesn't exist.
|
|
14
|
+
def set(text)
|
|
15
|
+
wait_until_exists
|
|
16
|
+
@text_field.set(text)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Clears text field's text.
|
|
20
|
+
# @raise [UnknownTextFieldException] if the text field doesn't exist.
|
|
21
|
+
def clear
|
|
22
|
+
wait_until_exists
|
|
23
|
+
@text_field.clear
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns text field's current value (text).
|
|
27
|
+
# @return [String] the value (text) of the text field.
|
|
28
|
+
# @raise [UnknownTextFieldException] if the text field doesn't exist.
|
|
29
|
+
def value
|
|
30
|
+
wait_until_exists
|
|
31
|
+
@text_field.value
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Checks if the text field exists.
|
|
35
|
+
# @return [Boolean] true if text field exists, false otherwise.
|
|
36
|
+
def exists?
|
|
37
|
+
@text_field.exists?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def hwnd
|
|
41
|
+
wait_until_exists
|
|
42
|
+
@text_field.hwnd
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
alias_method :exist?, :exists?
|
|
46
|
+
|
|
47
|
+
# Allows to execute specific {Adapter} methods not part of the public API.
|
|
48
|
+
def method_missing(name, *args)
|
|
49
|
+
@text_field.send(name, *args)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def wait_until_exists
|
|
55
|
+
WaitHelper.wait_until {exists?}
|
|
56
|
+
rescue WaitHelper::TimeoutError
|
|
57
|
+
raise UnknownTextFieldException, "Text field #{@locators.inspect} doesn't exist on window #{@window.locators.inspect}!" unless exists?
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RAutomation
|
|
2
|
+
# Waiting with timeout
|
|
3
|
+
module WaitHelper
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
class TimeoutError < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# @private
|
|
10
|
+
# Wait until the block evaluates to true or times out.
|
|
11
|
+
def wait_until(timeout = Window.wait_timeout, &block)
|
|
12
|
+
end_time = ::Time.now + timeout
|
|
13
|
+
|
|
14
|
+
until ::Time.now > end_time
|
|
15
|
+
result = yield(self)
|
|
16
|
+
return result if result
|
|
17
|
+
sleep 0.5
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
raise TimeoutError, "timed out after #{timeout} seconds"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
module RAutomation
|
|
2
|
+
class UnknownElementException < RuntimeError
|
|
3
|
+
end
|
|
4
|
+
class UnknownWindowException < UnknownElementException
|
|
5
|
+
end
|
|
6
|
+
class UnknownButtonException < UnknownElementException
|
|
7
|
+
end
|
|
8
|
+
class UnknownTextFieldException < UnknownElementException
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Window
|
|
12
|
+
include Adapter::Helper
|
|
13
|
+
extend ElementCollections
|
|
14
|
+
|
|
15
|
+
has_many :windows, :buttons, :text_fields
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# @return [Windows] all windows.
|
|
19
|
+
def windows
|
|
20
|
+
Windows.new(nil, {})
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Retrieves all windows with similar locators to the current window.
|
|
25
|
+
# @param locators (see #initialize)
|
|
26
|
+
# @return [Windows] all windows matching current window's _locators_ if no
|
|
27
|
+
# explicit locators specified or windows matching the specified _locators_.
|
|
28
|
+
def windows(locators = @window.locators)
|
|
29
|
+
Windows.new(nil, locators)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Currently used {Adapter}.
|
|
33
|
+
attr_reader :adapter
|
|
34
|
+
|
|
35
|
+
# Creates the window object.
|
|
36
|
+
#
|
|
37
|
+
# Possible window _locators_ may depend of the used platform and adapter, but
|
|
38
|
+
# following examples will use :title, :class and :hwnd.
|
|
39
|
+
#
|
|
40
|
+
# @example Use window with some title:
|
|
41
|
+
# RAutomation::Window.new(:title => "some title")
|
|
42
|
+
#
|
|
43
|
+
# @example Use window with Regexp title:
|
|
44
|
+
# RAutomation::Window.new(:title => /some title/i)
|
|
45
|
+
#
|
|
46
|
+
# @example Use window with handle (hwnd):
|
|
47
|
+
# RAutomation::Window.new(:hwnd => 123456)
|
|
48
|
+
#
|
|
49
|
+
# @example Use multiple locators, every locator will be matched (AND-ed) to the window:
|
|
50
|
+
# RAutomation::Window.new(:title => "some title", :class => "IEFrame")
|
|
51
|
+
#
|
|
52
|
+
# @note Refer to all possible _locators_ in each {Adapter} documentation.
|
|
53
|
+
#
|
|
54
|
+
# _locators_ may also include a key called :adapter to change default adapter,
|
|
55
|
+
# which is dependent of the platform, to automate windows and their controls.
|
|
56
|
+
#
|
|
57
|
+
# It is also possible to change the default adapter by using environment variable called
|
|
58
|
+
# __RAUTOMATION_ADAPTER__
|
|
59
|
+
#
|
|
60
|
+
# @note This constructor doesn't check for window's existance.
|
|
61
|
+
# @note Only visible windows are supported.
|
|
62
|
+
# @note If given _locators_ include :hwnd then every other possible _locator_ is ignored.
|
|
63
|
+
# @param [Hash] locators locators for the window.
|
|
64
|
+
def initialize(locators)
|
|
65
|
+
@adapter = locators.delete(:adapter) || ENV["RAUTOMATION_ADAPTER"] && ENV["RAUTOMATION_ADAPTER"].to_sym || default_adapter
|
|
66
|
+
@window = Adapter.const_get(normalize(@adapter)).const_get(:Window).new(locators)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class << self
|
|
70
|
+
# Timeout for waiting until object exists. If the timeout exceeds then an {WaitHelper::TimeoutError} is raised.
|
|
71
|
+
@@wait_timeout = 60
|
|
72
|
+
|
|
73
|
+
# Change the timeout to wait before {WaitHelper::TimeoutError} is raised.
|
|
74
|
+
# @param [Fixnum] timeout in seconds.
|
|
75
|
+
def wait_timeout=(timeout)
|
|
76
|
+
@@wait_timeout = timeout
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Retrieve current timeout in seconds to wait before {WaitHelper::TimeoutError} is raised.
|
|
80
|
+
# @return [Fixnum] timeout in seconds
|
|
81
|
+
def wait_timeout
|
|
82
|
+
@@wait_timeout
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [Fixnum] handle of the window which is used internally for other methods.
|
|
88
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
89
|
+
def hwnd
|
|
90
|
+
wait_until_present
|
|
91
|
+
@window.hwnd
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [Fixnum] process identifier (PID) of the window.
|
|
95
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
96
|
+
def pid
|
|
97
|
+
wait_until_present
|
|
98
|
+
@window.pid
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @return [String] title of the window.
|
|
102
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
103
|
+
def title
|
|
104
|
+
wait_until_present
|
|
105
|
+
@window.title
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Activates the Window, e.g. brings it to the top of other windows.
|
|
109
|
+
def activate
|
|
110
|
+
@window.activate
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Checks if the window is active, e.g. on the top of other windows.
|
|
114
|
+
# @return [Boolean] true if the window is active, false otherwise.
|
|
115
|
+
def active?
|
|
116
|
+
@window.active?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Returns visible text of the Window.
|
|
120
|
+
# @return [String] visible text of the window.
|
|
121
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
122
|
+
def text
|
|
123
|
+
wait_until_present
|
|
124
|
+
@window.text
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Checks if the window exists (does have to be visible).
|
|
128
|
+
# @return [Boolean] true if the window exists, false otherwise.
|
|
129
|
+
def exists?
|
|
130
|
+
@window.exists?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
alias_method :exist?, :exists?
|
|
134
|
+
|
|
135
|
+
# Checks if window is visible.
|
|
136
|
+
# @note Window is also visible, if it is behind other windows or minimized.
|
|
137
|
+
# @return [Boolean] true if window is visible, false otherwise.
|
|
138
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
139
|
+
def visible?
|
|
140
|
+
wait_until_exists
|
|
141
|
+
@window.visible?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Checks if the window exists and is visible.
|
|
145
|
+
# @return [Boolean] true if window exists and is visible, false otherwise
|
|
146
|
+
def present?
|
|
147
|
+
exists? && visible?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Maximizes the window.
|
|
151
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
152
|
+
def maximize
|
|
153
|
+
wait_until_present
|
|
154
|
+
@window.maximize
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Minimizes the window.
|
|
158
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
159
|
+
def minimize
|
|
160
|
+
wait_until_present
|
|
161
|
+
@window.minimize
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Checks if window is minimized.
|
|
165
|
+
# @return [Boolean] true if window is minimized, false otherwise.
|
|
166
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
167
|
+
def minimized?
|
|
168
|
+
wait_until_present
|
|
169
|
+
@window.minimized?
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Restores the window size and position.
|
|
173
|
+
# @note If the window is minimized, makes it visible again.
|
|
174
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
175
|
+
def restore
|
|
176
|
+
wait_until_present
|
|
177
|
+
@window.restore
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Sends keyboard keys to the window. Refer to specific {Adapter} documentation for all possible values.
|
|
181
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
182
|
+
def send_keys(keys)
|
|
183
|
+
wait_until_present
|
|
184
|
+
@window.send_keys(keys)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Closes the window if it exists.
|
|
188
|
+
def close
|
|
189
|
+
return unless @window.exists?
|
|
190
|
+
@window.close
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Retrieves {Button} on the window.
|
|
194
|
+
# @note Refer to specific {Adapter} documentation for possible _locator_ parameters.
|
|
195
|
+
# @param [Hash] locators for the {Button}.
|
|
196
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
197
|
+
def button(locators)
|
|
198
|
+
wait_until_present
|
|
199
|
+
Button.new(@window, locators)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Retrieves {TextField} on the window.
|
|
203
|
+
# @note Refer to specific {Adapter} documentation for possible _locators_ parameters.
|
|
204
|
+
# @raise [UnknownWindowException] if the window doesn't exist.
|
|
205
|
+
def text_field(locators)
|
|
206
|
+
wait_until_present
|
|
207
|
+
TextField.new(@window, locators)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Allows to execute specific {Adapter} methods not part of the public API.
|
|
211
|
+
def method_missing(name, *args)
|
|
212
|
+
@window.send(name, *args)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
private
|
|
216
|
+
|
|
217
|
+
def wait_until_present
|
|
218
|
+
WaitHelper.wait_until {present?}
|
|
219
|
+
rescue WaitHelper::TimeoutError
|
|
220
|
+
raise UnknownWindowException, "Window with locator #{@window.locators.inspect} doesn't exist or is not visible!"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def wait_until_exists
|
|
224
|
+
WaitHelper.wait_until {exists?}
|
|
225
|
+
rescue WaitHelper::TimeoutError
|
|
226
|
+
raise UnknownWindowException, "Window with locator #{@window.locators.inspect} doesn't exist!"
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def normalize adapter
|
|
230
|
+
adapter.to_s.split("_").map {|word| word.capitalize}.join
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "WinFfi::Button", :if => SpecHelper.adapter == :win_ffi do
|
|
4
|
+
it "find by id" do
|
|
5
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
|
6
|
+
window.button(:id => "aboutButton").should exist
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "check for button class" do
|
|
10
|
+
RAutomation::Window.new(:title => "MainFormWindow").button(:id => "textField").should_not exist
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
it "enabled/disabled" do
|
|
15
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
|
16
|
+
window.button(:id => "enabledButton").should be_enabled
|
|
17
|
+
window.button(:id => "enabledButton").should_not be_disabled
|
|
18
|
+
|
|
19
|
+
window.button(:id => "disabledButton").should be_disabled
|
|
20
|
+
window.button(:id => "disabledButton").should_not be_enabled
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "#set_focus" do
|
|
24
|
+
button = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).button(:id => "enabledButton")
|
|
25
|
+
button.should_not have_focus
|
|
26
|
+
|
|
27
|
+
button.set_focus
|
|
28
|
+
button.should have_focus
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "cannot click disabled button" do
|
|
32
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
|
33
|
+
lambda { window.button(:id => "disabledButton").click }.should raise_error
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "cannot set focus to disabled button" do
|
|
37
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
|
38
|
+
lambda { window.button(:id => "disabledButton").set_focus }.should raise_error
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|