AXElements 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -64,8 +64,10 @@ You need to have the OS X command line tools installed in order to
64
64
  build and install AXElements, but you will also need Xcode in order to
65
65
  run the test suite (sorry). Go ahead and install the tools now if you
66
66
  haven't done that yet, I'll wait. Once you have the developer tools,
67
- you should install MacRuby, the latest nightly build is required. If you
68
- are on Snow Leopard, you will also need to install the
67
+ you should install [MacRuby](http://macruby.org/), version 0.12 or
68
+ later is required and downloads can be found at
69
+ https://github.com/MacRuby/MacRuby/downloads.
70
+ If you are on Snow Leopard, you will also need to install the
69
71
  [Bridge Support Preview](http://www.macruby.org/blog/2010/10/08/bridgesupport-preview.html).
70
72
 
71
73
  Then you can install AXElements. You can install AXElements via
@@ -123,12 +125,9 @@ as the technical underpinnings of AXElements.
123
125
 
124
126
  ## Development
125
127
 
126
- Development of a stable release of AXElements is under way! The main
127
- focus is an overall refactoring to create a more robust core, end user
128
- features will become more consistent, and performance will
129
- increase. Documentation will be overhauled and more examples will be
130
- added. It will be magical, so we're code naming the next version
131
- "Clefairy".
128
+ AXElements has reached a point where the main focus is now performance,
129
+ features, and documentation. It will be magical, so we're code naming
130
+ the next version "Clefable".
132
131
 
133
132
  ![The Moon](https://github.com/Marketcircle/AXElements/raw/gh-pages/images/next_version.png)
134
133
 
@@ -4,17 +4,21 @@ require 'mouse'
4
4
  require 'ax/element'
5
5
  require 'ax/application'
6
6
  require 'ax/systemwide'
7
+ require 'ax/scroll_area'
8
+ require 'ax/menu'
7
9
  require 'accessibility'
8
10
  require 'accessibility/enumerators'
9
11
 
10
12
  ##
11
13
  # DSL methods for AXElements.
12
14
  #
13
- # The idea here is to pull actions out from an object and put them
14
- # in front of object to give AXElements more of a DSL feel to make
15
- # communicating test steps more clear. See the
16
- # [Acting tutorial](http://github.com/Marketcircle/AXElements/wiki/Acting)
17
- # for a more in depth tutorial on using this module.
15
+ # The DSL for AXElements is designed to pull actions out from an object
16
+ # and put them in front of object to make communicating test steps seem
17
+ # more like human instructions.
18
+ #
19
+ # You can read more about the DSL in the
20
+ # [Acting](http://github.com/Marketcircle/AXElements/wiki/Acting)
21
+ # section of the AXElements wiki.
18
22
  module Accessibility::DSL
19
23
 
20
24
 
@@ -156,52 +160,6 @@ module Accessibility::DSL
156
160
  app.perform :terminate
157
161
  end
158
162
 
159
- ##
160
- # Find the application with the given bundle identifier. If the
161
- # application is not already running, it will be launched.
162
- #
163
- # @example
164
- #
165
- # app_with_bundle_identifier 'com.apple.finder'
166
- # launch 'com.apple.mail'
167
- #
168
- # @param [String]
169
- # @return [AX::Application,nil]
170
- def app_with_bundle_identifier id
171
- Accessibility.application_with_bundle_identifier id
172
- end
173
- alias_method :app_with_bundle_id, :app_with_bundle_identifier
174
- alias_method :launch, :app_with_bundle_identifier
175
-
176
- ##
177
- # Find the application with the given name. If the application
178
- # is not already running, it will NOT be launched and this
179
- # method will return `nil`.
180
- #
181
- # @example
182
- #
183
- # app_with_name 'Finder'
184
- #
185
- # @param [String]
186
- # @return [AX::Application,nil]
187
- def app_with_name name
188
- AX::Application.new name
189
- end
190
-
191
- ##
192
- # Find the application with the given process identifier. An
193
- # invalid PID will cause an exception to be raised.
194
- #
195
- # @example
196
- #
197
- # app_with_pid 35843
198
- #
199
- # @param [Fixnum]
200
- # @return [AX::Application]
201
- def app_with_pid pid
202
- AX::Application.new pid
203
- end
204
-
205
163
  ##
206
164
  # Focus an element on the screen, but only if it can be directly
207
165
  # focused. It is safe to pass any element into this method as nothing
@@ -292,6 +250,64 @@ module Accessibility::DSL
292
250
  app.select_menu_item *path
293
251
  end
294
252
 
253
+ ##
254
+ # Show the "About" window for an app. Returns the window that is
255
+ # opened.
256
+ #
257
+ # @param [AX::Application]
258
+ # @return [AX::Window]
259
+ def show_about_window_for app
260
+ app.show_about_window
261
+ end
262
+
263
+ ##
264
+ # @note This method assumes that the app has setup the standard
265
+ # CMD+, hotkey to open the pref window
266
+ #
267
+ # Try to open the preferences for an app. Returns the window that
268
+ # is opened.
269
+ #
270
+ # @param [AX::Application]
271
+ # @return [AX::Window]
272
+ def show_preferences_window_for app
273
+ app.show_preferences_window
274
+ end
275
+
276
+ ##
277
+ # Scroll through a scroll area until the given element is visible.
278
+ #
279
+ # If you need to scroll an unknown amount of units through a table
280
+ # or another type of object contained in as scroll area, you can
281
+ # just pass the element that you are trying to get to and this method
282
+ # will scroll to it for you.
283
+ #
284
+ # @example
285
+ #
286
+ # scroll_to table.rows.last
287
+ #
288
+ # @param [AX::Element]
289
+ # @return [void]
290
+ def scroll_to element
291
+ element.ancestor(:scroll_area).scroll_to element
292
+ end
293
+ alias_method :scroll_to_visible, :scroll_to
294
+
295
+ ##
296
+ # Scroll a menu to an item in the menu and then move the mouse
297
+ # pointer to that item.
298
+ #
299
+ # @example
300
+ #
301
+ # click window.pop_up do
302
+ # scroll_menu_to pop_up.menu.item(title: "Expensive Cake")
303
+ # end
304
+ #
305
+ # @param [AX:]
306
+ # @return [void]
307
+ def scroll_menu_to element
308
+ menu = element.ancestor(:menu).scroll_to element
309
+ end
310
+
295
311
 
296
312
  # @group Polling
297
313
 
@@ -521,17 +537,18 @@ module Accessibility::DSL
521
537
  #
522
538
  # click
523
539
  # click window.close_button
540
+ # click do
541
+ # move_mouse_to [0,0]
542
+ # end
524
543
  #
544
+ # @yield Optionally take a block that is executed between click down
545
+ # and click up events.
525
546
  # @param [#to_point]
526
547
  def click obj = nil, wait = 0.2
527
548
  move_mouse_to obj, wait: 0 if obj
528
- if block_given?
529
- Mouse.click_down
530
- yield
531
- Mouse.click_up
532
- else
533
- Mouse.click
534
- end
549
+ Mouse.click_down
550
+ yield if block_given?
551
+ Mouse.click_up
535
552
  sleep wait
536
553
  end
537
554
 
@@ -603,13 +620,13 @@ module Accessibility::DSL
603
620
  #
604
621
  # @example
605
622
  #
606
- # puts subtree_for app
623
+ # puts subtree app
607
624
  #
608
625
  # @return [String]
609
- def subtree_for element
626
+ def subtree element
610
627
  element.inspect_subtree
611
628
  end
612
- alias_method :subtree, :subtree_for
629
+ alias_method :subtree_for, :subtree
613
630
 
614
631
  ##
615
632
  # @note You will need to have GraphViz command line tools installed
@@ -627,16 +644,11 @@ module Accessibility::DSL
627
644
  def graph element
628
645
  require 'accessibility/graph'
629
646
  graph = Accessibility::Graph.new(element)
630
- graph.build!
631
-
632
- require 'tempfile'
633
- file = Tempfile.new('graph')
634
- File.open(file.path, 'w') do |fd| fd.write graph.to_dot end
635
- `dot -Tpng #{file.path} > #{file.path}.png`
636
- `open #{file.path}.png`
637
-
638
- file.path
647
+ path = graph.generate_png!
648
+ `open #{path}`
649
+ path
639
650
  end
651
+ alias_method :graph_for, :graph
640
652
 
641
653
  ##
642
654
  # Take a screen shot and save it to disk. If a file name and path are
@@ -659,6 +671,9 @@ module Accessibility::DSL
659
671
  # @param [#to_s]
660
672
  # @return [String] path to the screenshot
661
673
  def screenshot name = "AXElements-ScreenShot", dir = '~/Desktop'
674
+ # @todo this could move to its own class, much like
675
+ # {Accessibility::Highlighter} and expose more options
676
+ # while retaining good defaults
662
677
  dir = File.expand_path dir.to_s
663
678
  file = "#{dir}/#{name}-#{Time.now.strftime '%Y%m%d%H%M%S'}.png"
664
679
 
@@ -675,10 +690,56 @@ module Accessibility::DSL
675
690
  file
676
691
  end
677
692
  alias_method :capture_screen, :screenshot
678
- alias_method :shoot_screen, :screenshot
679
693
 
680
694
 
681
- # @group Macros
695
+ # @endgroup
696
+
697
+
698
+ ##
699
+ # Find the application with the given bundle identifier. If the
700
+ # application is not already running, it will be launched.
701
+ #
702
+ # @example
703
+ #
704
+ # app_with_bundle_identifier 'com.apple.finder'
705
+ # launch 'com.apple.mail'
706
+ #
707
+ # @param [String]
708
+ # @return [AX::Application,nil]
709
+ def app_with_bundle_identifier id
710
+ Accessibility.application_with_bundle_identifier id
711
+ end
712
+ alias_method :app_with_bundle_id, :app_with_bundle_identifier
713
+ alias_method :launch, :app_with_bundle_identifier
714
+
715
+ ##
716
+ # Find the application with the given name. If the application
717
+ # is not already running, it will NOT be launched and this
718
+ # method will return `nil`.
719
+ #
720
+ # @example
721
+ #
722
+ # app_with_name 'Finder'
723
+ #
724
+ # @param [String]
725
+ # @return [AX::Application,nil]
726
+ def app_with_name name
727
+ AX::Application.new name
728
+ end
729
+
730
+ ##
731
+ # Find the application with the given process identifier. An
732
+ # invalid PID will cause an exception to be raised.
733
+ #
734
+ # @example
735
+ #
736
+ # app_with_pid 35843
737
+ #
738
+ # @param [Fixnum]
739
+ # @return [AX::Application]
740
+ def app_with_pid pid
741
+ AX::Application.new pid
742
+ end
682
743
 
683
744
  ##
684
745
  # Convenience for `AX::SystemWide.new`.
@@ -722,94 +783,6 @@ module Accessibility::DSL
722
783
  base = opts[:for] || system_wide
723
784
  base.element_at point
724
785
  end
725
-
726
- ##
727
- # Show the "About" window for an app. Returns the window that is
728
- # opened.
729
- #
730
- # @param [AX::Application]
731
- # @return [AX::Window]
732
- def show_about_window_for app
733
- app.show_about_window
734
- end
735
-
736
- ##
737
- # @note This method assumes that the app has setup the standard
738
- # CMD+, hotkey to open the pref window
739
- #
740
- # Try to open the preferences for an app. Returns the window that
741
- # is opened.
742
- #
743
- # @param [AX::Application]
744
- # @return [AX::Window]
745
- def show_preferences_window_for app
746
- app.show_preferences_window
747
- end
748
-
749
- ##
750
- # Scroll though a scroll area until the given element is visible.
751
- #
752
- # If you need to scroll an unknown ammount of units through a scroll area
753
- # you can just pass the element that you need visible and this method
754
- # will scroll to it for you.
755
- #
756
- # @example
757
- #
758
- # scroll_to table.rows.last
759
- #
760
- # @param [AX::Element]
761
- # @return [void]
762
- def scroll_to element
763
- scroll_area = element.ancestor :scroll_area
764
-
765
- return if NSContainsRect(scroll_area.bounds, element.bounds)
766
- move_mouse_to scroll_area
767
- # calculate direction to scroll
768
- direction = element.position.y > scroll_area.position.y ? -5 : 5
769
- until NSContainsRect(scroll_area.bounds, element.bounds)
770
- Mouse.scroll direction
771
- end
772
- sleep 0.1
773
- end
774
- alias_method :scroll_to_visible, :scroll_to
775
-
776
- ##
777
- # Scroll a menu to an item in the menu and then move the mouse
778
- # pointer to that item.
779
- #
780
- # @example
781
- #
782
- # scroll_menu_to menu.element(title: "Expensive Cake")
783
- #
784
- # @param [AX:]
785
- # @return [void]
786
- def scroll_menu_to element
787
- menu = element.ancestor :menu
788
- move_mouse_to menu
789
-
790
- row_height = menu.menu_item.size.height
791
- point = menu.position
792
- point.x += menu.size.width / 2
793
- point.y += if element.position.y > menu.position.y
794
- menu.size.height - (row_height * 0.1)
795
- else
796
- row_height * 0.1
797
- end
798
-
799
- until NSContainsRect(menu.bounds, element.bounds)
800
- move_mouse_to point
801
- end
802
-
803
- start = Time.now
804
- until Time.now - start > 5
805
- # This can happen sometimes with the little arrow bars
806
- # in menus covering up the menu item.
807
- if element_under_mouse != element
808
- move_mouse_to element
809
- else
810
- break
811
- end
812
- end
813
- end
786
+ alias_method :element_at, :element_at_point
814
787
 
815
788
  end
@@ -1,3 +1,5 @@
1
+ require 'accessibility/qualifier'
2
+
1
3
  ##
2
4
  # Error raised when an implicit search fails to return a result.
3
5
  class Accessibility::SearchFailure < NoMethodError
@@ -5,13 +7,13 @@ class Accessibility::SearchFailure < NoMethodError
5
7
  # @param [AX::Element]
6
8
  # @param [#to_s]
7
9
  # @param [Hash{Symbol=>Object}]
8
- def initialize searcher, searchee, filters
10
+ def initialize searcher, searchee, filters, &block
9
11
  filters = {} unless filters.kind_of? Hash
10
- msg = "Could not find `#{pp_searchee searchee, filters}` "
12
+ msg = "Could not find `#{pp_searchee searchee, filters, &block}` "
11
13
  msg << "as a child of #{searcher.class}\n"
12
14
  msg << "Element Path:\n\t" << path_to(searcher)
13
15
  # @todo Consider turning this on by default
14
- msg << "\nSubtree:\n\n" << subtree_for(searcher) if Accessibility.debug?
16
+ msg << "\nSubtree:\n\n" << searcher.inspect_subtree if Accessibility.debug?
15
17
  super msg
16
18
  end
17
19
 
@@ -19,8 +21,8 @@ class Accessibility::SearchFailure < NoMethodError
19
21
  private
20
22
 
21
23
  # Nice string representation of what was being searched for
22
- def pp_searchee searchee, filters
23
- Accessibility::Qualifier.new(searchee, filters).describe
24
+ def pp_searchee searchee, filters, &block
25
+ Accessibility::Qualifier.new(searchee, filters, &block).describe
24
26
  end
25
27
 
26
28
  # Nice string representation of element's path from the application root
@@ -1,3 +1,5 @@
1
+ require 'tempfile'
2
+
1
3
  ##
2
4
  # DOT graph generator for AXElements. It can generate the digraph code
3
5
  # for a UI subtree. That code can then be given to GraphViz to generate
@@ -178,6 +180,7 @@ class Accessibility::Graph
178
180
  # should use #size_of(:children), but that doesn't in all cases
179
181
  @edge_queue.concat Array.new(element.children.size, node)
180
182
  end
183
+ @built = true
181
184
  end
182
185
 
183
186
  ##
@@ -193,4 +196,17 @@ class Accessibility::Graph
193
196
  graph << "\n}\n"
194
197
  end
195
198
 
199
+ ##
200
+ # Generate the PNG file for the graph and save it to a temporary
201
+ # file. The path to the temporary file will be returned.
202
+ #
203
+ # @return [String] path to the saved PNG file
204
+ def generate_png!
205
+ build! unless @built
206
+ file = Tempfile.new 'ax_elements_graph'
207
+ file.write self.to_dot
208
+ `dot -Tpng #{file.path} > #{file.path}.png`
209
+ "#{file.path}.png"
210
+ end
211
+
196
212
  end
@@ -2,8 +2,8 @@
2
2
  # The main AXElements namespace.
3
3
  module Accessibility
4
4
  # @return [String]
5
- VERSION = '0.8.0'
5
+ VERSION = '0.8.1'
6
6
 
7
7
  # @return [String]
8
- CODE_NAME = 'Clefairy'
8
+ CODE_NAME = 'Clefable'
9
9
  end
data/lib/accessibility.rb CHANGED
@@ -51,7 +51,7 @@ class << Accessibility
51
51
  sleep 1
52
52
  end
53
53
  else
54
- raise ArgumentError "Could not launch app matching bundle id `#{bundle}'"
54
+ raise ArgumentError, "Could not launch app matching bundle id `#{bundle}'"
55
55
  end
56
56
  nil
57
57
  end
@@ -197,21 +197,17 @@ class AX::Application < AX::Element
197
197
  #
198
198
  # @return [AX::MenuItem]
199
199
  def navigate_menu *path
200
- # @todo CLEAN UP
201
200
  perform :unhide # can't navigate menus unless the app is up front
202
- current = attribute(:menu_bar).search(:menu_bar_item, title: path.shift)
201
+ bar_item = item = self.menu_bar.menu_bar_item(title: path.shift)
203
202
  path.each do |part|
204
- current.perform :press
205
- next_item = current.search(:menu_item, title: part)
206
- if next_item.blank?
207
- failure = Accessibility::SearchFailure.new(current, :menu_item, title: part)
208
- current.perform :cancel # close menu
209
- raise failure
210
- else
211
- current = next_item
212
- end
203
+ item.perform :press
204
+ next_item = item.menu_item(title: part)
205
+ item = next_item
213
206
  end
214
- current
207
+ item
208
+ ensure
209
+ # got to the end
210
+ bar_item.perform :cancel unless item.title == path.last
215
211
  end
216
212
 
217
213
  ##
data/lib/ax/element.rb CHANGED
@@ -340,7 +340,7 @@ class AX::Element
340
340
 
341
341
  elsif @ref.attributes.include? KAXChildrenAttribute
342
342
  if (result = search(method, *args, &block)).blank?
343
- raise Accessibility::SearchFailure.new(self, method, args.first)
343
+ raise Accessibility::SearchFailure.new(self, method, args.first, &block)
344
344
  else
345
345
  return result
346
346
  end
data/lib/ax/menu.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'ax/element'
2
+ require 'mouse'
3
+
4
+ ##
5
+ # UI element representing a menu. Not much to it...
6
+ class AX::Menu < AX::Element
7
+
8
+ ##
9
+ # Scroll the menu until the given element, which must be in the menu
10
+ # is visible in the bounds of the menu. This method will also move the
11
+ # mouse pointer to the given element.
12
+ #
13
+ # If you need to scroll an unknown number of units through a menu,
14
+ # you can just pass the element that you need visible and this method
15
+ # will scroll to it for you.
16
+ #
17
+ # @example
18
+ #
19
+ # click window.pop_up do
20
+ # menu = pop_up.menu
21
+ # menu.scroll_to menu.item(title: "Expensive Cake")
22
+ # end
23
+ #
24
+ # @param [AX::Element]
25
+ # @return [void]
26
+ def scroll_to element
27
+ Mouse.move_to self.to_point
28
+
29
+ # calculate which scroll arrow to move to
30
+ fudge_factor = self.item.size.height * 0.1
31
+ point = self.position
32
+ size = self.size
33
+ point.x += size.width / 2
34
+ point.y += if element.position.y > point.y
35
+ size.height - fudge_factor
36
+ else
37
+ fudge_factor
38
+ end
39
+
40
+ # scroll until element is visible
41
+ until NSContainsRect(self.bounds, element.bounds)
42
+ Mouse.move_to point
43
+ end
44
+
45
+ start = Time.now
46
+ until Time.now - start > 5
47
+ # Sometimes the little arrow bars in menus covering
48
+ # up the menu item and we have to move just a bit more.
49
+ if self.application.element_at(Mouse.current_position) != element
50
+ Mouse.move_to element.to_point
51
+ else
52
+ break
53
+ end
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Search the menu for a `menu_item` that matches the given
59
+ # filters. The filters should be specified just as they would
60
+ # be when calling {#search}.
61
+ def item filters = {}, &block
62
+ result = self.search :menu_item, filters, &block
63
+ return result unless result.blank?
64
+ raise Accessibility::SearchFailure.new(self, :menu_item, filters, &block)
65
+ end
66
+
67
+ end
data/lib/ax/row.rb CHANGED
@@ -31,7 +31,7 @@ class AX::Row < AX::Element
31
31
  qualifier = Accessibility::Qualifier.new(:Column, filters, &block)
32
32
  column = self.parent.columns.index { |x| qualifier.qualifies? x }
33
33
  return self.children.at(column) if column
34
- raise Accessibility::SearchFailure.new(self.parent, 'column', filters)
34
+ raise Accessibility::SearchFailure.new(self.parent, 'column', filters, &block)
35
35
  end
36
36
 
37
37
  end
@@ -0,0 +1,33 @@
1
+ require 'ax/element'
2
+
3
+ ##
4
+ # UI element for a view that can scroll? I'm not sure how else to
5
+ # describe it, the class name says it all.
6
+ class AX::ScrollArea < AX::Element
7
+
8
+ ##
9
+ # Scroll through the receiver until the given element is visible.
10
+ #
11
+ # If you need to scroll an unknown amount of units through a scroll
12
+ # area, or something in a scroll area (i.e. a table), you can just
13
+ # pass the element that you are trying to get to and this method
14
+ # will scroll to it for you.
15
+ #
16
+ # @example
17
+ #
18
+ # scroll_area.scroll_to table.rows.last
19
+ #
20
+ # @param [AX::Element]
21
+ # @return [void]
22
+ def scroll_to element
23
+ return if NSContainsRect(self.bounds, element.bounds)
24
+ Mouse.move_to self.to_point
25
+ # calculate direction to scroll
26
+ direction = element.position.y > self.position.y ? -5 : 5
27
+ until NSContainsRect(self.bounds, element.bounds)
28
+ Mouse.scroll direction
29
+ end
30
+ sleep 0.1
31
+ end
32
+
33
+ end
data/lib/mouse.rb CHANGED
@@ -92,30 +92,15 @@ module Mouse
92
92
  end
93
93
  end
94
94
 
95
- ##
96
- # A standard click. Default position is the current position.
97
- #
98
- # This `duration` parameter is used to add a minimum time between
99
- # down and up click as clicking up too fast has shown to screw things up in
100
- # some cases. However, the duration is arbitrary and if the system lags it
101
- # could cause certain timing behaviours (consider the two behaviours of
102
- # pop up buttons).
103
- #
104
- # @param [CGPoint]
105
- def click point = current_position, duration = 12
106
- click_down
107
- sleep QUANTUM*duration
108
- click_up
109
- end
110
-
111
95
  ##
112
96
  # Perform a down click. You should follow this up with a call to
113
97
  # {#click_up} to finish the click.
114
98
  #
115
99
  # @param [CGPoint]
116
- def click_down point = current_position
100
+ def click_down point = current_position, duration = 12
117
101
  event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
118
102
  post event
103
+ sleep QUANTUM*duration
119
104
  end
120
105
 
121
106
  ##
data/rakelib/ext.rake CHANGED
@@ -46,8 +46,8 @@ task :clobber_key_coder do
46
46
  $stdout.puts "rm #{file}"
47
47
  rm_f file
48
48
  end
49
- file = 'rm ext/accessibility/key_coder/Makefile'
50
- $stdout.puts file
49
+ file = 'ext/accessibility/key_coder/Makefile'
50
+ $stdout.puts "rm #{file}"
51
51
  rm_f file
52
52
  end
53
53
 
@@ -12,7 +12,6 @@ class TestAccessibilityDSL < MiniTest::Unit::TestCase
12
12
  @dsl ||= DSL.new
13
13
  end
14
14
 
15
- def app; @@app ||= AX::Application.new REF end
16
15
  def text_area; @@text_area ||= app.main_window.text_area end
17
16
  def pop_up; @@pop_up ||= app.main_window.pop_up end
18
17
  def pref_window; app.children.find { |x| x.attribute(:title) == 'Preferences' } end
@@ -2,10 +2,6 @@ require 'test/integration/helper'
2
2
 
3
3
  class TestAccessibilityEnumeratorsBreadthFirst < MiniTest::Unit::TestCase
4
4
 
5
- def app
6
- @@app ||= AX::Application.new REF
7
- end
8
-
9
5
  def test_each_iterates_in_correct_order
10
6
  tab_group = app.main_window.children.find { |x| x.class == AX::TabGroup }
11
7
  enum = Accessibility::Enumerators::BreadthFirst.new(tab_group)
@@ -1,38 +1,41 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'test/integration/helper'
2
3
 
3
4
  class TestAccessibilityErrors < MiniTest::Unit::TestCase
4
5
 
5
6
  def test_search_failure_shows_arguments
6
- e = Accessibility::SearchFailure.new(AX::DOCK, :list, {herp: :derp})
7
+ e = Accessibility::SearchFailure.new(app, :list, {herp: :derp}) { }
8
+ def e.backtrace; []; end
9
+ assert_match /Could not find `List\(herp: :derp\)\[✔\]`/, e.message
10
+
11
+ e = Accessibility::SearchFailure.new(app, :list, {herp: :derp})
7
12
  def e.backtrace; []; end
8
13
  assert_match /Could not find `List\(herp: :derp\)`/, e.message
9
14
  assert_match /as a child of AX::Application/, e.message
10
15
  assert_match /Element Path:\n\t\#<AX::Application/, e.message
11
16
 
12
- e = Accessibility::SearchFailure.new(AX::DOCK, :list, {})
17
+ e = Accessibility::SearchFailure.new(app, :list, {})
13
18
  def e.backtrace; []; end
14
19
  assert_match /Could not find `List`/, e.message
15
20
 
16
- e = Accessibility::SearchFailure.new(AX::DOCK, :list, nil)
21
+ e = Accessibility::SearchFailure.new(app, :list, nil)
17
22
  def e.backtrace; []; end
18
23
  assert_match /Could not find `List`/, e.message
19
24
  end
20
25
 
21
26
  def test_search_failure_shows_element_path
22
- l = AX::DOCK.children.first
23
- e = Accessibility::SearchFailure.new(l, :trash_dock_item, nil)
27
+ e = Accessibility::SearchFailure.new(app.menu_bar, :trash_dock_item, nil)
24
28
  def e.backtrace; []; end
25
29
  assert_match /AX::Application/, e.message
26
- assert_match /AX::List/, e.message
30
+ assert_match /AX::MenuBar/, e.message
27
31
  end
28
32
 
29
33
  def test_search_failure_includes_subtree_in_debug_mode
30
34
  assert Accessibility.debug?, 'Someone turned debugging off'
31
- l = AX::DOCK.children.first
32
- e = Accessibility::SearchFailure.new(l, :trash_dock_item, nil)
35
+ e = Accessibility::SearchFailure.new(app.menu_bar, :trash_dock_item, nil)
33
36
  def e.backtrace; []; end
34
37
  assert_match /Subtree:/, e.message
35
- assert_match subtree_for(l), e.message
38
+ assert_match app.menu_bar.inspect_subtree, e.message
36
39
  end
37
40
 
38
41
  end
@@ -0,0 +1,12 @@
1
+ require 'test/integration/helper'
2
+ require 'accessibility/graph'
3
+
4
+ class TestAccessibilityGraph < MiniTest::Unit::TestCase
5
+
6
+ def test_generate
7
+ p = Accessibility::Graph.new(app.main_window).generate_png!
8
+ assert File.exists? p
9
+ assert_match /^PNG image/, `file --brief #{p}`
10
+ end
11
+
12
+ end
@@ -3,10 +3,6 @@ require 'test/integration/helper'
3
3
 
4
4
  class TestAccessibilityQualifier < MiniTest::Unit::TestCase
5
5
 
6
- def app
7
- AX::Application.new REF
8
- end
9
-
10
6
  def qualifier klass, criteria, &block
11
7
  Accessibility::Qualifier.new(klass, criteria, &block)
12
8
  end
@@ -2,12 +2,8 @@ require 'test/integration/helper'
2
2
 
3
3
  class TestAXApplication < MiniTest::Unit::TestCase
4
4
 
5
- def app
6
- @app ||= AX::Application.new REF
7
- end
8
-
9
5
  def running_app
10
- @app.instance_variable_get :@app
6
+ app.instance_variable_get :@app
11
7
  end
12
8
 
13
9
  def test_initialize_args
@@ -2,10 +2,6 @@ require 'test/integration/helper'
2
2
 
3
3
  class TestAXElement < MiniTest::Unit::TestCase
4
4
 
5
- def app
6
- @@app ||= AX::Application.new PID
7
- end
8
-
9
5
  def test_path_returns_correct_elements_in_correct_order
10
6
  list = app.window.close_button.ancestry
11
7
  assert_equal 3, list.size
@@ -0,0 +1,29 @@
1
+ require 'test/integration/helper'
2
+
3
+ class TestAXMenu < MiniTest::Unit::TestCase
4
+
5
+ def test_item
6
+ pop_up = app.main_window.pop_up
7
+ click pop_up
8
+
9
+ assert_respond_to pop_up.menu, :item
10
+
11
+ assert_equal 'Togusa', pop_up.menu.item(title: 'Togusa').title
12
+
13
+ pop_up.menu.item(title: '38') { |x| @got_called = true }
14
+ assert @got_called
15
+
16
+ ensure
17
+ click pop_up if pop_up
18
+ end
19
+
20
+
21
+ def test_item_raises
22
+ pop_up = app.main_window.pop_up
23
+ click pop_up
24
+ assert_raises(Accessibility::SearchFailure) { pop_up.menu.item(herp: 'derp') }
25
+ ensure
26
+ click pop_up if pop_up
27
+ end
28
+
29
+ end
@@ -2,7 +2,6 @@ require 'test/integration/helper'
2
2
 
3
3
  class TestAXRow < MiniTest::Unit::TestCase
4
4
 
5
- def app; @@app ||= AX::Application.new REF end
6
5
  def table; @@table ||= app.main_window.table end
7
6
  def rows; @@rows ||= table.rows end
8
7
  def row; rows.first end
@@ -2,10 +2,6 @@ require 'test/integration/helper'
2
2
 
3
3
  class TestNSArrayCompat < MiniTest::Unit::TestCase
4
4
 
5
- def app
6
- @@app ||= AX::Application.new PID
7
- end
8
-
9
5
  def test_raises_for_non_elements
10
6
  assert_raises NoMethodError do
11
7
  [1].rows
@@ -3,10 +3,6 @@ require 'minitest/ax_elements'
3
3
 
4
4
  class TestMiniTestAssertions < MiniTest::Unit::TestCase
5
5
 
6
- def app
7
- @@app ||= AX::Application.new PID
8
- end
9
-
10
6
  def test_assert_has_child
11
7
  expected = app.window
12
8
 
@@ -4,11 +4,6 @@ require 'rspec/expectations/ax_elements'
4
4
 
5
5
  class TestRSpecMatchers < MiniTest::Unit::TestCase
6
6
 
7
- def app
8
- @@app ||= AX::Application.new PID
9
- end
10
-
11
-
12
7
 
13
8
  def test_have_child_should_failure_message
14
9
  e = app.main_window.slider
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: AXElements
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.8.0
5
+ version: 0.8.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mark Rada
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-24 00:00:00 Z
12
+ date: 2012-04-25 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -88,9 +88,11 @@ files:
88
88
  - lib/ax/application.rb
89
89
  - lib/ax/button.rb
90
90
  - lib/ax/element.rb
91
+ - lib/ax/menu.rb
91
92
  - lib/ax/pop_up_button.rb
92
93
  - lib/ax/radio_button.rb
93
94
  - lib/ax/row.rb
95
+ - lib/ax/scroll_area.rb
94
96
  - lib/ax/static_text.rb
95
97
  - lib/ax/systemwide.rb
96
98
  - lib/ax_elements/awesome_print.rb
@@ -117,9 +119,11 @@ files:
117
119
  - test/integration/accessibility/test_dsl.rb
118
120
  - test/integration/accessibility/test_enumerators.rb
119
121
  - test/integration/accessibility/test_errors.rb
122
+ - test/integration/accessibility/test_graph.rb
120
123
  - test/integration/accessibility/test_qualifier.rb
121
124
  - test/integration/ax/test_application.rb
122
125
  - test/integration/ax/test_element.rb
126
+ - test/integration/ax/test_menu.rb
123
127
  - test/integration/ax/test_row.rb
124
128
  - test/integration/ax_elements/test_nsarray_compat.rb
125
129
  - test/integration/minitest/test_ax_elements.rb
@@ -174,9 +178,11 @@ test_files:
174
178
  - test/integration/accessibility/test_dsl.rb
175
179
  - test/integration/accessibility/test_enumerators.rb
176
180
  - test/integration/accessibility/test_errors.rb
181
+ - test/integration/accessibility/test_graph.rb
177
182
  - test/integration/accessibility/test_qualifier.rb
178
183
  - test/integration/ax/test_application.rb
179
184
  - test/integration/ax/test_element.rb
185
+ - test/integration/ax/test_menu.rb
180
186
  - test/integration/ax/test_row.rb
181
187
  - test/integration/ax_elements/test_nsarray_compat.rb
182
188
  - test/integration/minitest/test_ax_elements.rb