AXElements 0.8.1 → 0.9.0
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 +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
|