rautomation 2.0.1-x86-mingw32

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 (202) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +41 -0
  4. data/.rspec +2 -0
  5. data/.yardopts +8 -0
  6. data/CHANGES.md +276 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +142 -0
  10. data/Rakefile +73 -0
  11. data/ext/AutoItX/AutoItX.chm +0 -0
  12. data/ext/AutoItX/AutoItX3.dll +0 -0
  13. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.cpp +30 -0
  14. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj +179 -0
  15. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.filters +42 -0
  16. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.user +3 -0
  17. data/ext/IAccessibleDLL/IAccessibleDLL/ReadMe.txt +48 -0
  18. data/ext/IAccessibleDLL/IAccessibleDLL/dllmain.cpp +19 -0
  19. data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.cpp +8 -0
  20. data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.h +22 -0
  21. data/ext/IAccessibleDLL/IAccessibleDLL/table_support.cpp +282 -0
  22. data/ext/IAccessibleDLL/IAccessibleDLL/targetver.h +8 -0
  23. data/ext/IAccessibleDLL/IAccessibleDLL.sln +31 -0
  24. data/ext/IAccessibleDLL/IAccessibleDLL.suo +0 -0
  25. data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
  26. data/ext/UiaDll/RAutomation.UIA/Controls/Clicker.cs +63 -0
  27. data/ext/UiaDll/RAutomation.UIA/Controls/SelectList.cs +116 -0
  28. data/ext/UiaDll/RAutomation.UIA/Controls/Spinner.cs +46 -0
  29. data/ext/UiaDll/RAutomation.UIA/Controls/TabControl.cs +54 -0
  30. data/ext/UiaDll/RAutomation.UIA/Controls/TableControl.cs +132 -0
  31. data/ext/UiaDll/RAutomation.UIA/Controls/TextControl.cs +50 -0
  32. data/ext/UiaDll/RAutomation.UIA/Expander.cs +59 -0
  33. data/ext/UiaDll/RAutomation.UIA/Extensions/Element.cs +166 -0
  34. data/ext/UiaDll/RAutomation.UIA/Extensions/Enumerable.cs +76 -0
  35. data/ext/UiaDll/RAutomation.UIA/Extensions/Property.cs +27 -0
  36. data/ext/UiaDll/RAutomation.UIA/Properties/AssemblyInfo.cs +36 -0
  37. data/ext/UiaDll/RAutomation.UIA/Properties/AutomationProperties.cs +18 -0
  38. data/ext/UiaDll/RAutomation.UIA/RAutomation.UIA.csproj +77 -0
  39. data/ext/UiaDll/Release/RAutomation.UIA.dll +0 -0
  40. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  41. data/ext/UiaDll/UiaDll/ArrayHelper.cpp +14 -0
  42. data/ext/UiaDll/UiaDll/ArrayHelper.h +7 -0
  43. data/ext/UiaDll/UiaDll/AssemblyInfo.cpp +40 -0
  44. data/ext/UiaDll/UiaDll/ControlMethods.cpp +16 -0
  45. data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.cpp +24 -0
  46. data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.h +16 -0
  47. data/ext/UiaDll/UiaDll/Locator.cpp +93 -0
  48. data/ext/UiaDll/UiaDll/Locator.h +55 -0
  49. data/ext/UiaDll/UiaDll/MenuItemSelector.cpp +75 -0
  50. data/ext/UiaDll/UiaDll/MenuItemSelector.h +24 -0
  51. data/ext/UiaDll/UiaDll/MenuMethods.cpp +62 -0
  52. data/ext/UiaDll/UiaDll/ReadMe.txt +38 -0
  53. data/ext/UiaDll/UiaDll/SelectListMethods.cpp +84 -0
  54. data/ext/UiaDll/UiaDll/SpinnerMethods.cpp +61 -0
  55. data/ext/UiaDll/UiaDll/StringHelper.cpp +57 -0
  56. data/ext/UiaDll/UiaDll/StringHelper.h +15 -0
  57. data/ext/UiaDll/UiaDll/StringMethods.cpp +8 -0
  58. data/ext/UiaDll/UiaDll/TabControlMethods.cpp +40 -0
  59. data/ext/UiaDll/UiaDll/TableMethods.cpp +108 -0
  60. data/ext/UiaDll/UiaDll/TextMethods.cpp +25 -0
  61. data/ext/UiaDll/UiaDll/ToggleStateHelper.h +10 -0
  62. data/ext/UiaDll/UiaDll/UiaDll.cpp +216 -0
  63. data/ext/UiaDll/UiaDll/UiaDll.h +13 -0
  64. data/ext/UiaDll/UiaDll/UiaDll.vcxproj +167 -0
  65. data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +110 -0
  66. data/ext/UiaDll/UiaDll/app.ico +0 -0
  67. data/ext/UiaDll/UiaDll/app.rc +0 -0
  68. data/ext/UiaDll/UiaDll/dllmain.cpp +1 -0
  69. data/ext/UiaDll/UiaDll/resource.h +3 -0
  70. data/ext/UiaDll/UiaDll/stdafx.cpp +5 -0
  71. data/ext/UiaDll/UiaDll/stdafx.h +41 -0
  72. data/ext/UiaDll/UiaDll/targetver.h +8 -0
  73. data/ext/UiaDll/UiaDll.sln +57 -0
  74. data/ext/WindowsForms/.nuget/NuGet.Config +6 -0
  75. data/ext/WindowsForms/.nuget/NuGet.exe +0 -0
  76. data/ext/WindowsForms/.nuget/NuGet.targets +136 -0
  77. data/ext/WindowsForms/Release/FizzWare.NBuilder.dll +0 -0
  78. data/ext/WindowsForms/Release/UIA.Extensions.dll +0 -0
  79. data/ext/WindowsForms/Release/WindowsForms.exe +0 -0
  80. data/ext/WindowsForms/WindowsForms/AboutBox.Designer.cs +168 -0
  81. data/ext/WindowsForms/WindowsForms/AboutBox.cs +103 -0
  82. data/ext/WindowsForms/WindowsForms/AboutBox.resx +123 -0
  83. data/ext/WindowsForms/WindowsForms/DataEntryForm.Designer.cs +218 -0
  84. data/ext/WindowsForms/WindowsForms/DataEntryForm.cs +52 -0
  85. data/ext/WindowsForms/WindowsForms/DataEntryForm.resx +120 -0
  86. data/ext/WindowsForms/WindowsForms/DataGridView.Designer.cs +77 -0
  87. data/ext/WindowsForms/WindowsForms/DataGridView.cs +43 -0
  88. data/ext/WindowsForms/WindowsForms/DataGridView.resx +120 -0
  89. data/ext/WindowsForms/WindowsForms/FizzWare.NBuilder.dll +0 -0
  90. data/ext/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +527 -0
  91. data/ext/WindowsForms/WindowsForms/MainFormWindow.cs +109 -0
  92. data/ext/WindowsForms/WindowsForms/MainFormWindow.resx +126 -0
  93. data/ext/WindowsForms/WindowsForms/PersonForm.Designer.cs +119 -0
  94. data/ext/WindowsForms/WindowsForms/PersonForm.cs +34 -0
  95. data/ext/WindowsForms/WindowsForms/PersonForm.resx +120 -0
  96. data/ext/WindowsForms/WindowsForms/Program.cs +21 -0
  97. data/ext/WindowsForms/WindowsForms/Properties/AssemblyInfo.cs +36 -0
  98. data/ext/WindowsForms/WindowsForms/Properties/Resources.Designer.cs +71 -0
  99. data/ext/WindowsForms/WindowsForms/Properties/Resources.resx +117 -0
  100. data/ext/WindowsForms/WindowsForms/Properties/Settings.Designer.cs +30 -0
  101. data/ext/WindowsForms/WindowsForms/Properties/Settings.settings +7 -0
  102. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.Designer.cs +93 -0
  103. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.cs +19 -0
  104. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.resx +120 -0
  105. data/ext/WindowsForms/WindowsForms/UIA.Extensions.dll +0 -0
  106. data/ext/WindowsForms/WindowsForms/ValueMonthCalendar.cs +28 -0
  107. data/ext/WindowsForms/WindowsForms/WindowsForms.csproj +166 -0
  108. data/ext/WindowsForms/WindowsForms/packages.config +4 -0
  109. data/ext/WindowsForms/WindowsForms.sln +46 -0
  110. data/lib/rautomation/adapter/autoit/button.rb +59 -0
  111. data/lib/rautomation/adapter/autoit/locators.rb +22 -0
  112. data/lib/rautomation/adapter/autoit/mouse.rb +38 -0
  113. data/lib/rautomation/adapter/autoit/text_field.rb +70 -0
  114. data/lib/rautomation/adapter/autoit/window.rb +197 -0
  115. data/lib/rautomation/adapter/autoit.rb +8 -0
  116. data/lib/rautomation/adapter/helper.rb +64 -0
  117. data/lib/rautomation/adapter/ms_uia/button.rb +21 -0
  118. data/lib/rautomation/adapter/ms_uia/button_helper.rb +19 -0
  119. data/lib/rautomation/adapter/ms_uia/checkbox.rb +23 -0
  120. data/lib/rautomation/adapter/ms_uia/constants.rb +111 -0
  121. data/lib/rautomation/adapter/ms_uia/control.rb +134 -0
  122. data/lib/rautomation/adapter/ms_uia/functions.rb +279 -0
  123. data/lib/rautomation/adapter/ms_uia/keys.rb +121 -0
  124. data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
  125. data/lib/rautomation/adapter/ms_uia/label.rb +18 -0
  126. data/lib/rautomation/adapter/ms_uia/list_box.rb +46 -0
  127. data/lib/rautomation/adapter/ms_uia/list_item.rb +22 -0
  128. data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
  129. data/lib/rautomation/adapter/ms_uia/menu.rb +36 -0
  130. data/lib/rautomation/adapter/ms_uia/radio.rb +23 -0
  131. data/lib/rautomation/adapter/ms_uia/select_list.rb +85 -0
  132. data/lib/rautomation/adapter/ms_uia/spinner.rb +31 -0
  133. data/lib/rautomation/adapter/ms_uia/tab_control.rb +46 -0
  134. data/lib/rautomation/adapter/ms_uia/table.rb +140 -0
  135. data/lib/rautomation/adapter/ms_uia/text_field.rb +39 -0
  136. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +428 -0
  137. data/lib/rautomation/adapter/ms_uia/value_control.rb +21 -0
  138. data/lib/rautomation/adapter/ms_uia/window.rb +289 -0
  139. data/lib/rautomation/adapter/ms_uia.rb +27 -0
  140. data/lib/rautomation/adapter/win_32/button.rb +14 -0
  141. data/lib/rautomation/adapter/win_32/button_helper.rb +24 -0
  142. data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
  143. data/lib/rautomation/adapter/win_32/constants.rb +73 -0
  144. data/lib/rautomation/adapter/win_32/control.rb +86 -0
  145. data/lib/rautomation/adapter/win_32/functions.rb +336 -0
  146. data/lib/rautomation/adapter/win_32/keys.rb +146 -0
  147. data/lib/rautomation/adapter/win_32/label.rb +10 -0
  148. data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
  149. data/lib/rautomation/adapter/win_32/locators.rb +22 -0
  150. data/lib/rautomation/adapter/win_32/mouse.rb +59 -0
  151. data/lib/rautomation/adapter/win_32/password_field.rb +15 -0
  152. data/lib/rautomation/adapter/win_32/radio.rb +11 -0
  153. data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
  154. data/lib/rautomation/adapter/win_32/table.rb +25 -0
  155. data/lib/rautomation/adapter/win_32/text_field.rb +52 -0
  156. data/lib/rautomation/adapter/win_32/window.rb +277 -0
  157. data/lib/rautomation/adapter/win_32.rb +23 -0
  158. data/lib/rautomation/button.rb +55 -0
  159. data/lib/rautomation/element_collections.rb +55 -0
  160. data/lib/rautomation/platform.rb +15 -0
  161. data/lib/rautomation/text_field.rb +60 -0
  162. data/lib/rautomation/version.rb +3 -0
  163. data/lib/rautomation/wait_helper.rb +23 -0
  164. data/lib/rautomation/window.rb +248 -0
  165. data/lib/rautomation.rb +8 -0
  166. data/rautomation.gemspec +52 -0
  167. data/spec/adapter/autoit/mouse_spec.rb +53 -0
  168. data/spec/adapter/autoit/window_spec.rb +17 -0
  169. data/spec/adapter/ms_uia/button_spec.rb +39 -0
  170. data/spec/adapter/ms_uia/checkbox_spec.rb +55 -0
  171. data/spec/adapter/ms_uia/control_spec.rb +88 -0
  172. data/spec/adapter/ms_uia/functions_spec.rb +39 -0
  173. data/spec/adapter/ms_uia/keystroke_converter_spec.rb +48 -0
  174. data/spec/adapter/ms_uia/label_spec.rb +18 -0
  175. data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
  176. data/spec/adapter/ms_uia/listbox_spec.rb +73 -0
  177. data/spec/adapter/ms_uia/radio_spec.rb +39 -0
  178. data/spec/adapter/ms_uia/select_list_spec.rb +118 -0
  179. data/spec/adapter/ms_uia/spinner_spec.rb +44 -0
  180. data/spec/adapter/ms_uia/tab_control_spec.rb +53 -0
  181. data/spec/adapter/ms_uia/table_spec.rb +197 -0
  182. data/spec/adapter/ms_uia/text_field_spec.rb +43 -0
  183. data/spec/adapter/ms_uia/value_control_spec.rb +11 -0
  184. data/spec/adapter/ms_uia/window_spec.rb +81 -0
  185. data/spec/adapter/win_32/button_spec.rb +31 -0
  186. data/spec/adapter/win_32/checkbox_spec.rb +46 -0
  187. data/spec/adapter/win_32/label_spec.rb +13 -0
  188. data/spec/adapter/win_32/listbox_spec.rb +41 -0
  189. data/spec/adapter/win_32/mouse_spec.rb +49 -0
  190. data/spec/adapter/win_32/radio_spec.rb +33 -0
  191. data/spec/adapter/win_32/select_list_spec.rb +65 -0
  192. data/spec/adapter/win_32/table_spec.rb +27 -0
  193. data/spec/adapter/win_32/text_field_spec.rb +24 -0
  194. data/spec/adapter/win_32/window_spec.rb +61 -0
  195. data/spec/button_spec.rb +67 -0
  196. data/spec/buttons_spec.rb +21 -0
  197. data/spec/spec_helper.rb +128 -0
  198. data/spec/text_field_spec.rb +64 -0
  199. data/spec/text_fields_spec.rb +22 -0
  200. data/spec/window_spec.rb +150 -0
  201. data/spec/windows_spec.rb +76 -0
  202. metadata +369 -0
