AXElements 0.7.8 → 0.8.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.
Files changed (64) hide show
  1. data/.yardopts +1 -10
  2. data/README.markdown +7 -14
  3. data/ext/accessibility/key_coder/key_coder.c +7 -0
  4. data/lib/AXElements.rb +0 -2
  5. data/lib/accessibility/core.rb +180 -123
  6. data/lib/accessibility/dsl.rb +310 -191
  7. data/lib/accessibility/enumerators.rb +9 -8
  8. data/lib/accessibility/errors.rb +7 -8
  9. data/lib/accessibility/factory.rb +16 -9
  10. data/lib/accessibility/graph.rb +68 -22
  11. data/lib/accessibility/highlighter.rb +86 -0
  12. data/lib/accessibility/pp_inspector.rb +4 -4
  13. data/lib/accessibility/qualifier.rb +11 -9
  14. data/lib/accessibility/string.rb +12 -4
  15. data/lib/accessibility/translator.rb +19 -10
  16. data/lib/accessibility/version.rb +3 -1
  17. data/lib/accessibility.rb +42 -17
  18. data/lib/ax/application.rb +90 -30
  19. data/lib/ax/button.rb +5 -2
  20. data/lib/ax/element.rb +133 -149
  21. data/lib/ax/pop_up_button.rb +12 -0
  22. data/lib/ax/radio_button.rb +5 -2
  23. data/lib/ax/row.rb +2 -2
  24. data/lib/ax/static_text.rb +5 -2
  25. data/lib/ax/systemwide.rb +24 -12
  26. data/lib/ax_elements/awesome_print.rb +13 -0
  27. data/lib/ax_elements/exception_workaround.rb +5 -0
  28. data/lib/ax_elements/nsarray_compat.rb +1 -0
  29. data/lib/ax_elements.rb +2 -1
  30. data/lib/minitest/ax_elements.rb +60 -4
  31. data/lib/mouse.rb +47 -20
  32. data/lib/rspec/expectations/ax_elements.rb +180 -88
  33. data/rakelib/doc.rake +7 -0
  34. data/test/helper.rb +2 -1
  35. data/test/integration/accessibility/test_dsl.rb +126 -18
  36. data/test/integration/accessibility/test_errors.rb +1 -1
  37. data/test/integration/ax/test_element.rb +17 -0
  38. data/test/integration/minitest/test_ax_elements.rb +33 -38
  39. data/test/integration/rspec/expectations/test_ax_elements.rb +68 -19
  40. data/test/sanity/accessibility/test_core.rb +45 -37
  41. data/test/sanity/accessibility/test_highlighter.rb +56 -0
  42. data/test/sanity/ax/test_application.rb +8 -0
  43. data/test/sanity/ax/test_element.rb +7 -3
  44. data/test/sanity/minitest/test_ax_elements.rb +2 -0
  45. data/test/sanity/rspec/expectations/test_ax_elements.rb +3 -0
  46. data/test/sanity/test_accessibility.rb +9 -0
  47. data/test/sanity/test_mouse.rb +2 -2
  48. metadata +11 -38
  49. data/docs/AccessibilityTips.markdown +0 -119
  50. data/docs/Acting.markdown +0 -340
  51. data/docs/Debugging.markdown +0 -165
  52. data/docs/Inspecting.markdown +0 -261
  53. data/docs/KeyboardEvents.markdown +0 -122
  54. data/docs/NewBehaviour.markdown +0 -151
  55. data/docs/Notifications.markdown +0 -271
  56. data/docs/Searching.markdown +0 -250
  57. data/docs/TestingExtensions.markdown +0 -52
  58. data/docs/images/all_the_buttons.jpg +0 -0
  59. data/docs/images/next_version.png +0 -0
  60. data/docs/images/ui_hierarchy.dot +0 -34
  61. data/docs/images/ui_hierarchy.png +0 -0
  62. data/lib/accessibility/debug.rb +0 -164
  63. data/test/integration/accessibility/test_debug.rb +0 -44
  64. data/test/sanity/accessibility/test_debug.rb +0 -63
