bewildr 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +28 -0
- data/README +8 -0
- data/Rakefile +52 -0
- data/lib/bewildr.rb +50 -0
- data/lib/bewildr/application.rb +95 -0
- data/lib/bewildr/bewildr_helpers.rb +17 -0
- data/lib/bewildr/control_patterns/expand_collapse_pattern.rb +24 -0
- data/lib/bewildr/control_patterns/grid_pattern.rb +15 -0
- data/lib/bewildr/control_patterns/invoke_pattern.rb +11 -0
- data/lib/bewildr/control_patterns/range_value_pattern.rb +19 -0
- data/lib/bewildr/control_patterns/selection_item_pattern.rb +24 -0
- data/lib/bewildr/control_patterns/selection_pattern.rb +28 -0
- data/lib/bewildr/control_patterns/table_pattern.rb +17 -0
- data/lib/bewildr/control_patterns/toggle_pattern.rb +70 -0
- data/lib/bewildr/control_patterns/value_pattern.rb +20 -0
- data/lib/bewildr/control_patterns/window_pattern.rb +31 -0
- data/lib/bewildr/control_type.rb +59 -0
- data/lib/bewildr/control_type_additions/combo_box_additions.rb +87 -0
- data/lib/bewildr/control_type_additions/data_grid_additions.rb +16 -0
- data/lib/bewildr/control_type_additions/list_additions.rb +18 -0
- data/lib/bewildr/control_type_additions/menu_additions.rb +60 -0
- data/lib/bewildr/control_type_additions/menu_item_additions.rb +18 -0
- data/lib/bewildr/control_type_additions/tab_additions.rb +18 -0
- data/lib/bewildr/control_type_additions/text_additions.rb +16 -0
- data/lib/bewildr/control_type_additions/tree_additions.rb +59 -0
- data/lib/bewildr/control_type_additions/tree_item_additions.rb +18 -0
- data/lib/bewildr/control_type_additions/window_additions.rb +23 -0
- data/lib/bewildr/element.rb +171 -0
- data/lib/bewildr/exceptions.rb +8 -0
- data/lib/bewildr/ext/BewildrClickr.dll +0 -0
- data/lib/bewildr/finder.rb +66 -0
- data/lib/bewildr/windows.rb +23 -0
- metadata +93 -0
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Copyright (c) 2010, Nathaniel Ritmeyer
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
3. Neither the name Nathaniel Ritmeyer nor the names of contributors to
|
15
|
+
this software may be used to endorse or promote products derived from this
|
16
|
+
software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
19
|
+
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
20
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
21
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
22
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
23
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
25
|
+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
26
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
27
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
28
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'cucumber'
|
9
|
+
require 'cucumber/rake/task'
|
10
|
+
|
11
|
+
spec = Gem::Specification.new do |s|
|
12
|
+
s.name = 'bewildr'
|
13
|
+
s.version = '0.1'
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.extra_rdoc_files = ['README', 'LICENSE']
|
16
|
+
s.summary = 'Test your WPF apps with (iron) ruby!'
|
17
|
+
s.description = s.summary
|
18
|
+
s.author = 'Nat Ritmeyer'
|
19
|
+
s.email = 'nat@natontesting.com'
|
20
|
+
s.homepage = 'http://github.com/natritmeyer/bewildr'
|
21
|
+
s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,lib}/**/*")
|
22
|
+
s.require_path = "lib"
|
23
|
+
s.bindir = "bin"
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::GemPackageTask.new(spec) do |p|
|
27
|
+
p.gem_spec = spec
|
28
|
+
p.need_tar = true
|
29
|
+
p.need_zip = true
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
files =['README', 'LICENSE', 'lib/**/*.rb']
|
34
|
+
rdoc.rdoc_files.add(files)
|
35
|
+
rdoc.main = "README" # page to start on
|
36
|
+
rdoc.title = "bewildr Docs"
|
37
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
38
|
+
rdoc.options << '--line-numbers'
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::TestTask.new do |t|
|
42
|
+
t.test_files = FileList['test/**/*.rb']
|
43
|
+
end
|
44
|
+
|
45
|
+
Spec::Rake::SpecTask.new do |t|
|
46
|
+
t.spec_files = FileList['spec/**/*.rb']
|
47
|
+
t.libs << Dir["lib"]
|
48
|
+
end
|
49
|
+
|
50
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
51
|
+
t.cucumber_opts = "features --format pretty --no-color"
|
52
|
+
end
|
data/lib/bewildr.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
#don't load bewildr unless we're using ironruby
|
4
|
+
#get rid of the following line and make sure that the gemspec sets it to be
|
5
|
+
#iron ruby only: http://www.ironruby.net/documentation/real_ruby_applications/rubygems
|
6
|
+
|
7
|
+
raise LoadError, "Bewildr only works under IronRuby" unless RUBY_ENGINE == "ironruby"
|
8
|
+
|
9
|
+
#require the UI Automation dlls
|
10
|
+
load_assembly 'UIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
|
11
|
+
load_assembly 'UIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
|
12
|
+
load_assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
|
13
|
+
|
14
|
+
#require BewildrClickr - stopgap until the ffi gem works under ironruby
|
15
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "bewildr", "ext", "BewildrClickr.dll")
|
16
|
+
CLICKR = Bewildr::Clickr::Clickr.new
|
17
|
+
|
18
|
+
#load plain old ruby libraries
|
19
|
+
require 'timeout'
|
20
|
+
|
21
|
+
#require bewildr classes
|
22
|
+
require 'bewildr/exceptions'
|
23
|
+
require 'bewildr/bewildr_helpers'
|
24
|
+
require 'bewildr/control_type'
|
25
|
+
require 'bewildr/finder'
|
26
|
+
require 'bewildr/application'
|
27
|
+
require 'bewildr/windows'
|
28
|
+
require 'bewildr/element'
|
29
|
+
|
30
|
+
require 'bewildr/control_patterns/window_pattern'
|
31
|
+
require 'bewildr/control_patterns/invoke_pattern'
|
32
|
+
require 'bewildr/control_patterns/value_pattern'
|
33
|
+
require 'bewildr/control_patterns/toggle_pattern'
|
34
|
+
require 'bewildr/control_patterns/selection_pattern'
|
35
|
+
require 'bewildr/control_patterns/expand_collapse_pattern'
|
36
|
+
require 'bewildr/control_patterns/selection_item_pattern'
|
37
|
+
require 'bewildr/control_patterns/range_value_pattern'
|
38
|
+
require 'bewildr/control_patterns/grid_pattern'
|
39
|
+
require 'bewildr/control_patterns/table_pattern'
|
40
|
+
|
41
|
+
require 'bewildr/control_type_additions/text_additions'
|
42
|
+
require 'bewildr/control_type_additions/combo_box_additions'
|
43
|
+
require 'bewildr/control_type_additions/window_additions'
|
44
|
+
require 'bewildr/control_type_additions/menu_additions'
|
45
|
+
require 'bewildr/control_type_additions/menu_item_additions'
|
46
|
+
require 'bewildr/control_type_additions/tab_additions'
|
47
|
+
require 'bewildr/control_type_additions/list_additions'
|
48
|
+
require 'bewildr/control_type_additions/tree_additions'
|
49
|
+
require 'bewildr/control_type_additions/tree_item_additions'
|
50
|
+
require 'bewildr/control_type_additions/data_grid_additions'
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
class Application
|
5
|
+
def initialize(proc)
|
6
|
+
@proc = proc
|
7
|
+
@proc.wait_for_input_idle(10)
|
8
|
+
@proc_id = proc.id
|
9
|
+
end
|
10
|
+
private :initialize
|
11
|
+
|
12
|
+
def kill
|
13
|
+
@proc.kill
|
14
|
+
Timeout::timeout(5) do
|
15
|
+
sleep 0.1 until @proc.has_exited
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def running?
|
20
|
+
@proc.nil? ? false : !@proc.has_exited
|
21
|
+
end
|
22
|
+
|
23
|
+
def wait_for_termination
|
24
|
+
Timeout::timeout(30) do
|
25
|
+
sleep 0.2 while running?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_windows
|
30
|
+
Bewildr::Windows.windows_by_process_id(@proc_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_window_by_name(input)
|
34
|
+
case input
|
35
|
+
when String then return get_windows.select{|window| window.name.strip == input.strip}.first
|
36
|
+
when Regexp then return get_windows.select{|window| input.match(window.name.strip).nil? == false}.first
|
37
|
+
else
|
38
|
+
raise ArgumentError, "input not a string or regexp but a #{input.class}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias :get_window :get_window_by_name
|
42
|
+
|
43
|
+
def wait_for_window(input, wait_time = 30)
|
44
|
+
begin
|
45
|
+
Timeout::timeout(wait_time) do
|
46
|
+
begin
|
47
|
+
my_window = get_window(input)
|
48
|
+
raise if my_window.nil?
|
49
|
+
return my_window
|
50
|
+
rescue
|
51
|
+
sleep 0.2
|
52
|
+
retry
|
53
|
+
end
|
54
|
+
end
|
55
|
+
rescue Timeout::Error
|
56
|
+
raise ElementDoesntExist
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def window_count
|
61
|
+
get_windows.size
|
62
|
+
end
|
63
|
+
|
64
|
+
#takes name or full path of exe to start
|
65
|
+
def self.start(process_name)
|
66
|
+
Bewildr::Application.new(System::Diagnostics::Process.start(process_name))
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.start_with_settings(settings_hash)
|
70
|
+
#TODO
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.attach_to_process_name(process_name)
|
74
|
+
Bewildr::Application.new(System::Diagnostics::Process.get_processes_by_name(process_name).first)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.attach_to_process(process)
|
78
|
+
Bewildr::Application.new(process)
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.start_app_and_wait_for_window(path, window_name)
|
82
|
+
app = Bewildr::Application.start(path)
|
83
|
+
window = app.wait_for_window(window_name)
|
84
|
+
return app, window
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.kill_all_processes_with_name(input)
|
88
|
+
System::Diagnostics::Process.get_processes_by_name(input).each {|p| p.kill}
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.processes_with_name(input)
|
92
|
+
System::Diagnostics::Process.get_processes_by_name(input).collect {|p| Bewildr::Application.attach_to_process(p) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module BewildrHelpers
|
5
|
+
def r_array_to_cs_array_of_strings(args)
|
6
|
+
System::Array[System::String].new(args.map {|arg| arg.to_s.to_clr_string})
|
7
|
+
end
|
8
|
+
|
9
|
+
def r_array_to_cs_array_of_conditions(args)
|
10
|
+
System::Array[System::Windows::Automation::Condition].new(args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def r_string_to_c_string(r_string)
|
14
|
+
System::String.new(r_string)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module ExpandCollapsePattern
|
6
|
+
def expand
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::ExpandCollapsePattern.pattern).expand unless expand_state == :expanded or expand_state == :leaf
|
8
|
+
end
|
9
|
+
|
10
|
+
def collapse
|
11
|
+
@automation_element.get_current_pattern(System::Windows::Automation::ExpandCollapsePattern.pattern).collapse unless expand_state == :collapsed or expand_state == :leaf
|
12
|
+
end
|
13
|
+
|
14
|
+
def expand_state
|
15
|
+
case @automation_element.get_current_pattern(System::Windows::Automation::ExpandCollapsePattern.pattern).current.expand_collapse_state
|
16
|
+
when System::Windows::Automation::ExpandCollapseState.collapsed then return :collapsed
|
17
|
+
when System::Windows::Automation::ExpandCollapseState.expanded then return :expanded
|
18
|
+
when System::Windows::Automation::ExpandCollapseState.partially_expanded then return :partially_expanded
|
19
|
+
when System::Windows::Automation::ExpandCollapseState.leaf_node then return :leaf
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module GridPattern
|
6
|
+
def row_count
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::GridPattern.pattern).current.row_count
|
8
|
+
end
|
9
|
+
|
10
|
+
def column_count
|
11
|
+
@automation_element.get_current_pattern(System::Windows::Automation::GridPattern.pattern).current.column_count
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module InvokePattern
|
6
|
+
def click
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::InvokePattern.pattern).invoke
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module RangeValuePattern
|
6
|
+
def value
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).current.value
|
8
|
+
end
|
9
|
+
|
10
|
+
def maximum
|
11
|
+
@automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).current.maximum
|
12
|
+
end
|
13
|
+
|
14
|
+
def minimum
|
15
|
+
@automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).current.minimum
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# To change this template, choose Tools | Templates
|
2
|
+
# and open the template in the editor.
|
3
|
+
|
4
|
+
module Bewildr
|
5
|
+
module ControlPatterns
|
6
|
+
module SelectionItemPattern
|
7
|
+
def select
|
8
|
+
@automation_element.get_current_pattern(System::Windows::Automation::SelectionItemPattern.pattern).select
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_selected?
|
12
|
+
@automation_element.get_current_pattern(System::Windows::Automation::SelectionItemPattern.pattern).current.is_selected
|
13
|
+
end
|
14
|
+
|
15
|
+
def selected?
|
16
|
+
is_selected?
|
17
|
+
end
|
18
|
+
|
19
|
+
def unselected?
|
20
|
+
!is_selected?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module SelectionPattern
|
6
|
+
def get_selection
|
7
|
+
my_selected_items = @automation_element.get_current_pattern(System::Windows::Automation::SelectionPattern.pattern).current.get_selection
|
8
|
+
|
9
|
+
c_array_list = System::Collections::ArrayList.new(my_selected_items)
|
10
|
+
item_array = c_array_list.to_array.to_a
|
11
|
+
|
12
|
+
return [] if item_array.size == 0
|
13
|
+
item_array.to_a.collect {|item| Bewildr::Element.new(item)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def can_select_multiple?
|
17
|
+
@automation_element.get_current_pattern(System::Windows::Automation::SelectionPattern.pattern).current.can_select_multiple
|
18
|
+
end
|
19
|
+
|
20
|
+
def selected
|
21
|
+
case can_select_multiple?
|
22
|
+
when true then get_selection
|
23
|
+
when false then get_selection.first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module TablePattern
|
6
|
+
def column_headers
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::TablePattern.pattern).current.get_column_headers.collect do |header|
|
8
|
+
Bewildr::Element.new(header)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def column_header_names
|
13
|
+
column_headers.collect {|header| header.name }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module TogglePattern
|
6
|
+
|
7
|
+
def self.extended(base)
|
8
|
+
base.instance_eval do
|
9
|
+
case @control_type
|
10
|
+
when :check_box
|
11
|
+
def check
|
12
|
+
set_state_to :on
|
13
|
+
end
|
14
|
+
|
15
|
+
def uncheck
|
16
|
+
set_state_to :off
|
17
|
+
end
|
18
|
+
|
19
|
+
def checked?
|
20
|
+
state == :on
|
21
|
+
end
|
22
|
+
|
23
|
+
def unchecked?
|
24
|
+
state == :off
|
25
|
+
end
|
26
|
+
|
27
|
+
def checked_state
|
28
|
+
state
|
29
|
+
end
|
30
|
+
when :button
|
31
|
+
def toggle(value)
|
32
|
+
set_state_to(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def toggle_state
|
36
|
+
state
|
37
|
+
end
|
38
|
+
|
39
|
+
def toggle
|
40
|
+
flip_state
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def set_state_to(value)
|
49
|
+
raise ElementNotEnabled unless enabled?
|
50
|
+
case value
|
51
|
+
when :on then flip_state while state != :on
|
52
|
+
when :off then flip_state while state != :off
|
53
|
+
else raise ArgumentError, "Didn't receive :on or :off"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def state
|
58
|
+
case @automation_element.get_current_pattern(System::Windows::Automation::TogglePattern.pattern).current.toggle_state
|
59
|
+
when System::Windows::Automation::ToggleState.Off then return :off
|
60
|
+
when System::Windows::Automation::ToggleState.On then return :on
|
61
|
+
when System::Windows::Automation::ToggleState.Indeterminate then return :indeterminate
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def flip_state
|
66
|
+
@automation_element.get_current_pattern(System::Windows::Automation::TogglePattern.pattern).toggle
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module ValuePattern
|
6
|
+
def is_password_field?
|
7
|
+
@automation_element.current.class_name.to_s == "PasswordBox" ? true : false
|
8
|
+
end
|
9
|
+
|
10
|
+
def text
|
11
|
+
raise PasswordFieldReadAttempt, "You can't get the text of a password field" if is_password_field?
|
12
|
+
@automation_element.get_current_pattern(System::Windows::Automation::ValuePattern.pattern).current.value.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def text=(input)
|
16
|
+
@automation_element.get_current_pattern(System::Windows::Automation::ValuePattern.pattern).set_value(input)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlPatterns
|
5
|
+
module WindowPattern
|
6
|
+
def close
|
7
|
+
@automation_element.get_current_pattern(System::Windows::Automation::WindowPattern.pattern).close
|
8
|
+
end
|
9
|
+
|
10
|
+
def minimize
|
11
|
+
@automation_element.get_current_pattern(System::Windows::Automation::WindowPattern.pattern).set_window_visual_state(System::Windows::Automation::WindowVisualState.minimized)
|
12
|
+
end
|
13
|
+
|
14
|
+
def maximize
|
15
|
+
@automation_element.get_current_pattern(System::Windows::Automation::WindowPattern.pattern).set_window_visual_state(System::Windows::Automation::WindowVisualState.maximized)
|
16
|
+
end
|
17
|
+
|
18
|
+
def restore
|
19
|
+
@automation_element.get_current_pattern(System::Windows::Automation::WindowPattern.pattern).set_window_visual_state(System::Windows::Automation::WindowVisualState.normal)
|
20
|
+
end
|
21
|
+
|
22
|
+
def visual_state
|
23
|
+
case @automation_element.get_current_pattern(System::Windows::Automation::WindowPattern.pattern).current.window_visual_state
|
24
|
+
when System::Windows::Automation::WindowVisualState.maximized then return :maximized
|
25
|
+
when System::Windows::Automation::WindowVisualState.minimized then return :minimized
|
26
|
+
when System::Windows::Automation::WindowVisualState.normal then return :normal
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
class ControlType
|
5
|
+
class << self
|
6
|
+
def symbol_for_enum(input_control_type_enum)
|
7
|
+
raise "Unknown control type: #{input_control_type_enum}" unless @@control_type_map.value?(input_control_type_enum)
|
8
|
+
@@control_type_map.index(input_control_type_enum)
|
9
|
+
end
|
10
|
+
|
11
|
+
def class_for_symbol(input_symbol)
|
12
|
+
raise "Unknown control type: #{input_symbol}" unless @@control_type_map.key?(input_symbol)
|
13
|
+
@@control_type_map[input_symbol]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
@@control_type_map = {
|
18
|
+
:button => System::Windows::Automation::ControlType.Button,
|
19
|
+
:calendar => System::Windows::Automation::ControlType.Calendar,
|
20
|
+
:check_box => System::Windows::Automation::ControlType.CheckBox,
|
21
|
+
:combo_box => System::Windows::Automation::ControlType.ComboBox,
|
22
|
+
:custom => System::Windows::Automation::ControlType.Custom,
|
23
|
+
:data_grid => System::Windows::Automation::ControlType.DataGrid,
|
24
|
+
:data_item => System::Windows::Automation::ControlType.DataItem,
|
25
|
+
:document => System::Windows::Automation::ControlType.Document,
|
26
|
+
:edit => System::Windows::Automation::ControlType.Edit,
|
27
|
+
:group => System::Windows::Automation::ControlType.Group,
|
28
|
+
:header => System::Windows::Automation::ControlType.Header,
|
29
|
+
:header_item => System::Windows::Automation::ControlType.HeaderItem,
|
30
|
+
:hyperlink => System::Windows::Automation::ControlType.Hyperlink,
|
31
|
+
:image => System::Windows::Automation::ControlType.Image,
|
32
|
+
:list => System::Windows::Automation::ControlType.List,
|
33
|
+
:list_item => System::Windows::Automation::ControlType.ListItem,
|
34
|
+
:menu => System::Windows::Automation::ControlType.Menu,
|
35
|
+
:menu_bar => System::Windows::Automation::ControlType.MenuBar,
|
36
|
+
:menu_item => System::Windows::Automation::ControlType.MenuItem,
|
37
|
+
:pane => System::Windows::Automation::ControlType.Pane,
|
38
|
+
:progress_bar => System::Windows::Automation::ControlType.ProgressBar,
|
39
|
+
:radio_button => System::Windows::Automation::ControlType.RadioButton,
|
40
|
+
:scroll_bar => System::Windows::Automation::ControlType.ScrollBar,
|
41
|
+
:seperator => System::Windows::Automation::ControlType.Separator,
|
42
|
+
:slider => System::Windows::Automation::ControlType.Slider,
|
43
|
+
:spinner => System::Windows::Automation::ControlType.Spinner,
|
44
|
+
:split_button => System::Windows::Automation::ControlType.SplitButton,
|
45
|
+
:status_bar => System::Windows::Automation::ControlType.StatusBar,
|
46
|
+
:tab => System::Windows::Automation::ControlType.Tab,
|
47
|
+
:tab_item => System::Windows::Automation::ControlType.TabItem,
|
48
|
+
:table => System::Windows::Automation::ControlType.Table,
|
49
|
+
:text => System::Windows::Automation::ControlType.Text,
|
50
|
+
:thumb => System::Windows::Automation::ControlType.Thumb,
|
51
|
+
:title_bar => System::Windows::Automation::ControlType.TitleBar,
|
52
|
+
:tool_bar => System::Windows::Automation::ControlType.ToolBar,
|
53
|
+
:tool_tip => System::Windows::Automation::ControlType.ToolTip,
|
54
|
+
:tree => System::Windows::Automation::ControlType.Tree,
|
55
|
+
:tree_item => System::Windows::Automation::ControlType.TreeItem,
|
56
|
+
:window => System::Windows::Automation::ControlType.Window
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module ComboBoxAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::ExpandCollapsePattern
|
8
|
+
base.extend Bewildr::ControlPatterns::SelectionPattern
|
9
|
+
base.extend Bewildr::ControlPatterns::SelectionItemPattern
|
10
|
+
|
11
|
+
base.instance_eval do
|
12
|
+
def items
|
13
|
+
my_list_items = list_items
|
14
|
+
return nil if my_list_items.nil?
|
15
|
+
my_list_items.collect {|item| item.name}
|
16
|
+
end
|
17
|
+
|
18
|
+
def list_items
|
19
|
+
begin
|
20
|
+
expand_combo
|
21
|
+
bewildr_list_items = get(:type => :list_item, :scope => :children)
|
22
|
+
bewildr_list_items.nil? ? nil : bewildr_list_items
|
23
|
+
ensure
|
24
|
+
collapse_combo
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def count
|
29
|
+
my_items = items
|
30
|
+
my_items.nil? ? 0 : my_items.size
|
31
|
+
end
|
32
|
+
|
33
|
+
def select(input)
|
34
|
+
case input
|
35
|
+
when String then select_by_name(input)
|
36
|
+
when Integer then select_by_index(input)
|
37
|
+
else raise ArgumentError, "Select by name or by index"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def select_by_name(input)
|
42
|
+
begin
|
43
|
+
expand_combo
|
44
|
+
my_item = list_items.find {|item| item.name == input}
|
45
|
+
raise NoSuchItemInComboBox if my_item.nil?
|
46
|
+
my_item.select
|
47
|
+
ensure
|
48
|
+
collapse_combo
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def select_by_index(input)
|
53
|
+
raise "Index must be 0 or greater" if input < 0
|
54
|
+
begin
|
55
|
+
expand_combo
|
56
|
+
my_item = list_items[input].select
|
57
|
+
ensure
|
58
|
+
collapse_combo
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def selected
|
63
|
+
#TODO: find a way to not need to expand and collapse before getting the selected item
|
64
|
+
expand_combo
|
65
|
+
collapse_combo
|
66
|
+
#get_selection.first
|
67
|
+
get_selection.first.name
|
68
|
+
end
|
69
|
+
|
70
|
+
def expand_combo
|
71
|
+
expand
|
72
|
+
Timeout.timeout(30) do
|
73
|
+
sleep 0.2 until expand_state == :expanded
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def collapse_combo
|
78
|
+
collapse
|
79
|
+
Timeout.timeout(30) do
|
80
|
+
sleep 0.2 until expand_state == :collapsed
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module DataGridAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::GridPattern
|
8
|
+
base.extend Bewildr::ControlPatterns::TablePattern
|
9
|
+
|
10
|
+
base.instance_eval do
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module ListAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::SelectionPattern
|
8
|
+
|
9
|
+
base.instance_eval do
|
10
|
+
def select(input)
|
11
|
+
selectable_elements = get(:type => :list_item, :scope => :children)
|
12
|
+
selectable_elements.find {|selectable_element| selectable_element.name == input}.select
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module MenuAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::ExpandCollapsePattern
|
8
|
+
base.extend Bewildr::ControlPatterns::SelectionPattern
|
9
|
+
base.extend Bewildr::ControlPatterns::SelectionItemPattern
|
10
|
+
|
11
|
+
base.instance_eval do
|
12
|
+
def root_menu_items
|
13
|
+
get(:type =>:menu_item, :scope => :children)
|
14
|
+
end
|
15
|
+
|
16
|
+
def select_menu(path)
|
17
|
+
menu_item(path).click
|
18
|
+
end
|
19
|
+
|
20
|
+
def select_node(path)
|
21
|
+
node(path).select
|
22
|
+
end
|
23
|
+
|
24
|
+
def menu_item(path)
|
25
|
+
current_menu_items = root_menu_items
|
26
|
+
matching_menu_item = nil
|
27
|
+
path.each_with_index do |target_menu_item, index|
|
28
|
+
case current_menu_items
|
29
|
+
when Array
|
30
|
+
matching_menu_item = current_menu_items.find {|node| node.name == target_menu_item} #TODO: make this work with regexes as well as strings...
|
31
|
+
raise ElementDoesntExist if matching_menu_item.nil?
|
32
|
+
when Bewildr::Element
|
33
|
+
if current_menu_items.name == target_menu_item #TODO: make this work with regexes as well as strings...
|
34
|
+
matching_menu_item = current_menu_items
|
35
|
+
else
|
36
|
+
raise ElementDoesntExist
|
37
|
+
end
|
38
|
+
end
|
39
|
+
raise ElementDoesntExist if matching_menu_item.nil?
|
40
|
+
if path.size != index + 1
|
41
|
+
matching_menu_item.expand
|
42
|
+
current_menu_items = matching_menu_item.sub_menus
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return matching_menu_item
|
46
|
+
end
|
47
|
+
|
48
|
+
def contains_menu_item?(path)
|
49
|
+
begin
|
50
|
+
menu_item(path)
|
51
|
+
return true
|
52
|
+
rescue ElementDoesntExist => e
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module MenuItemAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::ExpandCollapsePattern
|
8
|
+
base.extend Bewildr::ControlPatterns::InvokePattern
|
9
|
+
|
10
|
+
base.instance_eval do
|
11
|
+
def sub_menus
|
12
|
+
get(:type => :menu_item, :scope => :children)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module TabAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::SelectionPattern
|
8
|
+
|
9
|
+
base.instance_eval do
|
10
|
+
def select(input)
|
11
|
+
selectable_elements = get(:type => :tab_item, :scope => :children)
|
12
|
+
selectable_elements.find {|selectable_element| selectable_element.name == input}.select
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module TextAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.instance_eval do
|
8
|
+
def text
|
9
|
+
existence_check
|
10
|
+
name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module TreeAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::ExpandCollapsePattern
|
8
|
+
base.extend Bewildr::ControlPatterns::SelectionPattern
|
9
|
+
|
10
|
+
base.instance_eval do
|
11
|
+
def root_nodes
|
12
|
+
get(:type => :tree_item, :scope => :children)
|
13
|
+
end
|
14
|
+
|
15
|
+
def root_node
|
16
|
+
root_nodes.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def select_node(path)
|
20
|
+
node(path).select
|
21
|
+
end
|
22
|
+
|
23
|
+
def node(path)
|
24
|
+
current_nodes = root_nodes
|
25
|
+
matching_node = nil
|
26
|
+
path.each_with_index do |target_node, index|
|
27
|
+
case current_nodes
|
28
|
+
when Array
|
29
|
+
matching_node = current_nodes.find {|node| node.name == target_node} #TODO: make this work with regexes as well as strings...
|
30
|
+
raise ElementDoesntExist if matching_node.nil?
|
31
|
+
when Bewildr::Element
|
32
|
+
if current_nodes.name == target_node #TODO: make this work with regexes as well as strings...
|
33
|
+
matching_node = current_nodes
|
34
|
+
else
|
35
|
+
raise ElementDoesntExist
|
36
|
+
end
|
37
|
+
end
|
38
|
+
raise ElementDoesntExist if matching_node.nil?
|
39
|
+
if path.size != index + 1
|
40
|
+
matching_node.expand
|
41
|
+
current_nodes = matching_node.child_nodes
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return matching_node
|
45
|
+
end
|
46
|
+
|
47
|
+
def contains_node?(path)
|
48
|
+
begin
|
49
|
+
node(path)
|
50
|
+
return true
|
51
|
+
rescue ElementDoesntExist => e
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module TreeItemAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::ExpandCollapsePattern
|
8
|
+
base.extend Bewildr::ControlPatterns::SelectionItemPattern
|
9
|
+
|
10
|
+
base.instance_eval do
|
11
|
+
def child_nodes
|
12
|
+
get(:type => :tree_item, :scope => :children)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
module ControlTypeAdditions
|
5
|
+
module WindowAdditions
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend Bewildr::ControlPatterns::WindowPattern
|
8
|
+
|
9
|
+
base.instance_eval do
|
10
|
+
def open?
|
11
|
+
exists?
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait_for_close
|
15
|
+
Timeout::timeout(30) do
|
16
|
+
sleep 0.2 while open?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
class Element
|
5
|
+
attr_reader :automation_element
|
6
|
+
attr_reader :control_type
|
7
|
+
|
8
|
+
def initialize(input)
|
9
|
+
@automation_element = input
|
10
|
+
case input
|
11
|
+
when System::Windows::Automation::AutomationElement
|
12
|
+
set_control_type
|
13
|
+
build_element
|
14
|
+
when nil then @control_type = :non_existent
|
15
|
+
else raise BewildrInternalError, "Can only initialize an element with a nil or a Sys::Win::Auto::AE[C], not a #{input.class}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
existence_check
|
21
|
+
@automation_element.current.name.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
existence_check
|
26
|
+
@automation_element.current.automation_id.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def exists?
|
30
|
+
return false if @control_type == :non_existent
|
31
|
+
begin
|
32
|
+
@automation_element.current.bounding_rectangle
|
33
|
+
return true
|
34
|
+
rescue System::Windows::Automation::ElementNotAvailableException, TypeError => e
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
alias :exist? :exists?
|
39
|
+
|
40
|
+
def contains?(condition_hash)
|
41
|
+
get(condition_hash).exists?
|
42
|
+
end
|
43
|
+
alias :contain? :contains?
|
44
|
+
|
45
|
+
def existence_check
|
46
|
+
raise ElementDoesntExist unless exists?
|
47
|
+
end
|
48
|
+
private :existence_check
|
49
|
+
|
50
|
+
def enabled?
|
51
|
+
existence_check
|
52
|
+
@automation_element.current.is_enabled
|
53
|
+
end
|
54
|
+
|
55
|
+
#:id => "id"
|
56
|
+
#:name => "bob"
|
57
|
+
#:type => :button
|
58
|
+
#:scope => :children / :descendants
|
59
|
+
#:how_many => :first / :all
|
60
|
+
def get(condition_hash)
|
61
|
+
existence_check
|
62
|
+
condition = Finder.condition_for(condition_hash)
|
63
|
+
scope = Finder.scope_for(condition_hash)
|
64
|
+
how_many = Finder.how_many_for(condition_hash)
|
65
|
+
|
66
|
+
result = @automation_element.send how_many, scope, condition
|
67
|
+
case result
|
68
|
+
when System::Windows::Automation::AutomationElement, nil then return Bewildr::Element.new(result)
|
69
|
+
when System::Windows::Automation::AutomationElementCollection
|
70
|
+
c_array_list = System::Collections::ArrayList.new(result)
|
71
|
+
element_array = c_array_list.to_array.to_a
|
72
|
+
case
|
73
|
+
when element_array.size == 0 then return Bewildr::Element.new(nil)
|
74
|
+
when element_array.size == 1 then return Bewildr::Element.new(element_array.first)
|
75
|
+
when element_array.size > 1 then return element_array.collect {|element| Bewildr::Element.new(element) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#add "children/child" and "descendants/descendant" methods
|
81
|
+
|
82
|
+
def children
|
83
|
+
get({:scope => :children}).collect {|element| Bewildr::Element.new(element)}
|
84
|
+
end
|
85
|
+
|
86
|
+
def click
|
87
|
+
CLICKR.click(clickable_point)
|
88
|
+
end
|
89
|
+
|
90
|
+
def double_click
|
91
|
+
CLICKR.double_click(clickable_point)
|
92
|
+
end
|
93
|
+
|
94
|
+
def right_click
|
95
|
+
CLICKR.right_click(clickable_point)
|
96
|
+
end
|
97
|
+
|
98
|
+
def clickable_point
|
99
|
+
existence_check
|
100
|
+
@automation_element.get_clickable_point
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def set_control_type
|
106
|
+
@control_type = Bewildr::ControlType.symbol_for_enum(@automation_element.current.control_type)
|
107
|
+
end
|
108
|
+
|
109
|
+
#list of control types comes from http://msdn.microsoft.com/en-us/library/ms750574.aspx
|
110
|
+
def build_element
|
111
|
+
case @control_type
|
112
|
+
when :button
|
113
|
+
when :calendar
|
114
|
+
when :check_box
|
115
|
+
extend Bewildr::ControlPatterns::TogglePattern
|
116
|
+
when :combo_box
|
117
|
+
extend Bewildr::ControlTypeAdditions::ComboBoxAdditions
|
118
|
+
when :custom
|
119
|
+
when :data_grid
|
120
|
+
extend Bewildr::ControlTypeAdditions::DataGridAdditions
|
121
|
+
when :data_item
|
122
|
+
when :document
|
123
|
+
when :edit
|
124
|
+
extend Bewildr::ControlPatterns::ValuePattern
|
125
|
+
when :group
|
126
|
+
when :header
|
127
|
+
when :header_item
|
128
|
+
when :hyperlink
|
129
|
+
extend Bewildr::ControlTypeAdditions::TextAdditions
|
130
|
+
when :image
|
131
|
+
when :list
|
132
|
+
extend Bewildr::ControlTypeAdditions::ListAdditions
|
133
|
+
when :list_item
|
134
|
+
extend Bewildr::ControlPatterns::SelectionItemPattern
|
135
|
+
when :menu
|
136
|
+
extend Bewildr::ControlTypeAdditions::MenuAdditions
|
137
|
+
when :menu_bar
|
138
|
+
when :menu_item
|
139
|
+
extend Bewildr::ControlTypeAdditions::MenuItemAdditions
|
140
|
+
when :pane
|
141
|
+
when :progress_bar
|
142
|
+
extend Bewildr::ControlPatterns::RangeValuePattern
|
143
|
+
when :radio_button
|
144
|
+
extend Bewildr::ControlPatterns::SelectionItemPattern
|
145
|
+
when :scroll_bar
|
146
|
+
when :seperator
|
147
|
+
when :slider
|
148
|
+
when :spinner
|
149
|
+
when :split_button
|
150
|
+
when :status_bar
|
151
|
+
when :tab
|
152
|
+
extend Bewildr::ControlTypeAdditions::TabAdditions
|
153
|
+
when :tab_item
|
154
|
+
extend Bewildr::ControlPatterns::SelectionItemPattern
|
155
|
+
when :table
|
156
|
+
when :text
|
157
|
+
extend Bewildr::ControlTypeAdditions::TextAdditions
|
158
|
+
when :thumb
|
159
|
+
when :title_bar
|
160
|
+
when :tool_bar
|
161
|
+
when :tool_tip
|
162
|
+
when :tree
|
163
|
+
extend Bewildr::ControlTypeAdditions::TreeAdditions
|
164
|
+
when :tree_item
|
165
|
+
extend Bewildr::ControlTypeAdditions::TreeItemAdditions
|
166
|
+
when :window
|
167
|
+
extend Bewildr::ControlTypeAdditions::WindowAdditions
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
class ElementNotEnabled < StandardError; end
|
4
|
+
class ElementDoesntExist < StandardError; end
|
5
|
+
class PasswordFieldReadAttempt < StandardError; end
|
6
|
+
class NoSuchItemInComboBox < StandardError; end
|
7
|
+
|
8
|
+
class BewildrInternalError < StandardError; end
|
Binary file
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
class Finder
|
5
|
+
extend Bewildr::BewildrHelpers
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def condition_for(condition_hash)
|
9
|
+
conditions = condition_hash.select {|key, value| [:id, :name, :type].include?(key) }
|
10
|
+
conditions = Hash[*conditions.flatten]
|
11
|
+
case
|
12
|
+
when conditions.length == 0 then raise "Condition needs to include at least an :id, a :name or a :type"
|
13
|
+
when conditions.length == 1 then return single_condition(conditions)
|
14
|
+
when conditions.length > 1 then return multiple_conditions(conditions)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def scope_for(condition_hash)
|
19
|
+
case condition_hash[:scope]
|
20
|
+
when :children then System::Windows::Automation::TreeScope.Children
|
21
|
+
when :descendants, nil then System::Windows::Automation::TreeScope.Descendants
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#returns the method to call
|
26
|
+
def how_many_for(condition_hash)
|
27
|
+
case condition_hash[:how_many]
|
28
|
+
when :first then :find_first
|
29
|
+
when :all, nil then :find_all
|
30
|
+
else raise "Invalid number of elements to look for. Use ':first' or ':all'"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def multiple_conditions(condition_hash)
|
37
|
+
condition_array = []
|
38
|
+
condition_hash.keys.each {|key| condition_array << single_condition({key => condition_hash[key]}) }
|
39
|
+
System::Windows::Automation::AndCondition.new(r_array_to_cs_array_of_conditions(condition_array))
|
40
|
+
end
|
41
|
+
|
42
|
+
def single_condition(condition_hash)
|
43
|
+
case condition_hash.keys.first
|
44
|
+
when :id then id_condition(condition_hash)
|
45
|
+
when :name then name_condition(condition_hash)
|
46
|
+
when :type then type_condition(condition_hash)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def id_condition(condition_hash)
|
51
|
+
value = r_string_to_c_string(condition_hash[:id].to_s)
|
52
|
+
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.automation_id_property, value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def name_condition(condition_hash)
|
56
|
+
value = r_string_to_c_string(condition_hash[:name])
|
57
|
+
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.name_property, value)
|
58
|
+
end
|
59
|
+
|
60
|
+
def type_condition(condition_hash)
|
61
|
+
value = Bewildr::ControlType.class_for_symbol(condition_hash[:type])
|
62
|
+
System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.control_type_property, value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
2
|
+
|
3
|
+
module Bewildr
|
4
|
+
class Windows
|
5
|
+
def self.windows_by_process_id(process_id)
|
6
|
+
#find top level windows
|
7
|
+
window_scope = System::Windows::Automation::TreeScope.Children
|
8
|
+
process_id_property = System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.process_id_property, process_id.to_i)
|
9
|
+
top_level_windows = System::Windows::Automation::AutomationElement.root_element.find_all(window_scope, process_id_property).to_a
|
10
|
+
|
11
|
+
all_windows = []
|
12
|
+
all_windows << top_level_windows
|
13
|
+
|
14
|
+
#loop through the top level windows looking for child windows
|
15
|
+
top_level_windows.each do |top_level_window|
|
16
|
+
control_type_property = System::Windows::Automation::PropertyCondition.new(System::Windows::Automation::AutomationElement.control_type_property, System::Windows::Automation::ControlType.Window)
|
17
|
+
all_windows << top_level_window.find_all(window_scope, control_type_property).to_a
|
18
|
+
end
|
19
|
+
|
20
|
+
all_windows.flatten.collect {|window| Bewildr::Element.new(window)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bewildr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Nat Ritmeyer
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-04-20 00:00:00 +01:00
|
17
|
+
default_executable:
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: Test your WPF apps with (iron) ruby!
|
21
|
+
email: nat@natontesting.com
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files:
|
27
|
+
- README
|
28
|
+
- LICENSE
|
29
|
+
files:
|
30
|
+
- LICENSE
|
31
|
+
- README
|
32
|
+
- Rakefile
|
33
|
+
- lib/bewildr/application.rb
|
34
|
+
- lib/bewildr/bewildr_helpers.rb
|
35
|
+
- lib/bewildr/control_patterns/expand_collapse_pattern.rb
|
36
|
+
- lib/bewildr/control_patterns/grid_pattern.rb
|
37
|
+
- lib/bewildr/control_patterns/invoke_pattern.rb
|
38
|
+
- lib/bewildr/control_patterns/range_value_pattern.rb
|
39
|
+
- lib/bewildr/control_patterns/selection_item_pattern.rb
|
40
|
+
- lib/bewildr/control_patterns/selection_pattern.rb
|
41
|
+
- lib/bewildr/control_patterns/table_pattern.rb
|
42
|
+
- lib/bewildr/control_patterns/toggle_pattern.rb
|
43
|
+
- lib/bewildr/control_patterns/value_pattern.rb
|
44
|
+
- lib/bewildr/control_patterns/window_pattern.rb
|
45
|
+
- lib/bewildr/control_type.rb
|
46
|
+
- lib/bewildr/control_type_additions/combo_box_additions.rb
|
47
|
+
- lib/bewildr/control_type_additions/data_grid_additions.rb
|
48
|
+
- lib/bewildr/control_type_additions/list_additions.rb
|
49
|
+
- lib/bewildr/control_type_additions/menu_additions.rb
|
50
|
+
- lib/bewildr/control_type_additions/menu_item_additions.rb
|
51
|
+
- lib/bewildr/control_type_additions/tab_additions.rb
|
52
|
+
- lib/bewildr/control_type_additions/text_additions.rb
|
53
|
+
- lib/bewildr/control_type_additions/tree_additions.rb
|
54
|
+
- lib/bewildr/control_type_additions/tree_item_additions.rb
|
55
|
+
- lib/bewildr/control_type_additions/window_additions.rb
|
56
|
+
- lib/bewildr/element.rb
|
57
|
+
- lib/bewildr/exceptions.rb
|
58
|
+
- lib/bewildr/ext/BewildrClickr.dll
|
59
|
+
- lib/bewildr/finder.rb
|
60
|
+
- lib/bewildr/windows.rb
|
61
|
+
- lib/bewildr.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/natritmeyer/bewildr
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Test your WPF apps with (iron) ruby!
|
92
|
+
test_files: []
|
93
|
+
|