bewildr 0.1.8 → 0.1.9
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/Rakefile +2 -1
- data/lib/bewildr.rb +4 -0
- data/lib/bewildr/application.rb +38 -4
- data/lib/bewildr/control_patterns/toggle_pattern.rb +6 -2
- data/lib/bewildr/control_type_additions/combo_box_additions.rb +1 -1
- data/lib/bewildr/control_type_additions/list_additions.rb +2 -1
- data/lib/bewildr/control_type_additions/scroll_additions.rb +1 -1
- data/lib/bewildr/element.rb +50 -30
- data/lib/bewildr/finder.rb +28 -1
- data/lib/bewildr/mouse.rb +99 -0
- metadata +22 -6
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ require 'cucumber/rake/task'
|
|
10
10
|
|
11
11
|
spec = Gem::Specification.new do |s|
|
12
12
|
s.name = 'bewildr'
|
13
|
-
s.version = '0.1.
|
13
|
+
s.version = '0.1.9'
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
|
16
16
|
s.summary = 'Test WPF UI apps with IronRuby'
|
@@ -21,6 +21,7 @@ spec = Gem::Specification.new do |s|
|
|
21
21
|
s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{bin,lib}/**/*")
|
22
22
|
s.require_path = "lib"
|
23
23
|
s.bindir = "bin"
|
24
|
+
s.add_dependency('activesupport', '>= 3.0.0')
|
24
25
|
end
|
25
26
|
|
26
27
|
Rake::GemPackageTask.new(spec) do |p|
|
data/lib/bewildr.rb
CHANGED
@@ -11,6 +11,7 @@ load_assembly 'UIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyTo
|
|
11
11
|
load_assembly 'UIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
|
12
12
|
load_assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
|
13
13
|
load_assembly 'System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
|
14
|
+
load_assembly 'WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
|
14
15
|
|
15
16
|
#require BewildrClickr - stopgap until the ffi gem works under ironruby
|
16
17
|
require File.join(File.expand_path(File.dirname(__FILE__)), "bewildr", "ext", "BewildrClickr.dll")
|
@@ -18,6 +19,8 @@ CLICKR = Bewildr::Clickr::Clickr.new
|
|
18
19
|
|
19
20
|
#load plain old ruby libraries
|
20
21
|
require 'timeout'
|
22
|
+
require 'singleton'
|
23
|
+
require 'active_support/core_ext/string/inflections'
|
21
24
|
|
22
25
|
#require ruby extensions
|
23
26
|
require 'bewildr/ext/extensions'
|
@@ -30,6 +33,7 @@ require 'bewildr/finder'
|
|
30
33
|
require 'bewildr/application'
|
31
34
|
require 'bewildr/windows'
|
32
35
|
require 'bewildr/element'
|
36
|
+
require 'bewildr/mouse'
|
33
37
|
|
34
38
|
require 'bewildr/control_patterns/window_pattern'
|
35
39
|
require 'bewildr/control_patterns/value_pattern'
|
data/lib/bewildr/application.rb
CHANGED
@@ -1,35 +1,52 @@
|
|
1
1
|
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
2
|
|
3
3
|
module Bewildr
|
4
|
+
#Wraps System::Diagnostics::Process object and provides class methods to interrogate currently running
|
5
|
+
#processes, attach to processes or start new ones
|
4
6
|
class Application
|
7
|
+
#Returns a new instance of Bewildr::Application that wraps the process passed as the argument
|
5
8
|
def initialize(proc)
|
6
9
|
@proc = proc
|
7
10
|
@proc.wait_for_input_idle(10)
|
8
|
-
@proc_id = proc.id
|
9
11
|
end
|
10
12
|
private :initialize
|
11
13
|
|
14
|
+
#Returns the id of the underlying process
|
15
|
+
def proc_id
|
16
|
+
running? ? @proc.id.to_i : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
#Return the name of the underlying process
|
20
|
+
def name
|
21
|
+
running? ? @proc.process_name.to_s : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
#kills this process. Uses taskkill to perform the butchery
|
12
25
|
def kill
|
13
|
-
`taskkill /f /t /pid #{
|
26
|
+
`taskkill /f /t /pid #{proc_id}`
|
14
27
|
Timeout::timeout(5) do
|
15
28
|
sleep 0.1 while running?
|
16
29
|
end
|
17
30
|
end
|
18
31
|
|
32
|
+
#Returns true if this process is running, false if it isn't
|
19
33
|
def running?
|
20
34
|
@proc.nil? ? false : !@proc.has_exited
|
21
35
|
end
|
22
36
|
|
37
|
+
#Waits for up to 30 seconds for the process to terminate
|
23
38
|
def wait_for_termination
|
24
39
|
Timeout::timeout(30) do
|
25
40
|
sleep 0.2 while running?
|
26
41
|
end
|
27
42
|
end
|
28
43
|
|
44
|
+
#Returns a list of windows associated with this application
|
29
45
|
def windows
|
30
|
-
Bewildr::Windows.windows_by_process_id(
|
46
|
+
Bewildr::Windows.windows_by_process_id(proc_id)
|
31
47
|
end
|
32
48
|
|
49
|
+
#Returns a window whose title matches the string or regex passed in as the argument
|
33
50
|
def window_by_name(input)
|
34
51
|
case input
|
35
52
|
when String then return windows.select{|window| window.name.strip == input.strip}.first
|
@@ -40,6 +57,9 @@ module Bewildr
|
|
40
57
|
end
|
41
58
|
alias :window :window_by_name
|
42
59
|
|
60
|
+
#Waits for up to 30 seconds for a window belonging to this application to appear. When it does, a
|
61
|
+
#Bewildr::Element representing the window is returned. This method allows you in one line to wait
|
62
|
+
#for a window to appear and also return it
|
43
63
|
def wait_for_window(input, wait_time = 30)
|
44
64
|
begin
|
45
65
|
Timeout::timeout(wait_time) do
|
@@ -57,12 +77,15 @@ module Bewildr
|
|
57
77
|
end
|
58
78
|
end
|
59
79
|
|
60
|
-
#
|
80
|
+
#Returns a new instance of Bewildr::Application wrapping the process created when the specified exe file is invoked.
|
81
|
+
# Application.start("notepad.exe")
|
82
|
+
# Application.start("c:\some\path\my_app.exe")
|
61
83
|
def self.start(process_name)
|
62
84
|
raise "Can't find: #{process_name}" unless File.exist?(process_name)
|
63
85
|
Bewildr::Application.new(System::Diagnostics::Process.start(process_name))
|
64
86
|
end
|
65
87
|
|
88
|
+
#Same as the start method but allows the passing of arguments
|
66
89
|
def self.start_with_settings(path_to_exe, settings_hash)
|
67
90
|
start_info = System::Diagnostics::ProcessStartInfo.new(path_to_exe)
|
68
91
|
unless settings_hash[:args].nil? and settings_hash[:args].size > 0
|
@@ -71,14 +94,18 @@ module Bewildr
|
|
71
94
|
Bewildr::Application.new(System::Diagnostics::Process.start(start_info))
|
72
95
|
end
|
73
96
|
|
97
|
+
#Returns a Bewildr::Application wrapping a process already in memory where the argument is the process name
|
74
98
|
def self.attach_to_process_name(process_name)
|
75
99
|
Bewildr::Application.new(System::Diagnostics::Process.get_processes_by_name(process_name).first)
|
76
100
|
end
|
77
101
|
|
102
|
+
#Returns a Bewildr::Application wrapping a process already in memory where the argument is the process object to be wrapped
|
78
103
|
def self.attach_to_process(process)
|
79
104
|
Bewildr::Application.new(process)
|
80
105
|
end
|
81
106
|
|
107
|
+
#Given an exe name/path this method will return a new Bewildr::Application based either on a process already in memory
|
108
|
+
#or the process started by executing the app at the path specified in the argument
|
82
109
|
def self.attach_or_launch(path_to_exe)
|
83
110
|
#if app is already open attach to it
|
84
111
|
potential_process_name = File.basename(path_to_exe, ".exe")
|
@@ -91,12 +118,15 @@ module Bewildr
|
|
91
118
|
end
|
92
119
|
end
|
93
120
|
|
121
|
+
#Starts the app specified in the first argument and then waits and returns the window that matches the
|
122
|
+
#string or regex passed as the second argument
|
94
123
|
def self.start_app_and_wait_for_window(path, window_name)
|
95
124
|
app = Bewildr::Application.start(path)
|
96
125
|
window = app.wait_for_window(window_name)
|
97
126
|
return app, window
|
98
127
|
end
|
99
128
|
|
129
|
+
#Kills all processes that match the name passed as an argument
|
100
130
|
def self.kill_all_processes_with_name(input)
|
101
131
|
System::Diagnostics::Process.get_processes_by_name(input).each do |p|
|
102
132
|
p.kill
|
@@ -104,10 +134,14 @@ module Bewildr
|
|
104
134
|
end
|
105
135
|
end
|
106
136
|
|
137
|
+
#Returns an array of Bewildr::Application instances wrapping processes whose name match the string
|
138
|
+
#passed as an argument
|
107
139
|
def self.processes_with_name(input)
|
108
140
|
System::Diagnostics::Process.get_processes_by_name(input).collect {|p| Bewildr::Application.attach_to_process(p) }
|
109
141
|
end
|
110
142
|
|
143
|
+
#Waits for and eventually returns a Bewildr::Application wrapping the process whose name matches
|
144
|
+
#the string passed as an argument
|
111
145
|
def self.wait_for_process_with_name(input)
|
112
146
|
Timeout.timeout(30) {sleep 0.1 until System::Diagnostics::Process.get_processes_by_name(input).size > 0}
|
113
147
|
self.attach_to_process_name(input)
|
@@ -43,10 +43,11 @@ module Bewildr
|
|
43
43
|
|
44
44
|
def select_by_index(input)
|
45
45
|
raise "Index must be 0 or greater" if input < 0
|
46
|
-
|
46
|
+
list_items[input].select
|
47
47
|
end
|
48
48
|
|
49
49
|
def selected
|
50
|
+
return nil if get_selection.empty?
|
50
51
|
get_selection.first.name
|
51
52
|
end
|
52
53
|
end
|
data/lib/bewildr/element.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
2
|
|
3
3
|
module Bewildr
|
4
|
+
#All MS UI Automation elements accessed using bewildr are represented as instances of Bewildr::Element.
|
4
5
|
class Element
|
5
6
|
attr_reader :automation_element
|
6
7
|
attr_reader :control_type
|
7
8
|
|
9
|
+
#Returns a new instance of Bewildr::Element wrapping the MS UI Automation Element passed in as an
|
10
|
+
#argument. You probably won't be calling this method directly - if you are then you probably know
|
11
|
+
#what your'e doing
|
8
12
|
def initialize(input)
|
9
13
|
@automation_element = input
|
10
14
|
case input
|
@@ -17,16 +21,19 @@ module Bewildr
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
24
|
+
#Returns the underlying automation element's name property
|
20
25
|
def name
|
21
26
|
existence_check
|
22
27
|
@automation_element.current.name.to_s
|
23
28
|
end
|
24
29
|
|
30
|
+
#Returns the underlying automation element's automation id property
|
25
31
|
def automation_id
|
26
32
|
existence_check
|
27
33
|
@automation_element.current.automation_id.to_s
|
28
34
|
end
|
29
35
|
|
36
|
+
#Returns true if the element exists, false if it doesn't
|
30
37
|
def exists?
|
31
38
|
return false if @control_type == :non_existent
|
32
39
|
begin
|
@@ -38,21 +45,26 @@ module Bewildr
|
|
38
45
|
end
|
39
46
|
alias :exist? :exists?
|
40
47
|
|
48
|
+
#Returns true if the element is visible, false if it isn't
|
41
49
|
def visible?
|
42
50
|
existence_check
|
43
51
|
!@automation_element.current.is_offscreen
|
44
52
|
end
|
45
53
|
|
54
|
+
#Returns true if this element has a descendant that meets the search criteria, false if it doesn't
|
55
|
+
#Takes a condition hash
|
46
56
|
def contains?(condition_hash)
|
47
57
|
get(condition_hash).exists?
|
48
58
|
end
|
49
59
|
alias :contain? :contains?
|
50
60
|
|
61
|
+
#Returns true if the underlying automation element is enabled, false if it's not
|
51
62
|
def enabled?
|
52
63
|
existence_check
|
53
64
|
@automation_element.current.is_enabled
|
54
65
|
end
|
55
66
|
|
67
|
+
#Waits up to 30 seconds for a descendant of this element to exist that meets the search criteria
|
56
68
|
def wait_for_existence_of(condition_hash)
|
57
69
|
Timeout.timeout(30) do
|
58
70
|
sleep 0.1 until contains?(condition_hash)
|
@@ -60,26 +72,31 @@ module Bewildr
|
|
60
72
|
get(condition_hash)
|
61
73
|
end
|
62
74
|
|
75
|
+
#Waits for up to 30 seconds for this element to no longer have a descendant element that meest the criteria
|
63
76
|
def wait_for_non_existence_of(condition_hash)
|
64
77
|
Timeout.timeout(30) do
|
65
78
|
sleep 0.1 unless contains?(condition_hash)
|
66
79
|
end
|
67
80
|
end
|
68
81
|
|
82
|
+
#Gives this element focus
|
69
83
|
def focus
|
70
84
|
@automation_element.set_focus
|
71
85
|
end
|
72
86
|
|
87
|
+
#Returns true if this element is scrollable, false if it isn't.
|
73
88
|
def scrollable?
|
74
89
|
return false unless @automation_element.get_supported_patterns.collect {|pattern| pattern.programmatic_name.to_s }.include?("ScrollPatternIdentifiers.Pattern")
|
75
90
|
vertically_scrollable
|
76
91
|
end
|
77
92
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
93
|
+
#Returns the result of searching this element's children or descendants for the first or all matches of
|
94
|
+
#a particular id, name or type (or combination!). See Bewildr::Finder for more details
|
95
|
+
# :id => "id"
|
96
|
+
# :name => "bob"
|
97
|
+
# :type => :button
|
98
|
+
# :scope => :children / :descendants
|
99
|
+
# :how_many => :first / :all
|
83
100
|
def get(condition_hash)
|
84
101
|
existence_check
|
85
102
|
condition = Finder.condition_for(condition_hash)
|
@@ -99,12 +116,12 @@ module Bewildr
|
|
99
116
|
end
|
100
117
|
end
|
101
118
|
|
102
|
-
#
|
103
|
-
|
119
|
+
#Returns true if this element is the root element of the UI element tree
|
104
120
|
def root?
|
105
121
|
@automation_element == System::Windows::Automation::AutomationElement.root_element
|
106
122
|
end
|
107
123
|
|
124
|
+
#Returns a new element representing this element's parent in the UI element tree
|
108
125
|
def parent
|
109
126
|
return nil if root?
|
110
127
|
walker = System::Windows::Automation::TreeWalker.RawViewWalker
|
@@ -112,11 +129,13 @@ module Bewildr
|
|
112
129
|
Bewildr::Element.new(potential_parent)
|
113
130
|
end
|
114
131
|
|
132
|
+
#Returns true if this element has descendants, false if it doesn't
|
115
133
|
def has_children?
|
116
134
|
walker = System::Windows::Automation::TreeWalker.RawViewWalker
|
117
135
|
!walker.get_first_child(@automation_element).nil?
|
118
136
|
end
|
119
137
|
|
138
|
+
#Returns an array containing this element's (direct) children
|
120
139
|
def children
|
121
140
|
return [] unless has_children?
|
122
141
|
walker = System::Windows::Automation::TreeWalker.ControlViewWalker #RawViewWalker
|
@@ -129,24 +148,22 @@ module Bewildr
|
|
129
148
|
bewildred_children
|
130
149
|
end
|
131
150
|
|
151
|
+
#Clicks this element - this is done by actual mouse moves and clicks. The automation element's underlying InvokePattern is not used.
|
132
152
|
def click
|
133
|
-
|
153
|
+
Bewildr::Mouse.click(clickable_point)
|
134
154
|
end
|
135
155
|
|
156
|
+
#Double clicks this element - this is done by actual mouse moves and clicks. The automation element's underlying InvokePattern is not used.
|
136
157
|
def double_click
|
137
|
-
|
158
|
+
Bewildr::Mouse.double_click(clickable_point)
|
138
159
|
end
|
139
160
|
|
161
|
+
#Right clicks this element - this is done by actual mouse moves and clicks. The automation element's underlying InvokePattern is not used.
|
140
162
|
def right_click
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
private
|
145
|
-
|
146
|
-
def existence_check
|
147
|
-
raise Bewildr::ElementDoesntExist unless exists?
|
163
|
+
Bewildr::Mouse.right_click(clickable_point)
|
148
164
|
end
|
149
165
|
|
166
|
+
#Returns the underlying automation element's clickable point property - this is used by the various click methods
|
150
167
|
def clickable_point
|
151
168
|
existence_check
|
152
169
|
Timeout.timeout(30) do
|
@@ -160,14 +177,24 @@ module Bewildr
|
|
160
177
|
end
|
161
178
|
end
|
162
179
|
|
180
|
+
private
|
181
|
+
|
182
|
+
#Raises an exception if this element no longer exists
|
183
|
+
def existence_check
|
184
|
+
raise Bewildr::ElementDoesntExist unless exists?
|
185
|
+
end
|
186
|
+
|
187
|
+
#Used to add scrollability to an element if it becomes scrollable subsequent to its initial discovery
|
163
188
|
def prepare_element
|
164
189
|
load_all_items_hack if scrollable?
|
165
190
|
end
|
166
191
|
|
192
|
+
#Figures out this element's control type
|
167
193
|
def set_control_type
|
168
194
|
@control_type = Bewildr::ControlType.symbol_for_enum(@automation_element.current.control_type)
|
169
195
|
end
|
170
196
|
|
197
|
+
#Mixes in bewildr control patterns dynamically based on what patterns the underlying automation element has
|
171
198
|
def build_element
|
172
199
|
@automation_element.get_supported_patterns.each do |pattern|
|
173
200
|
pattern_name = pattern.programmatic_name.to_s.gsub(/Identifiers\.Pattern/, "")
|
@@ -176,22 +203,15 @@ module Bewildr
|
|
176
203
|
end
|
177
204
|
end
|
178
205
|
|
206
|
+
#Adds control type addition modules to this element based on the underlying automation element's control type.
|
179
207
|
#list of control types comes from http://msdn.microsoft.com/en-us/library/ms750574.aspx
|
180
208
|
def include_additions
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
when :menu then extend Bewildr::ControlTypeAdditions::MenuAdditions
|
188
|
-
when :menu_item then extend Bewildr::ControlTypeAdditions::MenuItemAdditions
|
189
|
-
when :tab then extend Bewildr::ControlTypeAdditions::TabAdditions
|
190
|
-
when :text then extend Bewildr::ControlTypeAdditions::TextAdditions
|
191
|
-
when :tree then extend Bewildr::ControlTypeAdditions::TreeAdditions
|
192
|
-
when :tree_item then extend Bewildr::ControlTypeAdditions::TreeItemAdditions
|
193
|
-
when :window then extend Bewildr::ControlTypeAdditions::WindowAdditions
|
194
|
-
end
|
209
|
+
#the following looks like could have performance issues, but the tests don't take any longer to execute...
|
210
|
+
potential_addition = Bewildr::ControlTypeAdditions.submodules.select {|mod| mod.name.demodulize == "#{@control_type.to_s.classify}Additions"}.first
|
211
|
+
extend potential_addition unless potential_addition.nil?
|
212
|
+
|
213
|
+
#non-standards - move this to another method in the near future
|
214
|
+
extend Bewildr::ControlTypeAdditions::TextAdditions if @control_type == :hyperlink
|
195
215
|
|
196
216
|
#add scrolling capability if relevant - TODO: this ugliness will be fixed later
|
197
217
|
if @automation_element.get_supported_patterns.collect {|pattern| pattern.programmatic_name.to_s }.include?("ScrollPatternIdentifiers.Pattern")
|
data/lib/bewildr/finder.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
2
|
|
3
3
|
module Bewildr
|
4
|
+
#Wraps the Search Condition paradigm used by MS UI Automation to find objects in the UI Element tree. It contains various
|
5
|
+
#methods that build up the parts needed for to search for elements. These methods are called by Bewildr::Element#get in
|
6
|
+
#order to get and test for existence of descendent elements in the UI element tree. All of the methods take a condition
|
7
|
+
#hash, this is made up of at least one, but can be several key/value pairs.
|
4
8
|
class Finder
|
5
9
|
extend Bewildr::BewildrHelpers
|
6
10
|
|
7
11
|
class << self
|
12
|
+
#Returns a System::Windows::Automation::PropertyCondition or AndCondition based on a translation of the condition hash.
|
13
|
+
#The condition hash must contain at least one of the following keys:
|
14
|
+
# :id => "some id"
|
15
|
+
# :name => "some name"
|
16
|
+
# :type => :some_control_type
|
17
|
+
#These keys can be combined to create more complex search criteria
|
8
18
|
def condition_for(condition_hash)
|
9
19
|
conditions = condition_hash.select {|key, value| [:id, :name, :type].include?(key) }
|
10
20
|
conditions = Hash[*conditions.flatten]
|
@@ -15,6 +25,11 @@ module Bewildr
|
|
15
25
|
end
|
16
26
|
end
|
17
27
|
|
28
|
+
#Returns whether the seach should interrogate only children, or all descendants. If neither is specified, the default
|
29
|
+
#is to search the descendants. The condition hash should contain one of the following options:
|
30
|
+
# :scope => :children
|
31
|
+
# :scope => :descendants
|
32
|
+
# nothing
|
18
33
|
def scope_for(condition_hash)
|
19
34
|
case condition_hash[:scope]
|
20
35
|
when :children then System::Windows::Automation::TreeScope.Children
|
@@ -22,7 +37,12 @@ module Bewildr
|
|
22
37
|
end
|
23
38
|
end
|
24
39
|
|
25
|
-
#
|
40
|
+
#Returns whether the seach should stop at the first element that matches the criteria or whether it should find all
|
41
|
+
#elements that match. If neither is specified, the default is to find only the first element that matches. The condition
|
42
|
+
#hash should contain one of the following options:
|
43
|
+
# :how_many => :first
|
44
|
+
# :how_many => :all
|
45
|
+
# nothing
|
26
46
|
def how_many_for(condition_hash)
|
27
47
|
case condition_hash[:how_many]
|
28
48
|
when :first, nil then :find_first
|
@@ -33,12 +53,16 @@ module Bewildr
|
|
33
53
|
|
34
54
|
private
|
35
55
|
|
56
|
+
#Used to create an AndCondition that takes into account all of the search conditions. This is done by
|
57
|
+
#creating a single condition for each of the conditions and then creating an AndCondition combining
|
58
|
+
#the individual search conditions
|
36
59
|
def multiple_conditions(condition_hash)
|
37
60
|
condition_array = []
|
38
61
|
condition_hash.keys.each {|key| condition_array << single_condition({key => condition_hash[key]}) }
|
39
62
|
System::Windows::Automation::AndCondition.new(r_array_to_cs_array_of_conditions(condition_array))
|
40
63
|
end
|
41
64
|
|
65
|
+
#Calls the condition hash's corresponding condition creation method
|
42
66
|
def single_condition(condition_hash)
|
43
67
|
case condition_hash.keys.first
|
44
68
|
when :id then id_condition(condition_hash)
|
@@ -47,16 +71,19 @@ module Bewildr
|
|
47
71
|
end
|
48
72
|
end
|
49
73
|
|
74
|
+
#Returns a PropertyCondition when :id has been specified as the condition type
|
50
75
|
def id_condition(condition_hash)
|
51
76
|
value = r_string_to_c_string(condition_hash[:id].to_s)
|
52
77
|
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.automation_id_property, value)
|
53
78
|
end
|
54
79
|
|
80
|
+
#Returns a PropertyCondition when :name has been specified as the condition type
|
55
81
|
def name_condition(condition_hash)
|
56
82
|
value = r_string_to_c_string(condition_hash[:name])
|
57
83
|
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.name_property, value)
|
58
84
|
end
|
59
85
|
|
86
|
+
#Returns a PropertyCondition when :type has been specified as the condition type
|
60
87
|
def type_condition(condition_hash)
|
61
88
|
value = Bewildr::ControlType.enum_for_symbol(condition_hash[:type])
|
62
89
|
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.control_type_property, value)
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#Represents and gives access to mouse actions. Implemented as a singleton, but accessed through class methods to make the API more contained.
|
2
|
+
class Bewildr::Mouse
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@clickr = Bewildr::Clickr::Clickr.new
|
7
|
+
end
|
8
|
+
|
9
|
+
#Returns the BewildrClickr instance - don't use!
|
10
|
+
def clickr
|
11
|
+
@clickr
|
12
|
+
end
|
13
|
+
|
14
|
+
#Clicks the mouse at the supplied point
|
15
|
+
def self.click(point)
|
16
|
+
instance.clickr.click(point)
|
17
|
+
end
|
18
|
+
|
19
|
+
#Double clicks the mouse at the supplied point
|
20
|
+
def self.double_click(point)
|
21
|
+
instance.clickr.double_click(point)
|
22
|
+
end
|
23
|
+
|
24
|
+
#Right clicks the mouse at the supplied point
|
25
|
+
def self.right_click(point)
|
26
|
+
instance.clickr.right_click(point)
|
27
|
+
end
|
28
|
+
|
29
|
+
#Press the left mouse button down at the current point
|
30
|
+
def self.left_down
|
31
|
+
instance.clickr.left_mouse_button_down
|
32
|
+
end
|
33
|
+
|
34
|
+
#Release the left mouse button
|
35
|
+
def self.left_up
|
36
|
+
instance.clickr.left_mouse_button_up
|
37
|
+
end
|
38
|
+
|
39
|
+
#Moves the mouse to the supplied point
|
40
|
+
def self.move_to(point)
|
41
|
+
instance.clickr.set_location(point)
|
42
|
+
end
|
43
|
+
|
44
|
+
#Drags the mouse from one location to another, and optionally, via another! Pass a has containing the following keys:
|
45
|
+
# :from
|
46
|
+
# :to
|
47
|
+
# :via (optional)
|
48
|
+
# :wait_at_via_for
|
49
|
+
#The value for each of those keys should be either a point or an element apart from :wait_at_via_for which
|
50
|
+
#takes seconds (eg: 0.2, 3, etc). If an element is supplied, the drag point will be the element's clickable point
|
51
|
+
def self.drag(args)
|
52
|
+
raise "Can't drag without a :from key in the hash" unless args.keys.include?(:from)
|
53
|
+
raise "Can't drag without a :to key in the hash" unless args.keys.include?(:to)
|
54
|
+
|
55
|
+
point_from = args[:from]
|
56
|
+
point_to = args[:to]
|
57
|
+
point_via = args[:via]
|
58
|
+
args[:wait_at_via_for].nil? ? wait_time = 2 : wait_time = args[:wait_at_via_for]
|
59
|
+
|
60
|
+
point_from = point_from.clickable_point if point_from.instance_of?(Bewildr::Element)
|
61
|
+
point_to = point_to.clickable_point if point_to.instance_of?(Bewildr::Element)
|
62
|
+
point_via = point_via.clickable_point if !point_via.nil? && point_via.instance_of?(Bewildr::Element)
|
63
|
+
|
64
|
+
raise "Supplied :from was not an Element or a Point" unless point_from.class == System::Windows::Point
|
65
|
+
raise "Supplied :to was not an Element or a Point" unless point_to.class == System::Windows::Point
|
66
|
+
raise "Supplied :via was not an Element or a Point" unless point_via.nil? || point_via.class == System::Windows::Point
|
67
|
+
|
68
|
+
self.move_to(point_from)
|
69
|
+
self.left_down
|
70
|
+
sleep 0.2
|
71
|
+
|
72
|
+
if point_via.instance_of?(System::Windows::Point)
|
73
|
+
almost_midway = System::Windows::Point.new
|
74
|
+
almost_midway.x = point_via.x + 1
|
75
|
+
almost_midway.y = point_via.y + 1
|
76
|
+
self.move_to(almost_midway)
|
77
|
+
sleep 0.3
|
78
|
+
self.move_to(point_via)
|
79
|
+
sleep wait_time
|
80
|
+
end
|
81
|
+
|
82
|
+
almost_there = System::Windows::Point.new
|
83
|
+
almost_there.x = point_to.x + 1
|
84
|
+
almost_there.y = point_to.y + 1
|
85
|
+
|
86
|
+
self.move_to(almost_there)
|
87
|
+
sleep 0.2
|
88
|
+
self.move_to(point_to)
|
89
|
+
self.left_up
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
=begin
|
94
|
+
Methods in BewildrClickr dll that need wrapping here...
|
95
|
+
|
96
|
+
public void Drag(Point startingLocation, Point targetLocation)
|
97
|
+
public void RightMouseButtonDown()
|
98
|
+
public void RightMouseButtonUp()
|
99
|
+
=end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bewildr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 9
|
10
|
+
version: 0.1.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Nat Ritmeyer
|
@@ -15,10 +15,25 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-20 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activesupport
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 3.0.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
22
37
|
description: Test WPF UI apps with IronRuby
|
23
38
|
email: nat@natontesting.com
|
24
39
|
executables: []
|
@@ -64,6 +79,7 @@ files:
|
|
64
79
|
- lib/bewildr/ext/BewildrClickr.dll
|
65
80
|
- lib/bewildr/ext/extensions.rb
|
66
81
|
- lib/bewildr/finder.rb
|
82
|
+
- lib/bewildr/mouse.rb
|
67
83
|
- lib/bewildr/windows.rb
|
68
84
|
- lib/bewildr.rb
|
69
85
|
has_rdoc: true
|