AXElements 0.6.0beta2 → 0.7.5
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/.yardopts +1 -2
- data/README.markdown +152 -88
- data/Rakefile +8 -103
- data/docs/Debugging.markdown +9 -2
- data/docs/KeyboardEvents.markdown +114 -49
- data/docs/Setting.markdown +1 -0
- data/docs/images/next_version.png +0 -0
- data/ext/accessibility/key_coder/extconf.rb +22 -0
- data/ext/accessibility/key_coder/key_coder.c +113 -0
- data/lib/AXElements.rb +2 -0
- data/lib/accessibility/core.rb +897 -0
- data/lib/accessibility/debug.rb +168 -0
- data/lib/accessibility/dsl.rb +697 -0
- data/lib/accessibility/enumerators.rb +104 -0
- data/lib/accessibility/errors.rb +32 -0
- data/lib/accessibility/factory.rb +153 -0
- data/lib/accessibility/graph.rb +150 -0
- data/lib/{ax_elements/inspector.rb → accessibility/pp_inspector.rb} +39 -28
- data/lib/accessibility/qualifier.rb +158 -0
- data/lib/accessibility/string.rb +494 -0
- data/lib/accessibility/translator.rb +178 -0
- data/lib/accessibility/version.rb +7 -0
- data/lib/accessibility.rb +79 -0
- data/lib/ax/application.rb +234 -0
- data/lib/{ax_elements/elements → ax}/button.rb +2 -0
- data/lib/ax/element.rb +518 -0
- data/lib/{ax_elements/elements → ax}/radio_button.rb +2 -0
- data/lib/ax/row.rb +37 -0
- data/lib/{ax_elements/elements → ax}/static_text.rb +2 -0
- data/lib/ax/systemwide.rb +86 -0
- data/lib/ax_elements/awesome_print.rb +25 -0
- data/lib/ax_elements/exception_workaround.rb +8 -0
- data/lib/ax_elements/nsarray_compat.rb +64 -0
- data/lib/ax_elements/vendor/inflection_data.rb +65 -0
- data/lib/ax_elements/vendor/inflections.rb +172 -0
- data/lib/ax_elements/vendor/inflector.rb +306 -0
- data/lib/ax_elements.rb +14 -25
- data/lib/minitest/ax_elements.rb +112 -12
- data/lib/mouse.rb +72 -46
- data/lib/rspec/expectations/ax_elements.rb +133 -6
- data/rakelib/doc.rake +13 -0
- data/rakelib/ext.rake +61 -0
- data/rakelib/gem.rake +28 -0
- data/rakelib/test.rake +53 -0
- data/test/helper.rb +11 -97
- data/test/integration/accessibility/test_core.rb +18 -0
- data/test/integration/accessibility/test_debug.rb +44 -0
- data/test/integration/accessibility/test_dsl.rb +225 -0
- data/test/integration/accessibility/test_enumerators.rb +122 -0
- data/test/integration/accessibility/test_errors.rb +38 -0
- data/test/integration/accessibility/test_notifications.rb +22 -0
- data/test/integration/accessibility/test_qualifier.rb +148 -0
- data/test/integration/ax/test_application.rb +56 -0
- data/test/integration/ax/test_element.rb +46 -0
- data/test/integration/ax/test_row.rb +23 -0
- data/test/integration/ax_elements/test_nsarray_compat.rb +43 -0
- data/test/integration/minitest/test_ax_elements.rb +98 -0
- data/test/integration/rspec/expectations/test_ax_elements.rb +58 -0
- data/test/integration/test_mouse.rb +35 -0
- data/test/sanity/accessibility/test_core.rb +553 -0
- data/test/sanity/accessibility/test_debug.rb +63 -0
- data/test/sanity/accessibility/test_dsl.rb +75 -0
- data/test/sanity/accessibility/test_errors.rb +10 -0
- data/test/sanity/accessibility/test_factory.rb +88 -0
- data/test/sanity/accessibility/test_pp_inspector.rb +110 -0
- data/test/sanity/accessibility/test_qualifier.rb +13 -0
- data/test/sanity/accessibility/test_string.rb +238 -0
- data/test/sanity/accessibility/test_translator.rb +145 -0
- data/test/sanity/ax/test_application.rb +90 -0
- data/test/sanity/ax/test_element.rb +80 -0
- data/test/sanity/ax/test_systemwide.rb +66 -0
- data/test/sanity/ax_elements/test_nsarray_compat.rb +16 -0
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +11 -0
- data/test/sanity/minitest/test_ax_elements.rb +15 -0
- data/test/sanity/rspec/expectations/test_ax_elements.rb +12 -0
- data/test/sanity/test_ax_elements.rb +10 -0
- data/test/sanity/test_mouse.rb +19 -0
- metadata +111 -93
- data/LICENSE.txt +0 -25
- data/ext/key_coder/extconf.rb +0 -6
- data/ext/key_coder/key_coder.m +0 -77
- data/lib/ax_elements/accessibility/enumerators.rb +0 -104
- data/lib/ax_elements/accessibility/graph.rb +0 -118
- data/lib/ax_elements/accessibility/language.rb +0 -347
- data/lib/ax_elements/accessibility/qualifier.rb +0 -73
- data/lib/ax_elements/accessibility.rb +0 -166
- data/lib/ax_elements/core.rb +0 -541
- data/lib/ax_elements/element.rb +0 -593
- data/lib/ax_elements/elements/application.rb +0 -88
- data/lib/ax_elements/elements/row.rb +0 -30
- data/lib/ax_elements/elements/systemwide.rb +0 -46
- data/lib/ax_elements/macruby_extensions.rb +0 -255
- data/lib/ax_elements/notification.rb +0 -37
- data/lib/ax_elements/version.rb +0 -9
- data/test/elements/test_application.rb +0 -72
- data/test/elements/test_row.rb +0 -27
- data/test/elements/test_systemwide.rb +0 -38
- data/test/test_accessibility.rb +0 -127
- data/test/test_blankness.rb +0 -26
- data/test/test_core.rb +0 -448
- data/test/test_element.rb +0 -939
- data/test/test_enumerators.rb +0 -81
- data/test/test_inspector.rb +0 -130
- data/test/test_language.rb +0 -157
- data/test/test_macruby_extensions.rb +0 -303
- data/test/test_mouse.rb +0 -5
- data/test/test_search_semantics.rb +0 -143
data/test/helper.rb
CHANGED
|
@@ -1,119 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require 'ax_elements'
|
|
4
|
-
require 'stringio'
|
|
5
|
-
|
|
6
|
-
# Accessibility.log.level = Logger::DEBUG
|
|
1
|
+
framework 'Cocoa'
|
|
7
2
|
|
|
8
3
|
# We want to launch the test app and make sure it responds to
|
|
9
4
|
# accessibility queries, but that is difficult, so we just sleep
|
|
10
|
-
APP_BUNDLE_URL = NSURL.
|
|
5
|
+
APP_BUNDLE_URL = NSURL.fileURLWithPath File.expand_path './test/fixture/Release/AXElementsTester.app'
|
|
6
|
+
APP_BUNDLE_IDENTIFIER = 'com.marketcircle.AXElementsTester'
|
|
11
7
|
|
|
12
|
-
error
|
|
8
|
+
error = Pointer.new :id
|
|
13
9
|
TEST_APP = NSWorkspace.sharedWorkspace.launchApplicationAtURL APP_BUNDLE_URL,
|
|
14
10
|
options: NSWorkspaceLaunchAsync,
|
|
15
11
|
configuration: {},
|
|
16
12
|
error: error
|
|
17
|
-
if
|
|
18
|
-
$stderr.puts 'You need to build AND run the fixture app before running tests'
|
|
19
|
-
$stderr.puts 'Run `rake fixture
|
|
13
|
+
if TEST_APP.nil?
|
|
14
|
+
$stderr.puts 'You need to build AND run the fixture app once before running tests'
|
|
15
|
+
$stderr.puts 'Run `rake run_fixture` to initalize the fixture'
|
|
20
16
|
exit 3
|
|
21
17
|
else
|
|
22
|
-
sleep
|
|
23
|
-
#
|
|
18
|
+
sleep 2 # Instead of using high level features of AXElements that we are
|
|
19
|
+
# testing, I think it is just safer to sleep
|
|
24
20
|
# Make sure the test app is closed when testing finishes
|
|
25
21
|
at_exit do TEST_APP.terminate end
|
|
26
22
|
end
|
|
27
23
|
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
require 'minitest/autorun'
|
|
31
|
-
|
|
32
|
-
# preprocessor powers, assemble!
|
|
33
|
-
if ENV['BENCH']
|
|
34
|
-
require 'minitest/benchmark'
|
|
35
|
-
else
|
|
36
|
-
require'minitest/pride'
|
|
37
|
-
end
|
|
25
|
+
require 'test/runner'
|
|
38
26
|
|
|
39
27
|
|
|
40
28
|
class MiniTest::Unit::TestCase
|
|
41
|
-
#
|
|
42
|
-
# def self.test_order
|
|
43
|
-
# :alpha
|
|
44
|
-
# end
|
|
45
|
-
|
|
46
|
-
def assert_instance_of_boolean value
|
|
47
|
-
message = "Expected #{value.inspect} to be a boolean"
|
|
48
|
-
assert value.is_a?(TrueClass) || value.is_a?(FalseClass), message
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.bench_range
|
|
52
|
-
bench_exp 10, 10_000
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
##
|
|
57
|
-
# A mix in module to allow capture of logs
|
|
58
|
-
module LoggingCapture
|
|
59
|
-
def setup
|
|
60
|
-
super
|
|
61
|
-
@log_output = StringIO.new
|
|
62
|
-
Accessibility.log = Logger.new @log_output
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
module AXHelpers
|
|
67
|
-
def pid_for name
|
|
68
|
-
NSWorkspace.sharedWorkspace.runningApplications.find do |app|
|
|
69
|
-
app.bundleIdentifier == name
|
|
70
|
-
end.processIdentifier
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# returns raw attribute
|
|
74
|
-
def attribute_for element, attr
|
|
75
|
-
ptr = Pointer.new :id
|
|
76
|
-
AXUIElementCopyAttributeValue(element, attr, ptr)
|
|
77
|
-
ptr[0]
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def children_for element
|
|
81
|
-
attribute_for element, KAXChildrenAttribute
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def value_for element
|
|
85
|
-
attribute_for element, KAXValueAttribute
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def action_for element, action
|
|
89
|
-
AXUIElementPerformAction(element, action)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# remember to wrap structs in an AXValueRef
|
|
93
|
-
def set_attribute_for element, attr, value
|
|
94
|
-
AXUIElementSetAttributeValue(element, attr, value)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
class TestAX < MiniTest::Unit::TestCase
|
|
99
|
-
include AXHelpers
|
|
100
|
-
extend AXHelpers
|
|
101
|
-
|
|
102
|
-
APP_BUNDLE_IDENTIFIER = 'com.marketcircle.AXElementsTester'
|
|
29
|
+
# needs to be defined in the class, there is a TOPLEVEL::PID
|
|
103
30
|
PID = pid_for APP_BUNDLE_IDENTIFIER
|
|
104
31
|
REF = AXUIElementCreateApplication(PID)
|
|
105
|
-
|
|
106
|
-
# execute the block with full logging turned on
|
|
107
|
-
def with_logging level = Logger::DEBUG
|
|
108
|
-
original_level = Accessibility.log.level
|
|
109
|
-
Accessibility.log.level = level
|
|
110
|
-
yield
|
|
111
|
-
Accessibility.log.level = original_level
|
|
112
|
-
end
|
|
113
32
|
end
|
|
114
33
|
|
|
115
|
-
##
|
|
116
|
-
# Just pretend that you didnt' see this hack
|
|
117
|
-
class AX::Element
|
|
118
|
-
attr_reader :ref
|
|
119
|
-
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'test/integration/helper'
|
|
2
|
+
|
|
3
|
+
class TestAccessibilityCore < MiniTest::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
# this assumes that radar://10040865 is not fixed
|
|
6
|
+
# once it is fixed, this case becomes less of an
|
|
7
|
+
# issue anyways
|
|
8
|
+
def test_nil_children_returns_empty_array
|
|
9
|
+
app = app_with_name 'AXElementsTester'
|
|
10
|
+
menu = app.menu_bar_item(title: 'Help')
|
|
11
|
+
press menu
|
|
12
|
+
|
|
13
|
+
assert_empty menu.search_field.children
|
|
14
|
+
ensure
|
|
15
|
+
cancel menu if menu
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'test/integration/helper'
|
|
2
|
+
|
|
3
|
+
class TestAccessibilityDebug < MiniTest::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def app
|
|
6
|
+
@app ||= AX::Application.new PID
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_path_returns_correct_elements_in_correct_order
|
|
10
|
+
list = Accessibility::Debug.path(app.window.close_button)
|
|
11
|
+
assert_equal 3, list.size
|
|
12
|
+
assert_instance_of AX::CloseButton, list.first
|
|
13
|
+
assert_instance_of AX::StandardWindow, list.second
|
|
14
|
+
assert_instance_of AX::Application, list.third
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_dump_works_for_nested_tab_groups
|
|
18
|
+
element = app.window.tab_group
|
|
19
|
+
output = Accessibility::Debug.subtree_for element
|
|
20
|
+
|
|
21
|
+
expected = [
|
|
22
|
+
['AX::TabGroup', 0],
|
|
23
|
+
['AX::RadioButton', 1], ['AX::RadioButton', 1], ['AX::TabGroup', 1],
|
|
24
|
+
['AX::RadioButton', 2], ['AX::RadioButton', 2], ['AX::TabGroup', 2],
|
|
25
|
+
['AX::RadioButton', 3], ['AX::RadioButton', 3], ['AX::TabGroup', 3],
|
|
26
|
+
['AX::RadioButton', 4], ['AX::RadioButton', 4],
|
|
27
|
+
['AX::Group', 4],
|
|
28
|
+
['AX::TextField', 5], ['AX::StaticText', 6],
|
|
29
|
+
['AX::TextField' , 5], ['AX::StaticText', 6]
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
refute_empty output
|
|
33
|
+
output = output.split("\n")
|
|
34
|
+
|
|
35
|
+
until output.empty?
|
|
36
|
+
line = output.shift
|
|
37
|
+
klass, indents = expected.shift
|
|
38
|
+
assert_equal indents, line.match(/^\t*/).to_a.first.length, line
|
|
39
|
+
line.strip!
|
|
40
|
+
assert_match /^\#<#{klass}/, line
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'test/integration/helper'
|
|
3
|
+
|
|
4
|
+
class TestAccessibilityDSL < MiniTest::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
# LSP FTW
|
|
7
|
+
class DSL
|
|
8
|
+
include Accessibility::DSL
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def dsl
|
|
12
|
+
@dsl ||= DSL.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def app
|
|
16
|
+
@@app ||= AX::Application.new REF
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def text_area
|
|
20
|
+
@@text_area ||= app.main_window.text_area
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def pref_window
|
|
24
|
+
app.children.find { |x|
|
|
25
|
+
x.attributes.include?(:title) && x.title == 'Preferences'
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def spelling_window
|
|
30
|
+
app.children.find { |x|
|
|
31
|
+
x.attributes.include?(:title) && x.title.match(/^Spelling/)
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def try_typing string, expected = nil
|
|
36
|
+
expected = string unless expected
|
|
37
|
+
text_area.set :focused, true
|
|
38
|
+
dsl.type string
|
|
39
|
+
assert_equal expected, text_area.value
|
|
40
|
+
ensure # reset for next test
|
|
41
|
+
dsl.type "\\COMMAND+a \b"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_dsl_is_mixed_into_toplevel
|
|
45
|
+
assert_includes Object.new.class.ancestors, Accessibility::DSL
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_application_with_bundle_id
|
|
49
|
+
assert_equal app, dsl.app_with_bundle_identifier(APP_BUNDLE_IDENTIFIER)
|
|
50
|
+
assert_equal app, dsl.app_with_bundle_id(APP_BUNDLE_IDENTIFIER)
|
|
51
|
+
assert_equal app, dsl.launch(APP_BUNDLE_IDENTIFIER)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_application_with_name
|
|
55
|
+
assert_equal app, dsl.app_with_name('AXElementsTester')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_application_with_pid
|
|
59
|
+
assert_equal app, dsl.app_with_pid(PID)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_typing_human_string
|
|
63
|
+
try_typing "A sentence, with punctuation and num8ers. LOL!\tA 'quoted' string--then some @#*$."
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_typing_backspaces
|
|
67
|
+
try_typing "The cake is a lie!\b\b\b\bgift!", 'The cake is a gift!'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_typing_hotkeys
|
|
71
|
+
try_typing ", world!\\CONTROL+a Hello", 'Hello, world!'
|
|
72
|
+
try_typing "MacRuby\\OPTION+2", 'MacRuby™'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_typing_command_keys
|
|
76
|
+
try_typing "Hai.\\<- \\<- \b", "Hi."
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_typing_ruby_escapes
|
|
80
|
+
try_typing "First.\nSecond."
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_select_menu_item_string
|
|
84
|
+
assert_nil pref_window
|
|
85
|
+
dsl.select_menu_item app, app.title, 'Preferences…'
|
|
86
|
+
window = dsl.wait_for :window, parent: app, title: 'Preferences'
|
|
87
|
+
refute_nil window
|
|
88
|
+
ensure
|
|
89
|
+
window.close_button.perform :press if window
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_select_menu_item_regexp
|
|
93
|
+
assert_nil spelling_window
|
|
94
|
+
dsl.select_menu_item app, /Edit/, /Spelling/, /show spelling/i
|
|
95
|
+
window = dsl.wait_for :floating_window, parent: app
|
|
96
|
+
refute_nil window
|
|
97
|
+
ensure
|
|
98
|
+
window.close_button.perform :press if window
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_select_menu_item_raises_if_cannot_find_item
|
|
102
|
+
assert_raises Accessibility::SearchFailure do
|
|
103
|
+
dsl.select_menu_item app, 'File', 'NonExistantMenuItem'
|
|
104
|
+
end
|
|
105
|
+
# @todo verify that menu is closed
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_select_menu_item_provides_proper_debug_info
|
|
109
|
+
e = assert_raises Accessibility::SearchFailure do
|
|
110
|
+
dsl.select_menu_item app, 'Format', 'Front'
|
|
111
|
+
end
|
|
112
|
+
assert_match /MenuItem/, e.message
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def test_wait_for_obeys_timeout_option
|
|
116
|
+
# loop sleeps for 0.2, so we have to wait at least that long
|
|
117
|
+
start = Time.now
|
|
118
|
+
dsl.wait_for :strawberry_rhubarb, parent: AX::DOCK, timeout: 0.2
|
|
119
|
+
assert_in_delta Time.now, start, 0.3
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_wait_for_parent_only_looks_at_children
|
|
123
|
+
result = dsl.wait_for :trash_dock_item, parent: AX::DOCK, timeout: 0.5
|
|
124
|
+
assert_nil result
|
|
125
|
+
|
|
126
|
+
result = dsl.wait_for :trash_dock_item, parent: AX::DOCK.list
|
|
127
|
+
assert_equal AX::DOCK.list.trash_dock_item, result
|
|
128
|
+
|
|
129
|
+
result = dsl.wait_for :button, parent: app.main_window, title: 'Yes'
|
|
130
|
+
assert_equal 'Yes', result.title
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_wait_for_ancestor_searches
|
|
134
|
+
result = dsl.wait_for :trash_dock_item, ancestor: AX::DOCK
|
|
135
|
+
assert_equal AX::DOCK.list.trash_dock_item, result
|
|
136
|
+
|
|
137
|
+
result = dsl.wait_for :nothing, ancestor: AX::DOCK, timeout: 0.5
|
|
138
|
+
assert_nil result
|
|
139
|
+
|
|
140
|
+
result = dsl.wait_for :text_field, ancestor: app.main_window, value: 'AXIsNyan'
|
|
141
|
+
assert_equal 'AXIsNyan', result.value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_system_wide
|
|
145
|
+
assert_instance_of AX::SystemWide, dsl.system_wide
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_element_under_mouse
|
|
149
|
+
[
|
|
150
|
+
app.main_window.close_button,
|
|
151
|
+
app.main_window.value_indicator
|
|
152
|
+
].each do |element|
|
|
153
|
+
dsl.move_mouse_to element
|
|
154
|
+
assert_equal element, dsl.element_under_mouse
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def test_element_at_point_for_app
|
|
159
|
+
[
|
|
160
|
+
app.main_window.minimize_button,
|
|
161
|
+
app.main_window.increment_arrow
|
|
162
|
+
].each do |element|
|
|
163
|
+
assert_equal element, dsl.element_at_point(element, for: app)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# @todo We aren't being very thorough here
|
|
168
|
+
def test_element_at_point
|
|
169
|
+
[
|
|
170
|
+
app.main_window.minimize_button,
|
|
171
|
+
app.main_window.increment_arrow
|
|
172
|
+
].each do |element|
|
|
173
|
+
assert_equal element, dsl.element_at_point(element)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def test_show_about_window
|
|
178
|
+
dialog = dsl.show_about_window_for app
|
|
179
|
+
assert_instance_of AX::Dialog, dialog
|
|
180
|
+
assert_equal 'AXElementsTester icon', dialog.image.description
|
|
181
|
+
ensure
|
|
182
|
+
dialog.close_button.perform :press if dialog
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_show_prefs_for_app
|
|
186
|
+
prefs = dsl.show_preferences_window_for app
|
|
187
|
+
assert_kind_of AX::Window, prefs
|
|
188
|
+
assert_equal 'Preferences', prefs.title
|
|
189
|
+
ensure
|
|
190
|
+
prefs.close_button.perform :press if prefs
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_scroll_to
|
|
194
|
+
table = app.main_window.table
|
|
195
|
+
['AXIsNyan', 'AXSubrole'].each do |attr|
|
|
196
|
+
text = table.text_field(value: attr)
|
|
197
|
+
dsl.scroll_to text
|
|
198
|
+
assert NSContainsRect(table.bounds, text.bounds)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_scroll_menu_to
|
|
203
|
+
pop_up = app.main_window.pop_up_button
|
|
204
|
+
|
|
205
|
+
pop_up.perform :press
|
|
206
|
+
expected = pop_up.menu_item(title: '49')
|
|
207
|
+
dsl.scroll_menu_to expected
|
|
208
|
+
assert_equal expected, element_under_mouse
|
|
209
|
+
dsl.click
|
|
210
|
+
assert_equal '49', pop_up.value
|
|
211
|
+
|
|
212
|
+
pop_up.perform :press
|
|
213
|
+
expected = pop_up.menu_item(title: 'Togusa')
|
|
214
|
+
dsl.scroll_menu_to expected
|
|
215
|
+
assert_equal expected, element_under_mouse
|
|
216
|
+
dsl.click
|
|
217
|
+
assert_equal 'Togusa', pop_up.value
|
|
218
|
+
|
|
219
|
+
ensure
|
|
220
|
+
unless pop_up.children.empty?
|
|
221
|
+
pop_up.menu_item.perform :cancel
|
|
222
|
+
end if pop_up
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'test/integration/helper'
|
|
2
|
+
|
|
3
|
+
class TestAccessibilityEnumeratorsBreadthFirst < MiniTest::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def app
|
|
6
|
+
@@app ||= AX::Application.new REF
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_each_iterates_in_correct_order
|
|
10
|
+
tab_group = app.main_window.children.find { |x| x.class == AX::TabGroup }
|
|
11
|
+
enum = Accessibility::Enumerators::BreadthFirst.new(tab_group)
|
|
12
|
+
actual = enum.map &:class
|
|
13
|
+
expected = [
|
|
14
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
15
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
16
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
17
|
+
AX::RadioButton, AX::RadioButton, AX::Group,
|
|
18
|
+
AX::TextField, AX::TextField,
|
|
19
|
+
AX::StaticText, AX::StaticText
|
|
20
|
+
]
|
|
21
|
+
assert_equal expected, actual
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_first_element_is_first_child # not the root
|
|
25
|
+
enum = Accessibility::Enumerators::BreadthFirst.new app
|
|
26
|
+
def enum.first
|
|
27
|
+
each { |x| return x }
|
|
28
|
+
end
|
|
29
|
+
assert_instance_of AX::StandardWindow, enum.first
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# this was a big performance issue, so we should make sure it
|
|
33
|
+
# doesn't happen again
|
|
34
|
+
def test_find_returns_immediately_after_finding
|
|
35
|
+
tree = Accessibility::Enumerators::BreadthFirst.new app
|
|
36
|
+
cache = []
|
|
37
|
+
tree.find do |element|
|
|
38
|
+
cache << element.class
|
|
39
|
+
element.class == AX::StandardWindow
|
|
40
|
+
end
|
|
41
|
+
assert_equal 1, cache.size
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def bench_each
|
|
45
|
+
skip 'TODO'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def bench_find
|
|
49
|
+
skip 'TODO'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestAccessibilityEnumeratorsDepthFirst < MiniTest::Unit::TestCase
|
|
56
|
+
include Accessibility::Core
|
|
57
|
+
|
|
58
|
+
def app
|
|
59
|
+
@@app ||= AX::Application.new REF
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_each_iterates_in_correct_order
|
|
63
|
+
tab_group = app.main_window.children.find { |x| x.class == AX::TabGroup }
|
|
64
|
+
enum = Accessibility::Enumerators::DepthFirst.new tab_group
|
|
65
|
+
actual = enum.map &:class
|
|
66
|
+
expected = [
|
|
67
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
68
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
69
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
70
|
+
AX::RadioButton, AX::RadioButton, AX::Group,
|
|
71
|
+
AX::TextField, AX::StaticText,
|
|
72
|
+
AX::TextField, AX::StaticText
|
|
73
|
+
]
|
|
74
|
+
assert_equal expected, actual
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# since we have a different implementation, we should also verify order here...
|
|
78
|
+
def test_each_with_level_in_correct_order
|
|
79
|
+
tab_group = app.main_window.children.find { |x| x.class == AX::TabGroup }
|
|
80
|
+
enum = Accessibility::Enumerators::DepthFirst.new tab_group
|
|
81
|
+
actual = []
|
|
82
|
+
enum.each_with_level do |x,_| actual << x.class end
|
|
83
|
+
expected = [
|
|
84
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
85
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
86
|
+
AX::RadioButton, AX::RadioButton, AX::TabGroup,
|
|
87
|
+
AX::RadioButton, AX::RadioButton, AX::Group,
|
|
88
|
+
AX::TextField, AX::StaticText,
|
|
89
|
+
AX::TextField, AX::StaticText
|
|
90
|
+
]
|
|
91
|
+
assert_equal expected, actual
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_each_with_level_has_correct_height
|
|
95
|
+
enum = Accessibility::Enumerators::DepthFirst.new app.main_window
|
|
96
|
+
actual = []
|
|
97
|
+
enum.each_with_level do |element, level|
|
|
98
|
+
actual << [element.class, level]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
assert_includes actual, [AX::Slider, 1]
|
|
102
|
+
assert_includes actual, [AX::CloseButton, 1]
|
|
103
|
+
assert_includes actual, [AX::ZoomButton, 1]
|
|
104
|
+
assert_includes actual, [AX::MinimizeButton, 1]
|
|
105
|
+
assert_includes actual, [AX::SearchField, 1]
|
|
106
|
+
assert_includes actual, [AX::CheckBox, 1]
|
|
107
|
+
assert_includes actual, [AX::WebArea, 2]
|
|
108
|
+
assert_includes actual, [AX::Table, 2]
|
|
109
|
+
assert_includes actual, [AX::ScrollBar, 2]
|
|
110
|
+
assert_includes actual, [AX::SortButton, 4]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def bench_each
|
|
114
|
+
skip 'TODO'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def bench_each_with_level
|
|
118
|
+
skip 'TODO'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'test/integration/helper'
|
|
2
|
+
|
|
3
|
+
class TestAccessibilityErrors < MiniTest::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_search_failure_shows_arguments
|
|
6
|
+
e = Accessibility::SearchFailure.new(AX::DOCK, :list, {herp: :derp})
|
|
7
|
+
def e.backtrace; []; end
|
|
8
|
+
assert_match /Could not find `List\(herp: :derp\)`/, e.message
|
|
9
|
+
assert_match /as a child of AX::Application/, e.message
|
|
10
|
+
assert_match /Element Path:\n\t\#<AX::Application/, e.message
|
|
11
|
+
|
|
12
|
+
e = Accessibility::SearchFailure.new(AX::DOCK, :list, {})
|
|
13
|
+
def e.backtrace; []; end
|
|
14
|
+
assert_match /Could not find `List`/, e.message
|
|
15
|
+
|
|
16
|
+
e = Accessibility::SearchFailure.new(AX::DOCK, :list, nil)
|
|
17
|
+
def e.backtrace; []; end
|
|
18
|
+
assert_match /Could not find `List`/, e.message
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_search_failure_shows_element_path
|
|
22
|
+
l = AX::DOCK.children.first
|
|
23
|
+
e = Accessibility::SearchFailure.new(l, :trash_dock_item, nil)
|
|
24
|
+
def e.backtrace; []; end
|
|
25
|
+
assert_match /AX::Application/, e.message
|
|
26
|
+
assert_match /AX::List/, e.message
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_search_failure_includes_subtree_in_debug_mode
|
|
30
|
+
assert Accessibility::Debug.on?, 'Someone turned debugging off'
|
|
31
|
+
l = AX::DOCK.children.first
|
|
32
|
+
e = Accessibility::SearchFailure.new(l, :trash_dock_item, nil)
|
|
33
|
+
def e.backtrace; []; end
|
|
34
|
+
assert_match /Subtree:/, e.message
|
|
35
|
+
assert_match subtree_for(l), e.message
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class TestAccessibilityNotifications < MiniTest::Unit::TestCase
|
|
2
|
+
|
|
3
|
+
def test_custom_notifications
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_standard_notifications
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_notifications_from_the_app
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_notification_filtering
|
|
16
|
+
# I can reject based on block return value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_notification_callbacks_get_correct_arguments
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|