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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +41 -0
- data/.rspec +2 -0
- data/.yardopts +8 -0
- data/CHANGES.md +276 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +142 -0
- data/Rakefile +73 -0
- data/ext/AutoItX/AutoItX.chm +0 -0
- data/ext/AutoItX/AutoItX3.dll +0 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.cpp +30 -0
- data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj +179 -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/IAccessibleDLL.sln +31 -0
- data/ext/IAccessibleDLL/IAccessibleDLL.suo +0 -0
- data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/Clicker.cs +63 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/SelectList.cs +116 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/Spinner.cs +46 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/TabControl.cs +54 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/TableControl.cs +132 -0
- data/ext/UiaDll/RAutomation.UIA/Controls/TextControl.cs +50 -0
- data/ext/UiaDll/RAutomation.UIA/Expander.cs +59 -0
- data/ext/UiaDll/RAutomation.UIA/Extensions/Element.cs +166 -0
- data/ext/UiaDll/RAutomation.UIA/Extensions/Enumerable.cs +76 -0
- data/ext/UiaDll/RAutomation.UIA/Extensions/Property.cs +27 -0
- data/ext/UiaDll/RAutomation.UIA/Properties/AssemblyInfo.cs +36 -0
- data/ext/UiaDll/RAutomation.UIA/Properties/AutomationProperties.cs +18 -0
- data/ext/UiaDll/RAutomation.UIA/RAutomation.UIA.csproj +77 -0
- data/ext/UiaDll/Release/RAutomation.UIA.dll +0 -0
- data/ext/UiaDll/Release/UiaDll.dll +0 -0
- data/ext/UiaDll/UiaDll/ArrayHelper.cpp +14 -0
- data/ext/UiaDll/UiaDll/ArrayHelper.h +7 -0
- data/ext/UiaDll/UiaDll/AssemblyInfo.cpp +40 -0
- data/ext/UiaDll/UiaDll/ControlMethods.cpp +16 -0
- data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.cpp +24 -0
- data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.h +16 -0
- data/ext/UiaDll/UiaDll/Locator.cpp +93 -0
- data/ext/UiaDll/UiaDll/Locator.h +55 -0
- data/ext/UiaDll/UiaDll/MenuItemSelector.cpp +75 -0
- data/ext/UiaDll/UiaDll/MenuItemSelector.h +24 -0
- data/ext/UiaDll/UiaDll/MenuMethods.cpp +62 -0
- data/ext/UiaDll/UiaDll/ReadMe.txt +38 -0
- data/ext/UiaDll/UiaDll/SelectListMethods.cpp +84 -0
- data/ext/UiaDll/UiaDll/SpinnerMethods.cpp +61 -0
- data/ext/UiaDll/UiaDll/StringHelper.cpp +57 -0
- data/ext/UiaDll/UiaDll/StringHelper.h +15 -0
- data/ext/UiaDll/UiaDll/StringMethods.cpp +8 -0
- data/ext/UiaDll/UiaDll/TabControlMethods.cpp +40 -0
- data/ext/UiaDll/UiaDll/TableMethods.cpp +108 -0
- data/ext/UiaDll/UiaDll/TextMethods.cpp +25 -0
- data/ext/UiaDll/UiaDll/ToggleStateHelper.h +10 -0
- data/ext/UiaDll/UiaDll/UiaDll.cpp +216 -0
- data/ext/UiaDll/UiaDll/UiaDll.h +13 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj +167 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +110 -0
- data/ext/UiaDll/UiaDll/app.ico +0 -0
- data/ext/UiaDll/UiaDll/app.rc +0 -0
- data/ext/UiaDll/UiaDll/dllmain.cpp +1 -0
- data/ext/UiaDll/UiaDll/resource.h +3 -0
- data/ext/UiaDll/UiaDll/stdafx.cpp +5 -0
- data/ext/UiaDll/UiaDll/stdafx.h +41 -0
- data/ext/UiaDll/UiaDll/targetver.h +8 -0
- data/ext/UiaDll/UiaDll.sln +57 -0
- data/ext/WindowsForms/.nuget/NuGet.Config +6 -0
- data/ext/WindowsForms/.nuget/NuGet.exe +0 -0
- data/ext/WindowsForms/.nuget/NuGet.targets +136 -0
- data/ext/WindowsForms/Release/FizzWare.NBuilder.dll +0 -0
- data/ext/WindowsForms/Release/UIA.Extensions.dll +0 -0
- data/ext/WindowsForms/Release/WindowsForms.exe +0 -0
- data/ext/WindowsForms/WindowsForms/AboutBox.Designer.cs +168 -0
- data/ext/WindowsForms/WindowsForms/AboutBox.cs +103 -0
- data/ext/WindowsForms/WindowsForms/AboutBox.resx +123 -0
- data/ext/WindowsForms/WindowsForms/DataEntryForm.Designer.cs +218 -0
- data/ext/WindowsForms/WindowsForms/DataEntryForm.cs +52 -0
- data/ext/WindowsForms/WindowsForms/DataEntryForm.resx +120 -0
- data/ext/WindowsForms/WindowsForms/DataGridView.Designer.cs +77 -0
- data/ext/WindowsForms/WindowsForms/DataGridView.cs +43 -0
- data/ext/WindowsForms/WindowsForms/DataGridView.resx +120 -0
- data/ext/WindowsForms/WindowsForms/FizzWare.NBuilder.dll +0 -0
- data/ext/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +527 -0
- data/ext/WindowsForms/WindowsForms/MainFormWindow.cs +109 -0
- data/ext/WindowsForms/WindowsForms/MainFormWindow.resx +126 -0
- data/ext/WindowsForms/WindowsForms/PersonForm.Designer.cs +119 -0
- data/ext/WindowsForms/WindowsForms/PersonForm.cs +34 -0
- data/ext/WindowsForms/WindowsForms/PersonForm.resx +120 -0
- data/ext/WindowsForms/WindowsForms/Program.cs +21 -0
- data/ext/WindowsForms/WindowsForms/Properties/AssemblyInfo.cs +36 -0
- data/ext/WindowsForms/WindowsForms/Properties/Resources.Designer.cs +71 -0
- data/ext/WindowsForms/WindowsForms/Properties/Resources.resx +117 -0
- data/ext/WindowsForms/WindowsForms/Properties/Settings.Designer.cs +30 -0
- data/ext/WindowsForms/WindowsForms/Properties/Settings.settings +7 -0
- data/ext/WindowsForms/WindowsForms/SimpleElementsForm.Designer.cs +93 -0
- data/ext/WindowsForms/WindowsForms/SimpleElementsForm.cs +19 -0
- data/ext/WindowsForms/WindowsForms/SimpleElementsForm.resx +120 -0
- data/ext/WindowsForms/WindowsForms/UIA.Extensions.dll +0 -0
- data/ext/WindowsForms/WindowsForms/ValueMonthCalendar.cs +28 -0
- data/ext/WindowsForms/WindowsForms/WindowsForms.csproj +166 -0
- data/ext/WindowsForms/WindowsForms/packages.config +4 -0
- data/ext/WindowsForms/WindowsForms.sln +46 -0
- data/lib/rautomation/adapter/autoit/button.rb +59 -0
- data/lib/rautomation/adapter/autoit/locators.rb +22 -0
- data/lib/rautomation/adapter/autoit/mouse.rb +38 -0
- data/lib/rautomation/adapter/autoit/text_field.rb +70 -0
- data/lib/rautomation/adapter/autoit/window.rb +197 -0
- data/lib/rautomation/adapter/autoit.rb +8 -0
- data/lib/rautomation/adapter/helper.rb +64 -0
- data/lib/rautomation/adapter/ms_uia/button.rb +21 -0
- data/lib/rautomation/adapter/ms_uia/button_helper.rb +19 -0
- data/lib/rautomation/adapter/ms_uia/checkbox.rb +23 -0
- data/lib/rautomation/adapter/ms_uia/constants.rb +111 -0
- data/lib/rautomation/adapter/ms_uia/control.rb +134 -0
- data/lib/rautomation/adapter/ms_uia/functions.rb +279 -0
- data/lib/rautomation/adapter/ms_uia/keys.rb +121 -0
- data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
- data/lib/rautomation/adapter/ms_uia/label.rb +18 -0
- data/lib/rautomation/adapter/ms_uia/list_box.rb +46 -0
- data/lib/rautomation/adapter/ms_uia/list_item.rb +22 -0
- data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
- data/lib/rautomation/adapter/ms_uia/menu.rb +36 -0
- data/lib/rautomation/adapter/ms_uia/radio.rb +23 -0
- data/lib/rautomation/adapter/ms_uia/select_list.rb +85 -0
- data/lib/rautomation/adapter/ms_uia/spinner.rb +31 -0
- data/lib/rautomation/adapter/ms_uia/tab_control.rb +46 -0
- data/lib/rautomation/adapter/ms_uia/table.rb +140 -0
- data/lib/rautomation/adapter/ms_uia/text_field.rb +39 -0
- data/lib/rautomation/adapter/ms_uia/uia_dll.rb +428 -0
- data/lib/rautomation/adapter/ms_uia/value_control.rb +21 -0
- data/lib/rautomation/adapter/ms_uia/window.rb +289 -0
- data/lib/rautomation/adapter/ms_uia.rb +27 -0
- data/lib/rautomation/adapter/win_32/button.rb +14 -0
- data/lib/rautomation/adapter/win_32/button_helper.rb +24 -0
- data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
- data/lib/rautomation/adapter/win_32/constants.rb +73 -0
- data/lib/rautomation/adapter/win_32/control.rb +86 -0
- data/lib/rautomation/adapter/win_32/functions.rb +336 -0
- data/lib/rautomation/adapter/win_32/keys.rb +146 -0
- data/lib/rautomation/adapter/win_32/label.rb +10 -0
- data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
- data/lib/rautomation/adapter/win_32/locators.rb +22 -0
- data/lib/rautomation/adapter/win_32/mouse.rb +59 -0
- data/lib/rautomation/adapter/win_32/password_field.rb +15 -0
- data/lib/rautomation/adapter/win_32/radio.rb +11 -0
- data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
- data/lib/rautomation/adapter/win_32/table.rb +25 -0
- data/lib/rautomation/adapter/win_32/text_field.rb +52 -0
- data/lib/rautomation/adapter/win_32/window.rb +277 -0
- data/lib/rautomation/adapter/win_32.rb +23 -0
- data/lib/rautomation/button.rb +55 -0
- data/lib/rautomation/element_collections.rb +55 -0
- data/lib/rautomation/platform.rb +15 -0
- data/lib/rautomation/text_field.rb +60 -0
- data/lib/rautomation/version.rb +3 -0
- data/lib/rautomation/wait_helper.rb +23 -0
- data/lib/rautomation/window.rb +248 -0
- data/lib/rautomation.rb +8 -0
- data/rautomation.gemspec +52 -0
- data/spec/adapter/autoit/mouse_spec.rb +53 -0
- data/spec/adapter/autoit/window_spec.rb +17 -0
- data/spec/adapter/ms_uia/button_spec.rb +39 -0
- data/spec/adapter/ms_uia/checkbox_spec.rb +55 -0
- data/spec/adapter/ms_uia/control_spec.rb +88 -0
- data/spec/adapter/ms_uia/functions_spec.rb +39 -0
- data/spec/adapter/ms_uia/keystroke_converter_spec.rb +48 -0
- data/spec/adapter/ms_uia/label_spec.rb +18 -0
- data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
- data/spec/adapter/ms_uia/listbox_spec.rb +73 -0
- data/spec/adapter/ms_uia/radio_spec.rb +39 -0
- data/spec/adapter/ms_uia/select_list_spec.rb +118 -0
- data/spec/adapter/ms_uia/spinner_spec.rb +44 -0
- data/spec/adapter/ms_uia/tab_control_spec.rb +53 -0
- data/spec/adapter/ms_uia/table_spec.rb +197 -0
- data/spec/adapter/ms_uia/text_field_spec.rb +43 -0
- data/spec/adapter/ms_uia/value_control_spec.rb +11 -0
- data/spec/adapter/ms_uia/window_spec.rb +81 -0
- data/spec/adapter/win_32/button_spec.rb +31 -0
- data/spec/adapter/win_32/checkbox_spec.rb +46 -0
- data/spec/adapter/win_32/label_spec.rb +13 -0
- data/spec/adapter/win_32/listbox_spec.rb +41 -0
- data/spec/adapter/win_32/mouse_spec.rb +49 -0
- data/spec/adapter/win_32/radio_spec.rb +33 -0
- data/spec/adapter/win_32/select_list_spec.rb +65 -0
- data/spec/adapter/win_32/table_spec.rb +27 -0
- data/spec/adapter/win_32/text_field_spec.rb +24 -0
- data/spec/adapter/win_32/window_spec.rb +61 -0
- data/spec/button_spec.rb +67 -0
- data/spec/buttons_spec.rb +21 -0
- data/spec/spec_helper.rb +128 -0
- data/spec/text_field_spec.rb +64 -0
- data/spec/text_fields_spec.rb +22 -0
- data/spec/window_spec.rb +150 -0
- data/spec/windows_spec.rb +76 -0
- 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
|
data/lib/rautomation.rb
ADDED
@@ -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"
|
data/rautomation.gemspec
ADDED
@@ -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
|