AXElements 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +4 -0
- data/History.markdown +41 -0
- data/README.markdown +59 -62
- data/Rakefile +1 -1
- data/ext/accessibility/key_coder/extconf.rb +1 -1
- data/ext/accessibility/key_coder/key_coder.c +8 -5
- data/lib/accessibility/dsl.rb +261 -87
- data/lib/accessibility/enumerators.rb +14 -11
- data/lib/accessibility/errors.rb +4 -3
- data/lib/accessibility/factory.rb +159 -108
- data/lib/accessibility/graph.rb +13 -9
- data/lib/accessibility/{pp_inspector.rb → pretty_printer.rb} +4 -5
- data/lib/accessibility/qualifier.rb +23 -13
- data/lib/accessibility/string.rb +4 -4
- data/lib/accessibility/system_info.rb +230 -0
- data/lib/accessibility/translator.rb +38 -28
- data/lib/accessibility/version.rb +24 -2
- data/lib/accessibility.rb +25 -8
- data/lib/ax/application.rb +207 -77
- data/lib/ax/element.rb +62 -65
- data/lib/ax/menu.rb +5 -1
- data/lib/ax/row.rb +1 -1
- data/lib/ax/scroll_area.rb +7 -6
- data/lib/ax/systemwide.rb +38 -5
- data/lib/ax_elements/active_support_selections.rb +10 -0
- data/lib/ax_elements/mri.rb +57 -0
- data/lib/ax_elements/nsarray_compat.rb +97 -17
- data/lib/ax_elements.rb +9 -1
- data/rakelib/gem.rake +11 -11
- data/rakelib/test.rake +0 -9
- data/test/helper.rb +10 -18
- data/test/integration/accessibility/test_dsl.rb +52 -42
- data/test/integration/accessibility/test_enumerators.rb +0 -1
- data/test/integration/accessibility/test_graph.rb +1 -0
- data/test/integration/accessibility/test_qualifier.rb +2 -2
- data/test/integration/ax/test_application.rb +9 -2
- data/test/integration/ax/test_element.rb +41 -1
- data/test/sanity/accessibility/test_factory.rb +23 -56
- data/test/sanity/accessibility/{test_pp_inspector.rb → test_pretty_printer.rb} +9 -9
- data/test/sanity/accessibility/test_translator.rb +2 -5
- data/test/sanity/accessibility/test_version.rb +15 -0
- data/test/sanity/ax/test_application.rb +17 -2
- data/test/sanity/ax/test_element.rb +2 -2
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +4 -2
- data/test/sanity/test_ax_elements.rb +1 -0
- metadata +69 -39
- data/lib/accessibility/core.rb +0 -973
- data/lib/accessibility/highlighter.rb +0 -86
- data/lib/ax_elements/vendor/inflection_data.rb +0 -66
- data/lib/ax_elements/vendor/inflections.rb +0 -172
- data/lib/ax_elements/vendor/inflector.rb +0 -306
- data/lib/minitest/ax_elements.rb +0 -175
- data/lib/mouse.rb +0 -223
- data/lib/rspec/expectations/ax_elements.rb +0 -234
- data/test/integration/accessibility/test_core.rb +0 -18
- data/test/integration/minitest/test_ax_elements.rb +0 -89
- data/test/integration/rspec/expectations/test_ax_elements.rb +0 -102
- data/test/sanity/accessibility/test_core.rb +0 -561
- data/test/sanity/accessibility/test_highlighter.rb +0 -56
- data/test/sanity/minitest/test_ax_elements.rb +0 -17
- data/test/sanity/rspec/expectations/test_ax_elements.rb +0 -15
- data/test/sanity/test_mouse.rb +0 -19
data/lib/minitest/ax_elements.rb
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'ax/element'
|
2
|
-
require 'accessibility/qualifier'
|
3
|
-
require 'accessibility/dsl'
|
4
|
-
|
5
|
-
##
|
6
|
-
# AXElements assertions for MiniTest.
|
7
|
-
# [Learn more about minitest.](https://github.com/seattlerb/minitest)
|
8
|
-
class MiniTest::Assertions
|
9
|
-
|
10
|
-
##
|
11
|
-
# Test that an element has a specific child. For example, test
|
12
|
-
# that a table has a row with certain contents. You can pass any
|
13
|
-
# filters that you normally would during a search, including a block.
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
#
|
17
|
-
# assert_has_child table, :row, static_text: { value: 'Mark' }
|
18
|
-
#
|
19
|
-
# @param [AX::Element]
|
20
|
-
# @param [#to_s]
|
21
|
-
# @param [Hash]
|
22
|
-
# @return [AX::Element]
|
23
|
-
def assert_has_child parent, kind, filters = {}, &block
|
24
|
-
msg = message {
|
25
|
-
child = ax_search_id kind, filters, block
|
26
|
-
"Expected #{parent.inspect} to have #{child} as a child"
|
27
|
-
}
|
28
|
-
result = ax_check_children parent, kind, filters, block
|
29
|
-
refute result.blank?, msg
|
30
|
-
result
|
31
|
-
end
|
32
|
-
|
33
|
-
##
|
34
|
-
# Test that an element has a specifc descendent. For example, test
|
35
|
-
# that a window contains a specific label. You can pass any filters
|
36
|
-
# that you normally would during a search, including a block.
|
37
|
-
#
|
38
|
-
# @example
|
39
|
-
#
|
40
|
-
# assert_has_descendent window, :static_text, value: /Cake/
|
41
|
-
#
|
42
|
-
# @param [AX::Element]
|
43
|
-
# @param [#to_s]
|
44
|
-
# @param [Hash]
|
45
|
-
# @return [AX::Element]
|
46
|
-
def assert_has_descendent ancestor, kind, filters = {}, &block
|
47
|
-
msg = message {
|
48
|
-
descendent = ax_search_id kind, filters, block
|
49
|
-
"Expected #{ancestor.inspect} to have #{descendent} as a descendent"
|
50
|
-
}
|
51
|
-
result = ax_check_descendent ancestor, kind, filters, block
|
52
|
-
refute result.blank?, msg
|
53
|
-
result
|
54
|
-
end
|
55
|
-
alias_method :assert_has_descendant, :assert_has_descendent
|
56
|
-
|
57
|
-
##
|
58
|
-
# Test that an element will have a child/descendent soon. This method
|
59
|
-
# will block until the element is found or a timeout occurs.
|
60
|
-
#
|
61
|
-
# This is a minitest front end to using {DSL#wait_for}, so any
|
62
|
-
# parameters you would normally pass to that method will work here.
|
63
|
-
# This also means that you must include either a `parent` key or an
|
64
|
-
# `ancestor` key as one of the filters.
|
65
|
-
#
|
66
|
-
# @param [#to_s]
|
67
|
-
# @param [Hash]
|
68
|
-
# @yield An optional block to be used in the search qualifier
|
69
|
-
def assert_shortly_has kind, filters = {}, &block
|
70
|
-
# need to know if parent/ancestor now because wait_for eats some keys
|
71
|
-
(ancest = filters[:ancestor]) || (parent = filters[:parent])
|
72
|
-
msg = message {
|
73
|
-
descend = ax_search_id kind, filters, block
|
74
|
-
if ancest
|
75
|
-
"Expected #{ancest.inspect} to have descendent #{descend} before a timeout occurred"
|
76
|
-
else
|
77
|
-
"Expected #{parent.inspect} to have child #{descend} before a timeout occurred"
|
78
|
-
end
|
79
|
-
}
|
80
|
-
result = wait_for kind, filters, &block
|
81
|
-
refute result.blank?, msg
|
82
|
-
result
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# Test that an element _does not_ have a specific child. For example,
|
87
|
-
# test that a row is no longer in a table. You can pass any filters
|
88
|
-
# that you normally would during a search, including a block.
|
89
|
-
#
|
90
|
-
# @example
|
91
|
-
#
|
92
|
-
# refute_has_child table, :row, id: 'MyRow'
|
93
|
-
#
|
94
|
-
# @param [AX::Element]
|
95
|
-
# @param [#to_s]
|
96
|
-
# @param [Hash]
|
97
|
-
# @return [nil]
|
98
|
-
def refute_has_child parent, kind, filters = {}, &block
|
99
|
-
result = ax_check_children parent, kind, filters, block
|
100
|
-
msg = message {
|
101
|
-
"Expected #{parent.inspect} NOT to have #{result} as a child"
|
102
|
-
}
|
103
|
-
assert result.blank?, msg
|
104
|
-
result
|
105
|
-
end
|
106
|
-
|
107
|
-
##
|
108
|
-
# Test that an element _does not_ have a specific descendent. For
|
109
|
-
# example, test that a window does not contain a spinning progress
|
110
|
-
# indicator anymore.
|
111
|
-
#
|
112
|
-
# @example
|
113
|
-
#
|
114
|
-
# refute_has_descendent window, :busy_indicator
|
115
|
-
#
|
116
|
-
# @param [AX::Element]
|
117
|
-
# @param [#to_s]
|
118
|
-
# @param [Hash]
|
119
|
-
# @return [nil,Array()]
|
120
|
-
def refute_has_descendent ancestor, kind, filters = {}, &block
|
121
|
-
result = ax_check_descendent ancestor, kind, filters, block
|
122
|
-
msg = message {
|
123
|
-
"Expected #{ancestor.inspect} NOT to have #{result} as a descendent"
|
124
|
-
}
|
125
|
-
assert result.blank?, msg
|
126
|
-
result
|
127
|
-
end
|
128
|
-
alias_method :refute_has_descendant, :refute_has_descendent
|
129
|
-
|
130
|
-
##
|
131
|
-
# @todo Does having this assertion make sense? I've only added it
|
132
|
-
# for the time being because OCD demands it.
|
133
|
-
#
|
134
|
-
# Test that an element will NOT have a child/descendent soon. This
|
135
|
-
# method will block until the element is found or a timeout occurs.
|
136
|
-
#
|
137
|
-
# This is a minitest front end to using {DSL#wait_for}, so any
|
138
|
-
# parameters you would normally pass to that method will work here.
|
139
|
-
# This also means that you must include either a `parent` key or an
|
140
|
-
# `ancestor` key as one of the filters.
|
141
|
-
#
|
142
|
-
# @param [#to_s]
|
143
|
-
# @param [Hash]
|
144
|
-
# @yield An optional block to be used in the search qualifier
|
145
|
-
def refute_shortly_has kind, filters = {}, &block
|
146
|
-
result = wait_for kind, filters, &block
|
147
|
-
msg = message {
|
148
|
-
if ancest = filters[:ancestor]
|
149
|
-
"Expected #{ancest.inspect} NOT to have #{result.inspect} as a descendent"
|
150
|
-
else
|
151
|
-
parent = filters[:parent]
|
152
|
-
"Expected #{parent.inspect} NOT to have #{result.inspect} as a child"
|
153
|
-
end
|
154
|
-
}
|
155
|
-
assert result.blank?, msg
|
156
|
-
result
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
private
|
161
|
-
|
162
|
-
def ax_search_id kind, filters, block
|
163
|
-
Accessibility::Qualifier.new(kind, filters, &block).describe
|
164
|
-
end
|
165
|
-
|
166
|
-
def ax_check_children parent, kind, filters, block
|
167
|
-
q = Accessibility::Qualifier.new(kind, filters, &block)
|
168
|
-
parent.children.find { |x| q.qualifies? x }
|
169
|
-
end
|
170
|
-
|
171
|
-
def ax_check_descendent ancestor, kind, filters, block
|
172
|
-
ancestor.search(kind, filters, &block)
|
173
|
-
end
|
174
|
-
|
175
|
-
end
|
data/lib/mouse.rb
DELETED
@@ -1,223 +0,0 @@
|
|
1
|
-
framework 'ApplicationServices'
|
2
|
-
|
3
|
-
##
|
4
|
-
# This is a first attempt at writing a wrapper around the CoreGraphics event
|
5
|
-
# taps API provided by OS X. The module provides a simple Ruby interface to
|
6
|
-
# performing mouse interactions such as moving and clicking.
|
7
|
-
#
|
8
|
-
# [Reference](http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html).
|
9
|
-
#
|
10
|
-
# A rewrite is in the works, but in the mean time this code base still works
|
11
|
-
# despite its warts.
|
12
|
-
module Mouse
|
13
|
-
extend self
|
14
|
-
|
15
|
-
##
|
16
|
-
# Number of animation steps per second.
|
17
|
-
#
|
18
|
-
# @return [Number]
|
19
|
-
FPS = 120
|
20
|
-
|
21
|
-
##
|
22
|
-
# @note We keep the number as a rational to try and avoid rounding
|
23
|
-
# error introduced by the floats, especially MacRuby floats.
|
24
|
-
#
|
25
|
-
# Smallest unit of time allowed for an animation step.
|
26
|
-
#
|
27
|
-
# @return [Number]
|
28
|
-
QUANTUM = Rational(1, FPS)
|
29
|
-
|
30
|
-
##
|
31
|
-
# Available constants for the type of units to use when scrolling.
|
32
|
-
#
|
33
|
-
# @return [Hash{Symbol=>Fixnum}]
|
34
|
-
UNIT = {
|
35
|
-
line: KCGScrollEventUnitLine,
|
36
|
-
pixel: KCGScrollEventUnitPixel
|
37
|
-
}
|
38
|
-
|
39
|
-
##
|
40
|
-
# The coordinates of the mouse using the flipped coordinate system
|
41
|
-
# (origin in top left).
|
42
|
-
#
|
43
|
-
# @return [CGPoint]
|
44
|
-
def current_position
|
45
|
-
CGEventGetLocation(CGEventCreate(nil))
|
46
|
-
end
|
47
|
-
|
48
|
-
##
|
49
|
-
# Move the mouse from the current position to the given point.
|
50
|
-
#
|
51
|
-
# @param [CGPoint]
|
52
|
-
# @param [Float] duration animation duration, in seconds
|
53
|
-
def move_to point, duration = 0.2
|
54
|
-
animate KCGEventMouseMoved, KCGMouseButtonLeft, current_position, point, duration
|
55
|
-
end
|
56
|
-
|
57
|
-
##
|
58
|
-
# Click and drag from the current position to the given point.
|
59
|
-
#
|
60
|
-
# @param [CGPoint]
|
61
|
-
# @param [Float] duration animation duration, in seconds
|
62
|
-
def drag_to point, duration = 0.2
|
63
|
-
post new_event(KCGEventLeftMouseDown, current_position, KCGMouseButtonLeft)
|
64
|
-
|
65
|
-
animate KCGEventLeftMouseDragged, KCGMouseButtonLeft, current_position, point, duration
|
66
|
-
|
67
|
-
post new_event(KCGEventLeftMouseUp, current_position, KCGMouseButtonLeft)
|
68
|
-
end
|
69
|
-
|
70
|
-
##
|
71
|
-
# @todo Need to double check to see if I introduce any inaccuracies.
|
72
|
-
#
|
73
|
-
# Scroll at the current position the given amount of units.
|
74
|
-
#
|
75
|
-
# Scrolling too much or too little in a period of time will cause the
|
76
|
-
# animation to look weird, possibly causing the app to mess things up.
|
77
|
-
#
|
78
|
-
# @param [Fixnum] amount number of units to scroll; positive to scroll
|
79
|
-
# up or negative to scroll down
|
80
|
-
# @param [Float] duration animation duration, in seconds
|
81
|
-
# @param [Symbol] units `:line` scrolls by line, `:pixel` scrolls by pixel
|
82
|
-
def scroll amount, duration = 0.2, units = :line
|
83
|
-
units = UNIT[units] || raise(ArgumentError, "#{units} is not a valid unit")
|
84
|
-
steps = (FPS * duration).round
|
85
|
-
current = 0.0
|
86
|
-
steps.times do |step|
|
87
|
-
done = (step+1).to_f / steps
|
88
|
-
scroll = ((done - current)*amount).floor
|
89
|
-
post new_scroll_event(units, 1, scroll)
|
90
|
-
sleep QUANTUM
|
91
|
-
current += scroll.to_f / amount
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
##
|
96
|
-
# Perform a down click. You should follow this up with a call to
|
97
|
-
# {#click_up} to finish the click.
|
98
|
-
#
|
99
|
-
# @param [CGPoint]
|
100
|
-
def click_down point = current_position, duration = 12
|
101
|
-
event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
|
102
|
-
post event
|
103
|
-
sleep QUANTUM*duration
|
104
|
-
end
|
105
|
-
|
106
|
-
##
|
107
|
-
# Perform an up click. This should only be called after a call to
|
108
|
-
# {#click_down} to finish the click event.
|
109
|
-
#
|
110
|
-
# @param [CGPoint]
|
111
|
-
def click_up point = current_position
|
112
|
-
event = new_event KCGEventLeftMouseUp, point, KCGMouseButtonLeft
|
113
|
-
post event
|
114
|
-
end
|
115
|
-
|
116
|
-
##
|
117
|
-
# Standard secondary click. Default position is the current position.
|
118
|
-
#
|
119
|
-
# @param [CGPoint]
|
120
|
-
def secondary_click point = current_position, duration = 12
|
121
|
-
event = new_event KCGEventRightMouseDown, point, KCGMouseButtonRight
|
122
|
-
post event
|
123
|
-
sleep QUANTUM*duration
|
124
|
-
set_type event, KCGEventRightMouseUp
|
125
|
-
post event
|
126
|
-
end
|
127
|
-
alias_method :right_click, :secondary_click
|
128
|
-
|
129
|
-
##
|
130
|
-
# A standard double click. Defaults to clicking at the current position.
|
131
|
-
#
|
132
|
-
# @param [CGPoint]
|
133
|
-
def double_click point = current_position
|
134
|
-
event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
|
135
|
-
post event
|
136
|
-
set_type event, KCGEventLeftMouseUp
|
137
|
-
post event
|
138
|
-
|
139
|
-
CGEventSetIntegerValueField(event, KCGMouseEventClickState, 2)
|
140
|
-
set_type event, KCGEventLeftMouseDown
|
141
|
-
post event
|
142
|
-
set_type event, KCGEventLeftMouseUp
|
143
|
-
post event
|
144
|
-
end
|
145
|
-
|
146
|
-
##
|
147
|
-
# Click with an arbitrary mouse button, using numbers to represent
|
148
|
-
# the mouse button. At the time of writing, the documented values are:
|
149
|
-
#
|
150
|
-
# - KCGMouseButtonLeft = 0
|
151
|
-
# - KCGMouseButtonRight = 1
|
152
|
-
# - KCGMouseButtonCenter = 2
|
153
|
-
#
|
154
|
-
# And the rest are not documented! Though they should be easy enough
|
155
|
-
# to figure out. See the `CGMouseButton` enum in the reference
|
156
|
-
# documentation for the most up to date list.
|
157
|
-
#
|
158
|
-
# @param [CGPoint]
|
159
|
-
# @param [Number]
|
160
|
-
def arbitrary_click point = current_position, button = KCGMouseButtonCenter, duration = 12
|
161
|
-
event = new_event KCGEventOtherMouseDown, point, button
|
162
|
-
post event
|
163
|
-
sleep QUANTUM*duration
|
164
|
-
set_type event, KCGEventOtherMouseUp
|
165
|
-
post event
|
166
|
-
end
|
167
|
-
alias_method :other_click, :arbitrary_click
|
168
|
-
|
169
|
-
|
170
|
-
private
|
171
|
-
|
172
|
-
##
|
173
|
-
# Executes a mouse movement animation. It can be a simple cursor
|
174
|
-
# move or a drag depending on what is passed to `type`.
|
175
|
-
def animate type, button, from, to, duration
|
176
|
-
current = current_position
|
177
|
-
xstep = (to.x - current.x) / (FPS * duration)
|
178
|
-
ystep = (to.y - current.y) / (FPS * duration)
|
179
|
-
start = NSDate.date
|
180
|
-
|
181
|
-
until close_enough?(current, to)
|
182
|
-
remaining = to.x - current.x
|
183
|
-
current.x += xstep.abs > remaining.abs ? remaining : xstep
|
184
|
-
|
185
|
-
remaining = to.y - current.y
|
186
|
-
current.y += ystep.abs > remaining.abs ? remaining : ystep
|
187
|
-
|
188
|
-
post new_event(type, current, button)
|
189
|
-
|
190
|
-
sleep QUANTUM
|
191
|
-
break if NSDate.date.timeIntervalSinceDate(start) > 5.0
|
192
|
-
current = current_position
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def close_enough? current, target
|
197
|
-
x = current.x - target.x
|
198
|
-
y = current.y - target.y
|
199
|
-
delta = Math.sqrt((x**2) + (y**2))
|
200
|
-
delta <= 1.0
|
201
|
-
end
|
202
|
-
|
203
|
-
def new_event event, position, button
|
204
|
-
CGEventCreateMouseEvent(nil, event, position, button)
|
205
|
-
end
|
206
|
-
|
207
|
-
# @param [Fixnum] wheel which scroll wheel to use (value between 1-3)
|
208
|
-
def new_scroll_event units, wheel, amount
|
209
|
-
CGEventCreateScrollWheelEvent(nil, units, wheel, amount)
|
210
|
-
end
|
211
|
-
|
212
|
-
def post event
|
213
|
-
CGEventPost(KCGHIDEventTap, event)
|
214
|
-
end
|
215
|
-
|
216
|
-
##
|
217
|
-
# Change the event type for an instance of an event. This is how you would
|
218
|
-
# reuse a specific event. In most cases, reusing events is a necessity.
|
219
|
-
def set_type event, state
|
220
|
-
CGEventSetType(event, state)
|
221
|
-
end
|
222
|
-
|
223
|
-
end
|
@@ -1,234 +0,0 @@
|
|
1
|
-
require 'accessibility/dsl'
|
2
|
-
require 'accessibility/qualifier'
|
3
|
-
require 'ax/element'
|
4
|
-
|
5
|
-
module Accessibility
|
6
|
-
|
7
|
-
##
|
8
|
-
# @abstract
|
9
|
-
#
|
10
|
-
# Base class for RSpec matchers used with AXElements.
|
11
|
-
class AbstractMatcher
|
12
|
-
|
13
|
-
# @return [#to_s]
|
14
|
-
attr_reader :kind
|
15
|
-
|
16
|
-
# @return [Hash{Symbol=>Object}]
|
17
|
-
attr_reader :filters
|
18
|
-
|
19
|
-
# @return [Proc]
|
20
|
-
attr_reader :block
|
21
|
-
|
22
|
-
# @param [#to_s]
|
23
|
-
# @param [Hash]
|
24
|
-
# @yield
|
25
|
-
def initialize kind, filters, &block
|
26
|
-
@kind, @filters, @block = kind, filters, block
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param [AX::Element]
|
30
|
-
def does_not_match? element
|
31
|
-
!matches?(element)
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
# @return [Accessibility::Qualifier]
|
38
|
-
def qualifier
|
39
|
-
@qualifier ||= Accessibility::Qualifier.new(kind, filters, &block)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
##
|
44
|
-
# Custom matcher for RSpec to check if an element has the specified
|
45
|
-
# child element.
|
46
|
-
class HasChildMatcher < AbstractMatcher
|
47
|
-
# @param [AX::Element]
|
48
|
-
def matches? parent
|
49
|
-
@parent = parent
|
50
|
-
@result = parent.children.find { |x| qualifier.qualifies? x }
|
51
|
-
!@result.blank?
|
52
|
-
end
|
53
|
-
|
54
|
-
# @return [String]
|
55
|
-
def failure_message_for_should
|
56
|
-
"Expected #@parent to have child #{qualifier.describe}"
|
57
|
-
end
|
58
|
-
|
59
|
-
# @return [String]
|
60
|
-
def failure_message_for_should_not
|
61
|
-
"Expected #@parent to NOT have child #@result"
|
62
|
-
end
|
63
|
-
|
64
|
-
# @return [String]
|
65
|
-
def description
|
66
|
-
"should have a child that matches #{qualifier.describe}"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
##
|
71
|
-
# Custom matcher for RSpec to check if an element has the specified
|
72
|
-
# descendent element.
|
73
|
-
class HasDescendentMatcher < AbstractMatcher
|
74
|
-
# @param [AX::Element]
|
75
|
-
def matches? ancestor
|
76
|
-
@ancestor = ancestor
|
77
|
-
@result = ancestor.search(kind, filters, &block)
|
78
|
-
!@result.blank?
|
79
|
-
end
|
80
|
-
|
81
|
-
# @return [String]
|
82
|
-
def failure_message_for_should
|
83
|
-
"Expected #@ancestor to have descendent #{qualifier.describe}"
|
84
|
-
end
|
85
|
-
|
86
|
-
# @return [String]
|
87
|
-
def failure_message_for_should_not
|
88
|
-
"Expected #@ancestor to NOT have descendent #@result"
|
89
|
-
end
|
90
|
-
|
91
|
-
# @return [String]
|
92
|
-
def description
|
93
|
-
"should have a descendent matching #{qualifier.describe}"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
##
|
98
|
-
# Custom matcher for RSpec to check if an element has the specified
|
99
|
-
# child element within a grace period. Used for testing things
|
100
|
-
# after an asynchronous action is performed.
|
101
|
-
class HasChildShortlyMatcher < AbstractMatcher
|
102
|
-
include DSL
|
103
|
-
|
104
|
-
# @param [AX::Element]
|
105
|
-
def matches? parent
|
106
|
-
@filters[:parent] = @parent = parent
|
107
|
-
@result = wait_for kind, filters, &block
|
108
|
-
!@result.blank?
|
109
|
-
end
|
110
|
-
|
111
|
-
# @return [String]
|
112
|
-
def failure_message_for_should
|
113
|
-
"Expected #@parent to have child #{qualifier.describe} before a timeout occurred"
|
114
|
-
end
|
115
|
-
|
116
|
-
# @return [String]
|
117
|
-
def failure_message_for_should_not
|
118
|
-
"Expected #@parent to NOT have child #@result before a timeout occurred"
|
119
|
-
end
|
120
|
-
|
121
|
-
# @return [String]
|
122
|
-
def description
|
123
|
-
"should have a child that matches #{qualifier.describe} before a timeout occurs"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
##
|
128
|
-
# Custom matcher for RSpec to check if an element has the specified
|
129
|
-
# descendent element within a grace period. Used for testing things
|
130
|
-
# after an asynchronous action is performed.
|
131
|
-
class HasDescendentShortlyMatcher < AbstractMatcher
|
132
|
-
include DSL
|
133
|
-
|
134
|
-
# @param [AX::Element]
|
135
|
-
def matches? ancestor
|
136
|
-
@filters[:ancestor] = @ancestor = ancestor
|
137
|
-
@result = wait_for kind, filters, &block
|
138
|
-
!@result.blank?
|
139
|
-
end
|
140
|
-
|
141
|
-
# @return [String]
|
142
|
-
def failure_message_for_should
|
143
|
-
"Expected #@ancestor to have descendent #{qualifier.describe} before a timeout occurred"
|
144
|
-
end
|
145
|
-
|
146
|
-
# @return [String]
|
147
|
-
def failure_message_for_should_not
|
148
|
-
"Expected #@ancestor to NOT have descendent #@result before a timeout occurred"
|
149
|
-
end
|
150
|
-
|
151
|
-
# @return [String]
|
152
|
-
def description
|
153
|
-
"should have a descendent matching #{qualifier.describe} before a timeout occurs"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
##
|
160
|
-
# Assert that the receiving element has the specified child element. You
|
161
|
-
# can use any filters you would normally use in a search, including
|
162
|
-
# a block.
|
163
|
-
#
|
164
|
-
# @example
|
165
|
-
#
|
166
|
-
# window.toolbar.should have_child(:search_field)
|
167
|
-
# table.should have_child(:row, static_text: { value: /42/ })
|
168
|
-
#
|
169
|
-
# search_field.should_not have_child(:busy_indicator)
|
170
|
-
#
|
171
|
-
# @param [#to_s]
|
172
|
-
# @param [Hash]
|
173
|
-
# @yield An optional block to be used as part of the search qualifier
|
174
|
-
def have_child kind, filters = {}, &block
|
175
|
-
Accessibility::HasChildMatcher.new kind, filters, &block
|
176
|
-
end
|
177
|
-
|
178
|
-
##
|
179
|
-
# Assert that the given element has the specified descendent. You can
|
180
|
-
# pass any parameters you normally would use during a search,
|
181
|
-
# including a block.
|
182
|
-
#
|
183
|
-
# @example
|
184
|
-
#
|
185
|
-
# app.main_window.should have_descendent(:button, title: 'Press Me')
|
186
|
-
#
|
187
|
-
# row.should_not have_descendent(:check_box)
|
188
|
-
#
|
189
|
-
# @param [#to_s]
|
190
|
-
# @param [Hash]
|
191
|
-
# @yield An optional block to be used as part of the search qualifier
|
192
|
-
def have_descendent kind, filters = {}, &block
|
193
|
-
Accessibility::HasDescendentMatcher.new kind, filters, &block
|
194
|
-
end
|
195
|
-
alias :have_descendant :have_descendent
|
196
|
-
|
197
|
-
##
|
198
|
-
# Assert that the given element has the specified child soon. This
|
199
|
-
# method will block until the child is found or a timeout occurs. You
|
200
|
-
# can pass any parameters you normally would use during a search,
|
201
|
-
# including a block.
|
202
|
-
#
|
203
|
-
# @example
|
204
|
-
#
|
205
|
-
# app.main_window.should shortly_have_child(:row, static_text: { value: 'Cake' })
|
206
|
-
#
|
207
|
-
# row.should_not shortly_have_child(:check_box)
|
208
|
-
#
|
209
|
-
# @param [#to_s]
|
210
|
-
# @param [Hash]
|
211
|
-
# @yield An optional block to be used as part of the search qualifier
|
212
|
-
def shortly_have_child kind, filters = {}, &block
|
213
|
-
Accessibility::HasChildShortlyMatcher.new(kind, filters, &block)
|
214
|
-
end
|
215
|
-
|
216
|
-
##
|
217
|
-
# Assert that the given element has the specified descendent soon. This
|
218
|
-
# method will block until the descendent is found or a timeout occurs.
|
219
|
-
# You can pass any parameters you normally would use during a search,
|
220
|
-
# including a block.
|
221
|
-
#
|
222
|
-
# @example
|
223
|
-
#
|
224
|
-
# app.main_window.should shortly_have_child(:row, static_text: { value: 'Cake' })
|
225
|
-
#
|
226
|
-
# row.should_not shortly_have_child(:check_box)
|
227
|
-
#
|
228
|
-
# @param [#to_s]
|
229
|
-
# @param [Hash]
|
230
|
-
# @yield An optional block to be used as part of the search qualifier
|
231
|
-
def shortly_have_descendent kind, filters = {}, &block
|
232
|
-
Accessibility::HasDescendentShortlyMatcher.new kind, filters, &block
|
233
|
-
end
|
234
|
-
alias :shortly_have_descendant :shortly_have_descendent
|
@@ -1,18 +0,0 @@
|
|
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
|