AXElements 0.7.8 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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