@@ -1,52 +0,0 @@
1
- # Test Helpers
2
-
3
- @todo Pretend that this does not exist yet
4
-
5
- There are some types of assertions that you would like to make during
6
- testing that simply does not make sense using the build in
7
- assertions. These can include things like existence checks which you
8
- would have to implement by searching, or ... that is really the only
9
- one I have so far :)
10
-
11
- ## RSpec
12
-
13
- RSpec 2 is the Marketcircle choice for implementing functional and
14
- behavioural tests for apps using AXElements. It is great and offers
15
- the flexibility and features that make using it very good for large
16
- test suites.
17
-
18
- You can load the RSpec matchers that AXElements adds by requiring
19
-
20
- require 'rspec/ax_elements'
21
-
22
- ### Existence
23
-
24
- Checking for the existence of an object in RSpec with AXElements looks
25
- a bit awkward:
26
-
27
- window.search(:button).should be_empty
28
- # or
29
- window.search(:button).should_not be_empty
30
-
31
- That does not communicate intent as clearly as it could. What if you
32
- could say something like:
33
-
34
- window.should have_a :button
35
- # or
36
- window.should_not have_a :button
37
-
38
- What if you have filters? Well, that is handled as well, though maybe
39
- not as nicely:
40
-
41
- window.should have_a(:button).with(title: 'Hello')
42
-
43
- ## Minitest
44
-
45
- AXElements uses minitest for its own regression test suite. Minitest
46
- is pretty cool, and there is good cause to support it as well. To that
47
- end, we have provided the equivalent assertions.
48
-
49
- You can load it like so:
50
-
51
- require 'minitest/ax_elements'
52
-
Binary file
Binary file
@@ -1,34 +0,0 @@
1
- digraph {
2
- Application [label = "Application: Mail", style=filled]
3
- MainWindow [label = "MainWindow: Inbox"]
4
- Outline [label = "Outline"]
5
- Table [label = "Table: Emails"]
6
- TableRow1 [label = "TableRow: Spam"]
7
- TableRow2 [label = "TableRow: Daily LOLcat"]
8
- MenuBar [label = "MenuBar", style=filled]
9
- MenuBarItem1 [label = "MenuBarItem: File", style=filled]
10
- MenuBarItem2 [label = "MenuBarItem: Edit"]
11
- MenuBarItem3 [label = "MenuBarItem: Help"]
12
- Menu1 [label = "Menu", style=filled]
13
- MenuItem1 [label = "MenuItem: Preferences"]
14
- MenuItem2 [label = "MenuItem: Services", style=filled]
15
- MenuItem3 [label = "MenuItem: Quit"]
16
- Menu2 [label = "Menu", style=filled]
17
- MenuItem4 [label = "MenuItem: Services Preferences", style=filled]
18
-
19
- Application -> MainWindow
20
- Application -> MenuBar
21
- MainWindow -> Outline
22
- MainWindow -> Table
23
- Table -> TableRow1
24
- Table -> TableRow2
25
- MenuBar -> MenuBarItem1
26
- MenuBar -> MenuBarItem2
27
- MenuBar -> MenuBarItem3
28
- MenuBarItem1 -> Menu1
29
- Menu1 -> MenuItem1
30
- Menu1 -> MenuItem2
31
- Menu1 -> MenuItem3
32
- MenuItem2 -> Menu2
33
- Menu2 -> MenuItem4
34
- }
Binary file
@@ -1,164 +0,0 @@
1
- require 'accessibility/version'
2
- framework 'Cocoa'
3
-
4
- ##
5
- # Collection of utility methods helpful when trying to debug issues.
6
- module Accessibility::Debug
7
-
8
- # Initialize the DEBUG value
9
- @on = ENV.fetch 'AXDEBUG', $DEBUG
10
-
11
-
12
- class << self
13
-
14
- ##
15
- # Whether or not to turn on DEBUG features in AXElements. The
16
- # value is initially inherited from `$DEBUG` but can be overridden
17
- # by an environment variable named `AXDEBUG` or changed dynamically
18
- # at runtime.
19
- #
20
- # @return [Boolean]
21
- attr_accessor :on
22
- alias_method :on?, :on
23
-
24
- ##
25
- # Get a list of elements, starting with an element you give, and riding
26
- # the hierarchy up to the top level object (i.e. the {AX::Application}).
27
- #
28
- # @example
29
- #
30
- # element = AX::DOCK.list.application_dock_item
31
- # path_for element
32
- # # => [AX::ApplicationDockItem, AX::List, AX::Application]
33
- #
34
- # @param [AX::Element]
35
- # @return [Array<AX::Element>] the path in ascending order
36
- def path *elements
37
- element = elements.last
38
- return path(elements << element.parent) if element.respond_to? :parent
39
- return elements
40
- end
41
-
42
- ##
43
- # @note This is an unfinished feature
44
- #
45
- # Make a `dot` format graph of the tree, meant for graphing with
46
- # GraphViz.
47
- #
48
- # @return [String]
49
- def graph_subtree root
50
- require 'accessibility/graph'
51
- dot = Accessibility::Graph.new(root)
52
- dot.build!
53
- dot.to_s
54
- end
55
-
56
- ##
57
- # Dump a tree to the console, indenting for each level down the
58
- # tree that we go, and inspecting each element.
59
- #
60
- # @example
61
- #
62
- # puts subtree_for app
63
- #
64
- # @return [String]
65
- def text_subtree element
66
- output = element.inspect + "\n"
67
- # @todo should use each_child_with_level instead
68
- enum = Accessibility::Enumerators::DepthFirst.new element
69
- enum.each_with_level do |element, depth|
70
- output << "\t"*depth + element.inspect + "\n"
71
- end
72
- output
73
- end
74
-
75
- ##
76
- # Highlight an element on screen. You can optionally specify the
77
- # highlight colour or pass a timeout to automatically have the
78
- # highlighter disappear.
79
- #
80
- # The highlighter is actually a window, so if you do not set a
81
- # timeout, you will need to call `#stop` or `#close` on the `NSWindow`
82
- # object that this method returns in order to get rid of the
83
- # highlighter.
84
- #
85
- # You could use this method to highlight an arbitrary number of
86
- # elements on screen, with a rainbow of colours for debugging.
87
- #
88
- # @example
89
- #
90
- # highlighter = highlight window.outline
91
- # highlight window.outline.row, colour: NSColor.greenColor, timeout: 5
92
- # highlighter.stop
93
- #
94
- # @param [AX::Element]
95
- # @param [Hash] opts
96
- # @option opts [Number] :timeout
97
- # @option opts [NSColor] :colour
98
- # @return [NSWindow]
99
- def highlight element, opts = {}
100
- app = NSApplication.sharedApplication
101
- colour = opts[:colour] || opts[:color] || NSColor.magentaColor
102
- window = highlight_window_for element.bounds, colour
103
-
104
- if opts.has_key? :timeout
105
- Dispatch::Queue.new('window_killer').after opts[:timeout] do
106
- window.close
107
- end
108
- end
109
-
110
- window
111
- end
112
-
113
-
114
- private
115
-
116
- ##
117
- # Create the window that acts as the highlighted portion of the screen.
118
- #
119
- # @param [NSRect]
120
- # @param [NSColor]
121
- # @return [NSWindow]
122
- def highlight_window_for bounds, colour
123
- bounds.flip!
124
- window = NSWindow.alloc.initWithContentRect bounds,
125
- styleMask: NSBorderlessWindowMask,
126
- backing: NSBackingStoreBuffered,
127
- defer: true
128
-
129
- window.setOpaque false
130
- window.setAlphaValue 0.20
131
- window.setLevel NSStatusWindowLevel
132
- window.setBackgroundColor colour
133
- window.setIgnoresMouseEvents true
134
- window.setFrame bounds, display: false
135
- window.makeKeyAndOrderFront NSApp
136
- def window.stop
137
- close
138
- end
139
- window
140
- end
141
-
142
- end
143
- end
144
-
145
-
146
- ##
147
- # AXElements extensions to `CGRect`.
148
- class CGRect
149
- ##
150
- # Treats the rect as belonging to one co-ordinate system and then
151
- # converts it to the other system.
152
- #
153
- # This is useful because accessibility API's expect to work with
154
- # the flipped co-ordinate system (origin in top left), but AppKit
155
- # prefers to use the cartesian co-ordinate system (origin in bottom
156
- # left).
157
- #
158
- # @return [CGRect]
159
- def flip!
160
- screen_height = NSMaxY(NSScreen.mainScreen.frame)
161
- origin.y = screen_height - NSMaxY(self)
162
- self
163
- end
164
- end
@@ -1,44 +0,0 @@
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
@@ -1,63 +0,0 @@
1
- require 'test/runner'
2
- require 'accessibility/debug'
3
-
4
- class TestAccessibilityDebug < MiniTest::Unit::TestCase
5
-
6
- def mock_element
7
- @mock = Object.new
8
- def @mock.bounds; CGRectMake(100,100,100,100); end
9
- @mock
10
- end
11
-
12
- def test_debug_setting
13
- assert_respond_to Accessibility::Debug, :on?
14
- assert_respond_to Accessibility::Debug, :on=
15
- end
16
-
17
- def test_highlight_returns_created_window
18
- w = Accessibility::Debug.highlight mock_element
19
- assert_kind_of NSWindow, w
20
- assert_respond_to w, :stop
21
- ensure
22
- w.close if w
23
- end
24
-
25
- def test_highlight_can_take_a_timeout
26
- w = Accessibility::Debug.highlight mock_element, timeout: 0.1
27
- assert w.visible?
28
- sleep 0.15
29
- refute w.visible? # Not exactly the assertion I want, but close enough
30
- ensure
31
- w.close if w
32
- end
33
-
34
- def test_highlight_can_have_custom_colour
35
- w = Accessibility::Debug.highlight mock_element, color: NSColor.cyanColor
36
- assert w.backgroundColor == NSColor.cyanColor
37
- w.close
38
-
39
- # test both spellings of colour
40
- w = Accessibility::Debug.highlight mock_element, colour: NSColor.purpleColor
41
- assert w.backgroundColor == NSColor.purpleColor
42
- end
43
-
44
- def test_highlight_highlights_correct_rect
45
- w = Accessibility::Debug.highlight mock_element
46
- assert_equal w.frame, mock_element.bounds.flip!
47
- end
48
-
49
- end
50
-
51
- class TestCGRectExtensions < MiniTest::Unit::TestCase
52
-
53
- def test_flipping
54
- size = NSScreen.mainScreen.frame.size
55
- assert_equal CGRectMake( 0, size.height, 0, 0), CGRectZero.dup.flip!
56
- assert_equal CGRectMake(100, size.height-200,100,100), CGRectMake(100,100,100,100).flip!
57
- end
58
-
59
- def test_flipping_twice_returns_to_original
60
- assert_equal CGRectZero.dup, CGRectZero.dup.flip!.flip!
61
- end
62
-
63
- end