@@ -0,0 +1,248 @@
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
+ class UnsupportedAdapterException < RuntimeError
11
+ end
12
+
13
+ class Window
14
+ include Adapter::Helper
15
+ extend ElementCollections
16
+
17
+ has_many :windows, :buttons, :text_fields
18
+
19
+ class << self
20
+ # @param locators (see #initialize)
21
+ # @return [Windows] all windows.
22
+ def windows(locators = {})
23
+ Windows.new(nil, locators)
24
+ end
25
+ end
26
+
27
+ # Retrieves all windows with similar locators to the current window.
28
+ # @param locators (see #initialize)
29
+ # @return [Windows] all windows matching current window's _locators_ if no
30
+ # explicit locators specified or windows matching the specified _locators_.
31
+ def windows(locators = @window.locators)
32
+ Windows.new(nil, locators)
33
+ end
34
+
35
+ # Currently used {Adapter}.
36
+ attr_reader :adapter
37
+
38
+ # Creates the window object.
39
+ #
40
+ # Possible window _locators_ may depend of the used platform and adapter, but
41
+ # following examples will use :title, :class and :hwnd.
42
+ #
43
+ # @example Use window with some title:
44
+ # RAutomation::Window.new(:title => "some title")
45
+ #
46
+ # @example Use window with Regexp title:
47
+ # RAutomation::Window.new(:title => /some title/i)
48
+ #
49
+ # @example Use window with handle (hwnd):
50
+ # RAutomation::Window.new(:hwnd => 123456)
51
+ #
52
+ # @example Use multiple locators, every locator will be matched (AND-ed) to the window:
53
+ # RAutomation::Window.new(:title => "some title", :class => "IEFrame")
54
+ #
55
+ # @note Refer to all possible _locators_ in each {Adapter} documentation.
56
+ #
57
+ # _locators_ may also include a key called :adapter to change default adapter,
58
+ # which is dependent of the platform, to automate windows and their controls.
59
+ #
60
+ # It is also possible to change the default adapter by using environment variable called
61
+ # __RAUTOMATION_ADAPTER__
62
+ #
63
+ # @note This constructor doesn't check for window's existance.
64
+ # @note Only visible windows are supported.
65
+ # @note If given _locators_ include :hwnd then every other possible _locator_ is ignored.
66
+ # @param [Hash] locators locators for the window.
67
+ def initialize(locators)
68
+ @adapter = locators.delete(:adapter) || ENV["RAUTOMATION_ADAPTER"] && ENV["RAUTOMATION_ADAPTER"].to_sym || default_adapter
69
+ unless Adapter::Helper.supported_for_current_platform?(@adapter)
70
+ raise UnsupportedAdapterException, "RAutomation #{@adapter} adapter is only supported on a 32bit Ruby - please use either :win32 adapter or 32bit Ruby."
71
+ end
72
+
73
+ @window = Adapter.const_get(normalize(@adapter)).const_get(:Window).new(self, locators)
74
+ end
75
+
76
+ class << self
77
+ # Timeout for waiting until object exists. If the timeout exceeds then an {WaitHelper::TimeoutError} is raised.
78
+ @@wait_timeout = 60
79
+
80
+ # Change the timeout to wait before {WaitHelper::TimeoutError} is raised.
81
+ # @param [Integer] timeout in seconds.
82
+ def wait_timeout=(timeout)
83
+ @@wait_timeout = timeout
84
+ end
85
+
86
+ # Retrieve current timeout in seconds to wait before {WaitHelper::TimeoutError} is raised.
87
+ # @return [Integer] timeout in seconds
88
+ def wait_timeout
89
+ @@wait_timeout
90
+ end
91
+
92
+ end
93
+
94
+ # @return [Integer] handle of the window which is used internally for other methods.
95
+ # @raise [UnknownWindowException] if the window doesn't exist.
96
+ def hwnd
97
+ wait_until_present
98
+ @window.hwnd
99
+ end
100
+
101
+ # @return [Integer] process identifier (PID) of the window.
102
+ # @raise [UnknownWindowException] if the window doesn't exist.
103
+ def pid
104
+ wait_until_present
105
+ @window.pid
106
+ end
107
+
108
+ # @return [String] title of the window.
109
+ # @raise [UnknownWindowException] if the window doesn't exist.
110
+ def title
111
+ wait_until_present
112
+ @window.title
113
+ end
114
+
115
+ # @return [Array<String>] all {Window} class names in a sorted array.
116
+ # @raise [UnknownWindowException] if the window doesn't exist.
117
+ def class_names
118
+ wait_until_present
119
+ @window.class_names
120
+ end
121
+
122
+ # Activates the Window, e.g. brings it to the top of other windows.
123
+ def activate
124
+ @window.activate
125
+ end
126
+
127
+ # Checks if the window is active, e.g. on the top of other windows.
128
+ # @return [Boolean] true if the window is active, false otherwise.
129
+ def active?
130
+ @window.active?
131
+ end
132
+
133
+ # Returns visible text of the Window.
134
+ # @return [String] visible text of the window.
135
+ # @raise [UnknownWindowException] if the window doesn't exist.
136
+ def text
137
+ wait_until_present
138
+ @window.text
139
+ end
140
+
141
+ # Checks if the window exists (does have to be visible).
142
+ # @return [Boolean] true if the window exists, false otherwise.
143
+ def exists?
144
+ @window.exists?
145
+ end
146
+
147
+ alias_method :exist?, :exists?
148
+
149
+ # Checks if window is visible.
150
+ # @note Window is also visible, if it is behind other windows or minimized.
151
+ # @return [Boolean] true if window is visible, false otherwise.
152
+ # @raise [UnknownWindowException] if the window doesn't exist.
153
+ def visible?
154
+ wait_until_exists
155
+ @window.visible?
156
+ end
157
+
158
+ # Checks if the window exists and is visible.
159
+ # @return [Boolean] true if window exists and is visible, false otherwise
160
+ def present?
161
+ exists? && visible?
162
+ end
163
+
164
+ # Maximizes the window.
165
+ # @raise [UnknownWindowException] if the window doesn't exist.
166
+ def maximize
167
+ wait_until_present
168
+ @window.maximize
169
+ end
170
+
171
+ # Minimizes the window.
172
+ # @raise [UnknownWindowException] if the window doesn't exist.
173
+ def minimize
174
+ wait_until_present
175
+ @window.minimize
176
+ end
177
+
178
+ # Checks if window is minimized.
179
+ # @return [Boolean] true if window is minimized, false otherwise.
180
+ # @raise [UnknownWindowException] if the window doesn't exist.
181
+ def minimized?
182
+ wait_until_present
183
+ @window.minimized?
184
+ end
185
+
186
+ # Restores the window size and position.
187
+ # @note If the window is minimized, makes it visible again.
188
+ # @raise [UnknownWindowException] if the window doesn't exist.
189
+ def restore
190
+ wait_until_present
191
+ @window.restore
192
+ end
193
+
194
+ # Sends keyboard keys to the window. Refer to specific {Adapter} documentation for all possible values.
195
+ # @raise [UnknownWindowException] if the window doesn't exist.
196
+ def send_keys(*keys)
197
+ wait_until_present
198
+ @window.send_keys(keys)
199
+ end
200
+
201
+ # Closes the window if it exists.
202
+ def close
203
+ return unless @window.exists?
204
+ @window.close
205
+ end
206
+
207
+ # Retrieves {Button} on the window.
208
+ # @note Refer to specific {Adapter} documentation for possible _locator_ parameters.
209
+ # @param [Hash] locators for the {Button}.
210
+ # @raise [UnknownWindowException] if the window doesn't exist.
211
+ def button(locators={})
212
+ wait_until_present
213
+ Button.new(@window, locators)
214
+ end
215
+
216
+ # Retrieves {TextField} on the window.
217
+ # @note Refer to specific {Adapter} documentation for possible _locators_ parameters.
218
+ # @raise [UnknownWindowException] if the window doesn't exist.
219
+ def text_field(locators={})
220
+ wait_until_present
221
+ TextField.new(@window, locators)
222
+ end
223
+
224
+ # Allows to execute specific {Adapter} methods not part of the public API.
225
+ def method_missing(name, *args)
226
+ @window.send(name, *args)
227
+ end
228
+
229
+ def wait_until_present
230
+ WaitHelper.wait_until {present?}
231
+ rescue WaitHelper::TimeoutError
232
+ raise UnknownWindowException, "Window with locator #{@window.locators.inspect} doesn't exist or is not visible!"
233
+ end
234
+
235
+ def wait_until_exists
236
+ WaitHelper.wait_until {exists?}
237
+ rescue WaitHelper::TimeoutError
238
+ raise UnknownWindowException, "Window with locator #{@window.locators.inspect} doesn't exist!"
239
+ end
240
+
241
+ private
242
+
243
+ def normalize adapter
244
+ adapter.to_s.split("_").map {|word| word.capitalize}.join
245
+ end
246
+
247
+ end
248
+ end
@@ -0,0 +1,8 @@
1
+ require "rautomation/platform"
2
+ require "rautomation/wait_helper"
3
+ require "rautomation/adapter/helper"
4
+ require "rautomation/button"
5
+ require "rautomation/text_field"
6
+ require "rautomation/element_collections"
7
+ require "rautomation/window"
8
+ require "rautomation/version"
@@ -0,0 +1,52 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/rautomation/adapter/helper', __FILE__)
3
+ require File.expand_path('../lib/rautomation/version', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{rautomation}
7
+ s.version = RAutomation::VERSION
8
+ s.authors = [%q{Jarmo Pertman}]
9
+ s.email = %q{jarmo.p@gmail.com}
10
+ s.description = %q{RAutomation is a small and easy to use library for helping out to automate windows and their controls
11
+ for automated testing.
12
+
13
+ RAutomation provides:
14
+ * Easy to use and user-friendly API (inspired by Watir http://www.watir.com)
15
+ * Cross-platform compatibility
16
+ * Easy extensibility - with small scripting effort it's possible to add support for not yet
17
+ supported platforms or technologies}
18
+ s.homepage = %q{http://github.com/jarmo/RAutomation}
19
+ s.summary = %q{Automate windows and their controls through user-friendly API with Ruby}
20
+ s.license = "MIT"
21
+ s.platform = Gem::Platform.local if s.platform == 'ruby'
22
+
23
+ ext_locations = [
24
+ "ext/IAccessibleDLL/Release/IAccessibleDLL.dll",
25
+ "ext/UiaDll/Release/UiaDll.dll",
26
+ "ext/UiaDll/Release/RAutomation.UIA.dll"
27
+ ]
28
+
29
+ winforms_files = Dir[
30
+ "ext/WindowsForms/Release/*.dll",
31
+ "ext/WindowsForms/Release/*.exe"
32
+ ]
33
+
34
+ RAutomation::Adapter::Helper.find_missing_externals(ext_locations).each do |ext|
35
+ RAutomation::Adapter::Helper.build_solution(ext)
36
+ end
37
+
38
+ # move .dll files and get array containing paths
39
+ # send first three externals and first three characters from platform eg 'x86' from 'x86-mingw32'
40
+ externals = RAutomation::Adapter::Helper.move_adapter_dlls(ext_locations[0, 3], s.platform.to_s[0, 3])
41
+
42
+ s.files = `git ls-files`.split("\n") + externals + winforms_files
43
+ s.test_files = `git ls-files -- spec/*`.split("\n")
44
+ s.require_paths = ["lib"]
45
+
46
+ s.add_dependency("ffi", "~> 1.15.0")
47
+ s.add_development_dependency("rspec", "~> 3.9")
48
+ s.add_development_dependency("rake", "~> 10.5")
49
+ s.add_development_dependency("yard", "~> 0.9")
50
+ s.add_development_dependency("redcarpet", "~> 3.5")
51
+ s.add_development_dependency("github-markup", "~> 3.0")
52
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ describe "AutoIt::Mouse", :if => SpecHelper.adapter == :autoit do
4
+
5
+ it "#click" do
6
+ window = RAutomation::Window.new(:title => "MainFormWindow")
7
+
8
+ popup = RAutomation::Window.new(:title => "About")
9
+ popup.should_not be_present
10
+
11
+ window.maximize
12
+ mouse = window.mouse
13
+ mouse.move :x => 60, :y => 65
14
+ mouse.click
15
+
16
+ RAutomation::WaitHelper.wait_until {popup.present?}
17
+ end
18
+
19
+ it "#position" do
20
+ window = RAutomation::Window.new(:title => "MainFormWindow")
21
+ mouse = window.mouse
22
+
23
+ mouse.move :x => 13, :y => 16
24
+ mouse.position.should == {:x => 13, :y => 16}
25
+ end
26
+
27
+ it "#press/#release" do
28
+ window = RAutomation::Window.new(:title => "MainFormWindow")
29
+ window.maximize
30
+
31
+ text_field = window.text_field(:index => 2)
32
+ text_field.set("start string")
33
+ text_field.value.should == "start string"
34
+
35
+ mouse = window.mouse
36
+ mouse.move :x => 146, :y => 125
37
+ mouse.press
38
+ mouse.move :x => 194
39
+ mouse.release
40
+ window.send_keys "^c"
41
+
42
+ text_field.set("new string")
43
+ text_field.value.should == "new string"
44
+
45
+ mouse.move :x => 146
46
+ mouse.press
47
+ mouse.move :x => 194
48
+ mouse.release
49
+ window.send_keys "^v"
50
+
51
+ text_field.value.should == "start string"
52
+ end
53
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe "AutoIt::Window", :if => SpecHelper.adapter == :autoit do
4
+ it "#method_missing" do
5
+ window = RAutomation::Window.new(:title => "MainFormWindow")
6
+
7
+ window.MouseMove(1, 1)
8
+ position = [window.MouseGetPosX, window.MouseGetPosY]
9
+ position.should_not == [100, 100]
10
+
11
+ window.MouseMove(100, 100)
12
+ position = [window.MouseGetPosX, window.MouseGetPosY]
13
+
14
+ position.should == [100, 100]
15
+ end
16
+ end
17
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MsUia::Button", if: SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(title: SpecHelper::DATA[:window1_title]) }
5
+ it "find by id" do
6
+ expect(window.button(id: "aboutButton").exist?).to be true
7
+ end
8
+
9
+ it "check for button class" do
10
+ expect(window.button(id: "textField").exist?).to_not be true
11
+ end
12
+
13
+
14
+ it "enabled/disabled" do
15
+ expect(window.button(id: "enabledButton").enabled?).to be true
16
+ expect(window.button(id: "enabledButton").disabled?).to_not be be true
17
+
18
+ expect(window.button(id: "disabledButton").disabled?).to be true
19
+ expect(window.button(id: "disabledButton").enabled?).to_not be true
20
+ end
21
+
22
+ it "#focus" do
23
+ button = window.button(id: "enabledButton")
24
+ expect(button.focused?).to_not be true
25
+
26
+ button.focus
27
+ expect(button.focused?).to be true
28
+ end
29
+
30
+ it "cannot click disabled button" do
31
+ expect { window.button(id: "disabledButton").click }.to raise_error(RuntimeError)
32
+ end
33
+
34
+ it "cannot set focus to disabled button" do
35
+ window = RAutomation::Window.new(title: SpecHelper::DATA[:window1_title])
36
+ expect { window.button(id: "disabledButton").focus }.to raise_error(RuntimeError)
37
+ end
38
+
39
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MsUia::Checkbox", if: SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(title: "MainFormWindow") }
5
+ it "#checkbox" do
6
+ expect(window.checkbox(value: "checkBox").exist?).to be true
7
+
8
+ RAutomation::Window.wait_timeout = 0.1
9
+ expect { RAutomation::Window.new(title: "non-existing-window").checkbox(value: "Something") }.
10
+ to raise_exception(RAutomation::UnknownWindowException)
11
+ end
12
+
13
+ it "check for checkbox class" do
14
+ expect(window.checkbox(id: "textField").exist?).to_not be true
15
+ expect(window.checkbox(id: "checkBox").exist?).to be true
16
+ end
17
+
18
+
19
+ it "#set? & #set" do
20
+ checkbox = window.checkbox(value: "checkBox")
21
+ expect(checkbox.set?).to_not be true
22
+
23
+ checkbox.set
24
+ expect(checkbox.set?).to be true
25
+ end
26
+
27
+ it "#value" do
28
+ checkbox = window.checkbox(id: "checkBox")
29
+ expect(checkbox.value).to be == "checkBox"
30
+ end
31
+
32
+ it "#clear" do
33
+ checkbox = window.checkbox(value: "checkBox")
34
+ checkbox.set
35
+ expect(checkbox.set?).to be true
36
+
37
+ checkbox.clear
38
+ expect(checkbox.set?).to_not be true
39
+ end
40
+
41
+ it "enabled/disabled" do
42
+ expect(window.checkbox(id: "checkBox").enabled?).to be true
43
+ expect(window.checkbox(id: "checkBox").disabled?).to_not be true
44
+
45
+ expect(window.checkbox(id: "checkBoxDisabled").enabled?).to_not be true
46
+ expect(window.checkbox(id: "checkBoxDisabled").disabled?).to be true
47
+ end
48
+
49
+ it "cannot check a disabled checkbox" do
50
+ expect {
51
+ window.checkbox(id: "checkBoxDisabled").set
52
+ }.to raise_error(RuntimeError)
53
+ end
54
+
55
+ end
@@ -0,0 +1,88 @@
1
+ require "spec_helper"
2
+
3
+ describe "MsUia::Control", if: SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(title: /MainFormWindow/i) }
5
+
6
+ context '#click' do
7
+ it 'stops trying after the window goes away' do
8
+ window.button(value: 'About').click { true }
9
+
10
+ RAutomation::Window.new(title: 'About').button(id: 'button1').click
11
+ end
12
+ end
13
+
14
+ it "control coordinates", special: false do
15
+ window.maximize
16
+ control = window.control(id: "radioButtonReset")
17
+ expect(control.bounding_rectangle).to be_all {|coord| coord.between?(200, 400)}
18
+ end
19
+
20
+ it "control process id", special: true do
21
+ control = window.control(id: "radioButtonReset")
22
+ expect(control.new_pid).to be == @pid1
23
+ end
24
+
25
+ it "has a class" do
26
+ control = window.control(id: "radioButtonReset")
27
+ expect(control.control_class).to be =~ /WindowsForms10.BUTTON.*/
28
+ end
29
+
30
+ it "can get tooltip information" do
31
+ control = window.button(value: 'Reset')
32
+ expect(control.help_text).to eq 'Some help text'
33
+ end
34
+
35
+ it "can limit the search depth" do
36
+ window.button(id: 'buttonDataGridView').click { true }
37
+ data_grid_window = RAutomation::Window.new(title: /DataGridView/i)
38
+
39
+ start = Time.new
40
+ data_grid_window.button(id: 'buttonClose', children_only: true).exist?
41
+ elapsed_time = Time.new - start
42
+ expect(elapsed_time).to be < 2
43
+ end
44
+
45
+ context RAutomation::Adapter::MsUia::UiaDll::SearchCriteria, pure_unit: true do
46
+ let(:window) { double('RAutomation Window').as_null_object }
47
+ let(:locator) { {id: 'someId'} }
48
+ let(:control) { RAutomation::Adapter::MsUia::Control.new(window, locator) }
49
+ let(:old_style_control) { RAutomation::Adapter::MsUia::Control.new(window, class: 'someClass') }
50
+ let(:expect_a_handle) { expect(RAutomation::Adapter::MsUia::UiaDll).to receive(:cached_hwnd).once.and_return(456) }
51
+ let(:expect_no_handle) { expect(RAutomation::Adapter::MsUia::UiaDll).to receive(:cached_hwnd).once.and_return(0) }
52
+ subject { control.search_information }
53
+
54
+ before(:each) do
55
+ expect(window).to receive(:hwnd).at_least(:once).and_return(123)
56
+ allow(RAutomation::Adapter::MsUia::Functions).to receive(:control_hwnd)
57
+ end
58
+
59
+ it "uses the cached window handle if it has one" do
60
+ expect_a_handle
61
+ expect(subject.how).to eq(:hwnd)
62
+ expect(subject.data).to eq(456)
63
+ end
64
+
65
+ it "only asks for the window handle once" do
66
+ expect_a_handle
67
+ 2.times { control.search_information }
68
+ end
69
+
70
+ it "uses the locator specified when no window handle is present" do
71
+ expect_no_handle
72
+ expect(subject.how).to eq(:id)
73
+ expect(subject.data).to eq('someId')
74
+ end
75
+
76
+ it "tries the old way of locating the window handle if no UIA locator is provided" do
77
+ expect_no_handle
78
+ expect(RAutomation::Adapter::MsUia::Functions).to receive(:control_hwnd)
79
+ .with(window.hwnd, index: 0, class: 'someClass')
80
+ .and_return(789)
81
+ old_info = old_style_control.search_information
82
+ expect(old_info.how).to eq(:hwnd)
83
+ expect(old_info.data).to eq(789)
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MsUia::Functions", if: SpecHelper.adapter == :ms_uia do
4
+ context "working with expandable / collapsable items" do
5
+ let(:tree_view) { RAutomation::Window.new(title: "MainFormWindow").select_list(id: "treeView") }
6
+
7
+ def options
8
+ tree_view.options.map(&:text)
9
+ end
10
+
11
+ it "can be expanded by value" do
12
+ expect(options).to eq(["Parent One", "Parent Two"])
13
+ tree_view.expand "Parent One"
14
+ expect(options).to eq(["Parent One", "Child 1", "Child 2", "Parent Two"])
15
+ end
16
+
17
+ it "can be expanded by index" do
18
+ expect(options).to eq(["Parent One", "Parent Two"])
19
+ tree_view.expand(0)
20
+ tree_view.expand(2)
21
+ expect(options).to eq(["Parent One", "Child 1", "Child 2", "Grandchild 1", "Parent Two"])
22
+ end
23
+
24
+ it "can be collapsed by value" do
25
+ tree_view.expand("Parent One")
26
+ expect(options).to eq(["Parent One", "Child 1", "Child 2", "Parent Two"])
27
+ tree_view.collapse "Parent One"
28
+ expect(options).to eq(["Parent One", "Parent Two"])
29
+ end
30
+
31
+ it "can be collapsed by index" do
32
+ tree_view.expand(0)
33
+ expect(options).to eq(["Parent One", "Child 1", "Child 2", "Parent Two"])
34
+ tree_view.collapse(0)
35
+ expect(options).to eq(["Parent One", "Parent Two"])
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe "KeystrokeConverter", if: SpecHelper.adapter == :ms_uia do
4
+
5
+ it "converts plain ASCII" do
6
+ codes = RAutomation::Adapter::MsUia::KeystrokeConverter.convert("abc")
7
+ converted_keys = convert_keys "abc"
8
+ expect(codes).to be == converted_keys
9
+ end
10
+
11
+ it "uses caps lock for entering downcase keys" do
12
+ codes = RAutomation::Adapter::MsUia::KeystrokeConverter.convert("aBc")
13
+ converted_keys = convert_keys "abc"
14
+ converted_keys = converted_keys.insert(1, RAutomation::Adapter::MsUia::Constants::VK_LSHIFT)
15
+ expect(codes).to be == converted_keys
16
+ end
17
+
18
+ it "converts special keys" do
19
+ codes = RAutomation::Adapter::MsUia::KeystrokeConverter.convert("{tab}a{backspace}b{enter}c {left}d{right}ee{down}f{up}g{unsupported}{home}{end}{delete}")
20
+ expected_codes = [
21
+ RAutomation::Adapter::MsUia::Constants::VK_TAB,
22
+ convert_keys("a"),
23
+ RAutomation::Adapter::MsUia::Constants::VK_BACK,
24
+ convert_keys("b"),
25
+ RAutomation::Adapter::MsUia::Constants::VK_RETURN,
26
+ convert_keys("c"),
27
+ RAutomation::Adapter::MsUia::Constants::VK_SPACE,
28
+ RAutomation::Adapter::MsUia::Constants::VK_LEFT,
29
+ convert_keys("d"),
30
+ RAutomation::Adapter::MsUia::Constants::VK_RIGHT,
31
+ convert_keys("ee"),
32
+ RAutomation::Adapter::MsUia::Constants::VK_DOWN,
33
+ convert_keys("f"),
34
+ RAutomation::Adapter::MsUia::Constants::VK_UP,
35
+ convert_keys("g"),
36
+ convert_keys("unsupported"),
37
+ RAutomation::Adapter::MsUia::Constants::VK_HOME,
38
+ RAutomation::Adapter::MsUia::Constants::VK_END,
39
+ RAutomation::Adapter::MsUia::Constants::VK_DELETE
40
+ ].flatten
41
+ expect(codes).to be == expected_codes
42
+ end
43
+
44
+ def convert_keys keys
45
+ keys.split("").map { |k| k.upcase.unpack("c")[0] }
46
+ end
47
+
48
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MsUia::Label", if: SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(title: "MainFormWindow") }
5
+ it "#exist?" do
6
+ expect(window.label(value: "This is a sample text").exist?).to be true
7
+ expect(window.label(value: "This label should not exist").exist?).to_not be true
8
+ end
9
+
10
+ it "check for label class" do
11
+ expect(window.label(id: "textField").exist?).to_not be true
12
+ expect(window.label(id: "label1").exists?).to be true
13
+ end
14
+
15
+ it "#label" do
16
+ expect(window.label(value: "This is a sample text").value).to be == "This is a sample text"
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe "MsUia::ListItem", if: SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(title: "MainFormWindow") }
5
+ it "#exists" do
6
+ expect(window.list_item(value: "Apple").exist?).to be true
7
+ expect(window.list_item(value: "This is a sample text").exist?).to_not be true
8
+ end
9
+
10
+ it "#value" do
11
+ expect(window.list_item(value: "Apple").value).to be == "Apple"
12
+ end
13
+
14
+ end