Module: Accessibility::DSL
- Included in:
- HasChildShortlyMatcher, HasDescendentShortlyMatcher
- Defined in:
- lib/accessibility/dsl.rb
Overview
DSL methods for AXElements.
The DSL for AXElements is designed to pull actions out from an object and put them in front of object to make communicating test steps seem more like human instructions.
You can read more about the DSL in the Acting section of the AXElements wiki.
Actions collapse
-
#cancel(element) ⇒ Boolean
Try to perform the
cancel
action on the given element. -
#confirm(element) ⇒ Boolean
Try to perform the
confirm
action on the given element. -
#decrement(element) ⇒ Boolean
Try to perform the
decrement
action on the given element. -
#delete(element) ⇒ Boolean
Try to perform the
delete
action on the given element. -
#hide(app) ⇒ Boolean
Tell an app to hide itself.
-
#increment(element) ⇒ Boolean
Try to perform the
increment
action on the given element. -
#method_missing(meth, *args) ⇒ Object
We assume that any method that has the first argument with a type of AX::Element is intended to be an action and so
#method_missing
will forward the message to the element. -
#pick(element) ⇒ Boolean
Try to perform the
pick
action on the given element. -
#press(element) ⇒ Boolean
Try to perform the
press
action on the given element. -
#raise(*args) ⇒ Object
Try to perform the
raise
action on the given element. -
#scroll_menu_to(element)
Scroll a menu to an item in the menu and then move the mouse pointer to that item.
-
#scroll_to(element)
(also: #scroll_to_visible)
Scroll through a scroll area until the given element is visible.
-
#select_menu_item(app, *path) ⇒ Boolean
Navigate the menu bar menus for the given application and select the last item in the chain.
-
#set(element, change) ⇒ Object
Set the value of an attribute on an element.
-
#set_focus_to(element) ⇒ Object
(also: #set_focus)
Focus an element on the screen, but only if it can be directly focused.
-
#show_about_window_for(app) ⇒ AX::Window
Show the “About” window for an app.
-
#show_menu(element) ⇒ Boolean
Try to perform the
show_menu
action on the given element. -
#show_preferences_window_for(app) ⇒ AX::Window
Try to open the preferences for an app.
-
#terminate(app) ⇒ Boolean
Tell an app to quit.
-
#type(string, app = system_wide) ⇒ Object
(also: #type_string)
Simulate keyboard input by typing out the given string.
-
#unhide(app) ⇒ Boolean
(also: #show)
Tell an app to unhide itself.
Polling collapse
-
#wait_for(element, filters = {}, &block) ⇒ AX::Element?
Simply wait around for something to show up.
-
#wait_for_child(child, parent, filters, &block) ⇒ AX::Element?
Wait around for particular element and then return that element.
-
#wait_for_descendant(descendant, ancestor, filters, &block) ⇒ AX::Element?
(also: #wait_for_descendent)
Wait around for particular element and then return that element.
-
#wait_for_invalidation_of(element, filters = {}, &block) ⇒ Boolean
(also: #wait_for_invalidation, #wait_for_invalid)
Simply wait for an element to disappear.
Mouse Manipulation collapse
-
#click(obj = nil, wait = 0.2) { ... } ⇒ Object
Perform a regular click.
-
#double_click(obj = nil, wait = 0.2) ⇒ Object
Perform a double click action.
-
#drag_mouse_to(arg, opts = {}) ⇒ Object
Click and drag the mouse from its current position to the given position.
-
#move_mouse_to(arg, opts = {}) ⇒ Object
Move the mouse cursor to the given point or object on the screen.
-
#right_click(obj = nil, wait = 0.2) ⇒ Object
(also: #secondary_click)
Perform a right (aka secondary) click action.
-
#scroll(lines, obj = nil, wait = 0.1) ⇒ Object
Scrolls an arbitrary number of lines at the mouses current point on the screen.
Debug Helpers collapse
-
#graph(element) ⇒ String
(also: #graph_for)
Make and open a
dot
format graph of the tree, meant for graphing with GraphViz. -
#highlight(obj, opts = {}) ⇒ Accessibility::Highlighter
Highlight an element on screen.
-
#screenshot(name = "AXElements-ScreenShot", dir = '~/Desktop') ⇒ String
(also: #capture_screen)
Take a screen shot and save it to disk.
-
#subtree(element) ⇒ String
(also: #subtree_for)
Get the dump of the subtree of children and descendants for the given element.
Instance Method Summary collapse
-
#app_with_bundle_identifier(id) ⇒ AX::Application?
(also: #app_with_bundle_id, #launch)
Find the application with the given bundle identifier.
-
#app_with_name(name) ⇒ AX::Application?
Find the application with the given name.
-
#app_with_pid(pid) ⇒ AX::Application
Find the application with the given process identifier.
-
#element_at_point(point, opts = {}) ⇒ AX::Element
(also: #element_at)
Get the top most object at an arbitrary point on the screen for the given application.
-
#element_under_mouse ⇒ AX::Element
Return the top most element at the current mouse position.
-
#system_wide ⇒ AX::SystemWide
Convenience for
AX::SystemWide.new
.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args) ⇒ Object
We assume that any method that has the first argument with a type
of AX::Element is intended to be an action and so #method_missing
will forward the message to the element.
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/accessibility/dsl.rb', line 33 def method_missing meth, *args arg = args.first if arg.kind_of? AX::Element return arg.perform meth if arg.actions.include? meth raise ArgumentError, "`#{meth}' is not an action of #{self}:#{self.class}" end # @todo do we still need this? we should just call super # should be able to just call super, but there is a bug in MacRuby (#1320) # so we just recreate what should be happening = "undefined method `#{meth}' for #{self}:#{self.class}" raise NoMethodError, , caller(1) end |
Instance Method Details
#app_with_bundle_identifier(id) ⇒ AX::Application? Also known as: app_with_bundle_id, launch
Find the application with the given bundle identifier. If the application is not already running, it will be launched.
709 710 711 |
# File 'lib/accessibility/dsl.rb', line 709 def app_with_bundle_identifier id Accessibility.application_with_bundle_identifier id end |
#app_with_name(name) ⇒ AX::Application?
Find the application with the given name. If the application
is not already running, it will NOT be launched and this
method will return nil
.
726 727 728 |
# File 'lib/accessibility/dsl.rb', line 726 def app_with_name name AX::Application.new name end |
#app_with_pid(pid) ⇒ AX::Application
Find the application with the given process identifier. An invalid PID will cause an exception to be raised.
740 741 742 |
# File 'lib/accessibility/dsl.rb', line 740 def app_with_pid pid AX::Application.new pid end |
#cancel(element) ⇒ Boolean
Try to perform the cancel
action on the given element.
114 115 116 |
# File 'lib/accessibility/dsl.rb', line 114 def cancel element element.perform :cancel end |
#click(obj = nil, wait = 0.2) { ... } ⇒ Object
Perform a regular click.
If a parameter is provided then the mouse will move to that point
first; the argument must respond to #to_point
.
If a block is given, it will be yielded to between the click down and click up event.
547 548 549 550 551 552 553 |
# File 'lib/accessibility/dsl.rb', line 547 def click obj = nil, wait = 0.2 move_mouse_to obj, wait: 0 if obj Mouse.click_down yield if block_given? Mouse.click_up sleep wait end |
#confirm(element) ⇒ Boolean
Try to perform the confirm
action on the given element.
87 88 89 |
# File 'lib/accessibility/dsl.rb', line 87 def confirm element element.perform :confirm end |
#decrement(element) ⇒ Boolean
Try to perform the decrement
action on the given element.
78 79 80 |
# File 'lib/accessibility/dsl.rb', line 78 def decrement element element.perform :decrement end |
#delete(element) ⇒ Boolean
Try to perform the delete
action on the given element.
105 106 107 |
# File 'lib/accessibility/dsl.rb', line 105 def delete element element.perform :delete end |
#double_click(obj = nil, wait = 0.2) ⇒ Object
Perform a double click action.
If an argument is provided then the mouse will move to that point
first; the argument must respond to #to_point
.
576 577 578 579 580 |
# File 'lib/accessibility/dsl.rb', line 576 def double_click obj = nil, wait = 0.2 move_mouse_to obj, wait: 0 if obj Mouse.double_click sleep wait end |
#drag_mouse_to(arg, opts = {}) ⇒ Object
Click and drag the mouse from its current position to the given position.
There are many reasons why you would want to cause a drag event with the mouse. Perhaps you want to drag an object to another place, or maybe you want to select a group of objects on the screen.
503 504 505 506 507 |
# File 'lib/accessibility/dsl.rb', line 503 def drag_mouse_to arg, opts = {} move_mouse_to opts[:from] if opts[:from] Mouse.drag_to arg.to_point, (opts[:duration] || 0.2) sleep(opts[:wait] || 0.2) end |
#element_at_point(point, opts = {}) ⇒ AX::Element Also known as: element_at
Get the top most object at an arbitrary point on the screen for
the given application. The given point can be a CGPoint, an Array,
or anything else that responds to #to_point
.
Optionally, you can look for the top-most element for a specific
application by passing an AX::Application object using the for:
key.
782 783 784 785 |
# File 'lib/accessibility/dsl.rb', line 782 def element_at_point point, opts = {} base = opts[:for] || system_wide base.element_at point end |
#element_under_mouse ⇒ AX::Element
Return the top most element at the current mouse position.
See #element_at_point for more details.
758 759 760 |
# File 'lib/accessibility/dsl.rb', line 758 def element_under_mouse element_at_point Mouse.current_position end |
#graph(element) ⇒ String Also known as: graph_for
You will need to have GraphViz command line tools installed in order for this to work.
Make and open a dot
format graph of the tree, meant for graphing
with GraphViz.
644 645 646 647 648 649 650 |
# File 'lib/accessibility/dsl.rb', line 644 def graph element require 'accessibility/graph' graph = Accessibility::Graph.new(element) path = graph.generate_png! `open #{path}` path end |
#hide(app) ⇒ Boolean
Tell an app to hide itself.
140 141 142 |
# File 'lib/accessibility/dsl.rb', line 140 def hide app app.perform :hide end |
#highlight(obj, opts = {}) ⇒ Accessibility::Highlighter
Highlight an element on screen. You can optionally specify the highlight colour or pass a timeout to automatically have the highlighter disappear.
The highlighter is actually a window, so if you do not set a
timeout, you will need to call #stop
or #close
on the returned
highlighter object in order to get rid of the highlighter.
You could use this method to highlight an arbitrary number of elements on screen, with a rainbow of colours. Great for debugging.
611 612 613 614 |
# File 'lib/accessibility/dsl.rb', line 611 def highlight obj, opts = {} require 'accessibility/highlighter' Accessibility::Highlighter.new obj.bounds, opts end |
#increment(element) ⇒ Boolean
Try to perform the increment
action on the given element.
96 97 98 |
# File 'lib/accessibility/dsl.rb', line 96 def increment element element.perform :increment end |
#move_mouse_to(arg, opts = {}) ⇒ Object
Move the mouse cursor to the given point or object on the screen.
476 477 478 479 480 481 482 483 |
# File 'lib/accessibility/dsl.rb', line 476 def move_mouse_to arg, opts = {} duration = opts[:duration] || 0.2 if Accessibility.debug? && arg.respond_to?(:bounds) highlight arg, timeout: duration, color: NSColor.orangeColor end Mouse.move_to arg.to_point, duration sleep(opts[:wait] || 0.2) end |
#pick(element) ⇒ Boolean
Try to perform the pick
action on the given element.
69 70 71 |
# File 'lib/accessibility/dsl.rb', line 69 def pick element element.perform :pick end |
#press(element) ⇒ Boolean
Try to perform the press
action on the given element.
51 52 53 |
# File 'lib/accessibility/dsl.rb', line 51 def press element element.perform :press end |
#raise(element) ⇒ Boolean #raise(exception[, message[, backtrace]]) ⇒ Object
This method overrides Kernel#raise
so we have to check the
class of the first argument to decide which code path to take.
Try to perform the raise
action on the given element.
130 131 132 133 |
# File 'lib/accessibility/dsl.rb', line 130 def raise *args arg = args.first arg.kind_of?(AX::Element) ? arg.perform(:raise) : super(*args) end |
#right_click(obj = nil, wait = 0.2) ⇒ Object Also known as: secondary_click
Perform a right (aka secondary) click action.
If an argument is provided then the mouse will move to that point
first; the argument must respond to #to_point
.
562 563 564 565 566 |
# File 'lib/accessibility/dsl.rb', line 562 def right_click obj = nil, wait = 0.2 move_mouse_to obj, wait: 0 if obj Mouse.right_click sleep wait end |
#screenshot(name = "AXElements-ScreenShot", dir = '~/Desktop') ⇒ String Also known as: capture_screen
Take a screen shot and save it to disk. If a file name and path are not given then default values will be used; given paths will be expanded automatically.A timestamp and file extension will always automatically be appended to the file name.
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 |
# File 'lib/accessibility/dsl.rb', line 673 def screenshot name = "AXElements-ScreenShot", dir = '~/Desktop' # @todo this could move to its own class, much like # {Accessibility::Highlighter} and expose more options # while retaining good defaults dir = File. dir.to_s file = "#{dir}/#{name}-#{Time.now.strftime '%Y%m%d%H%M%S'}.png" cg_image = CGWindowListCreateImage(CGRectInfinite, KCGWindowListOptionOnScreenOnly, KCGNullWindowID, KCGWindowImageDefault) NSBitmapImageRep .alloc .initWithCGImage(cg_image) .representationUsingType(NSPNGFileType, properties: nil) .writeToFile(file, atomically: false) file end |
#scroll(lines, obj = nil, wait = 0.1) ⇒ Object
Need to expose the units option? Would allow scrolling by pixel.
Scrolls an arbitrary number of lines at the mouses current point on the screen. Use a positive number to scroll down, and a negative number to scroll up.
If the second argument is provided then the mouse will move to that
point first; the argument must respond to #to_point
.
521 522 523 524 525 |
# File 'lib/accessibility/dsl.rb', line 521 def scroll lines, obj = nil, wait = 0.1 move_mouse_to obj, wait: 0 if obj Mouse.scroll lines sleep wait end |
#scroll_menu_to(element)
This method returns an undefined value.
Scroll a menu to an item in the menu and then move the mouse pointer to that item.
307 308 309 |
# File 'lib/accessibility/dsl.rb', line 307 def element = element.ancestor(:menu).scroll_to element end |
#scroll_to(element) Also known as: scroll_to_visible
This method returns an undefined value.
Scroll through a scroll area until the given element is visible.
If you need to scroll an unknown amount of units through a table or another type of object contained in as scroll area, you can just pass the element that you are trying to get to and this method will scroll to it for you.
290 291 292 |
# File 'lib/accessibility/dsl.rb', line 290 def scroll_to element element.ancestor(:scroll_area).scroll_to element end |
#select_menu_item(app, *path) ⇒ Boolean
Navigate the menu bar menus for the given application and select the last item in the chain.
249 250 251 |
# File 'lib/accessibility/dsl.rb', line 249 def app, *path app. *path end |
#set(element, attribute_name: new_value) ⇒ Object #set(element, new_value) ⇒ Object
Set the value of an attribute on an element.
This method will try to set focus to the element first; this is to compensate for cases where app developers assumed an element would have to have focus before a user could change the value.
200 201 202 203 204 205 206 207 208 |
# File 'lib/accessibility/dsl.rb', line 200 def set element, change set_focus_to element if change.kind_of? Hash element.set *change.first else element.set :value, change end end |
#set_focus_to(element) ⇒ Object Also known as: set_focus
Focus an element on the screen, but only if it can be directly focused. It is safe to pass any element into this method as nothing will happen if it does not have a writable focused state attribute.
169 170 171 |
# File 'lib/accessibility/dsl.rb', line 169 def set_focus_to element element.set(:focused, true) if element.writable? :focused end |
#show_about_window_for(app) ⇒ AX::Window
Show the “About” window for an app. Returns the window that is opened.
259 260 261 |
# File 'lib/accessibility/dsl.rb', line 259 def show_about_window_for app app.show_about_window end |
#show_menu(element) ⇒ Boolean
Try to perform the show_menu
action on the given element.
60 61 62 |
# File 'lib/accessibility/dsl.rb', line 60 def element element.perform :show_menu end |
#show_preferences_window_for(app) ⇒ AX::Window
This method assumes that the app has setup the standard CMD+, hotkey to open the pref window
Try to open the preferences for an app. Returns the window that is opened.
272 273 274 |
# File 'lib/accessibility/dsl.rb', line 272 def show_preferences_window_for app app.show_preferences_window end |
#subtree(element) ⇒ String Also known as: subtree_for
Get the dump of the subtree of children and descendants for the given element. Each generation down the tree will be indented another level, and each element will be inspected.
626 627 628 |
# File 'lib/accessibility/dsl.rb', line 626 def subtree element element.inspect_subtree end |
#system_wide ⇒ AX::SystemWide
Convenience for AX::SystemWide.new
.
748 749 750 |
# File 'lib/accessibility/dsl.rb', line 748 def system_wide AX::SystemWide.new end |
#terminate(app) ⇒ Boolean
Tell an app to quit.
159 160 161 |
# File 'lib/accessibility/dsl.rb', line 159 def terminate app app.perform :terminate end |
#type(string) ⇒ Object #type(string, app) ⇒ Object Also known as: type_string
Simulate keyboard input by typing out the given string. To learn more about how to encode modifier keys (e.g. Command), see the dedicated documentation page on Keyboard Events wiki page.
230 231 232 233 |
# File 'lib/accessibility/dsl.rb', line 230 def type string, app = system_wide sleep 0.1 app.type string.to_s end |
#unhide(app) ⇒ Boolean Also known as: show
Tell an app to unhide itself.
149 150 151 |
# File 'lib/accessibility/dsl.rb', line 149 def unhide app app.perform :unhide end |
#wait_for(element, filters = {}, &block) ⇒ AX::Element?
Simply wait around for something to show up. This method is similar to performing an explicit search on an element except that the search filters take two extra options which can control the timeout period and the search subtree. You MUST supply either the parent or ancestor option to specify where to search from. Searching from the parent implies that what you are waiting for is a child of the parent and not a more distant descendant.
This is an alternative to using the notifications system. It is far easier to use than notifications in most cases, but it will perform more slowly (and without all the fun crashes).
344 345 346 347 348 349 350 351 352 |
# File 'lib/accessibility/dsl.rb', line 344 def wait_for element, filters = {}, &block if filters.has_key? :ancestor wait_for_descendant element, filters.delete(:ancestor), filters, &block elsif filters.has_key? :parent wait_for_child element, filters.delete(:parent), filters, &block else raise ArgumentError, 'parent/ancestor filter required' end end |
#wait_for_child(child, parent, filters, &block) ⇒ AX::Element?
This is really just an optimized case of #wait_for_descendant when you know what you are waiting for is a child of a particular element. Use #wait_for_descendant if you are unsure of the relationship.
Wait around for particular element and then return that element. The parent argument must be the parent of the element you are waiting for, this method will not look further down the hierarchy. The options you pass to this method can be any search filter that you can normally use.
See #wait_for for more details.
395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/accessibility/dsl.rb', line 395 def wait_for_child child, parent, filters, &block timeout = filters.delete(:timeout) || 5 start = Time.now q = Accessibility::Qualifier.new(child, filters, &block) until Time.now - start > timeout result = parent.children.find { |x| q.qualifies? x } return result unless result.blank? sleep 0.1 end nil end |
#wait_for_descendant(descendant, ancestor, filters, &block) ⇒ AX::Element? Also known as: wait_for_descendent
Wait around for particular element and then return that element. The options you pass to this method can be any search filter that you can normally use.
See #wait_for for more details.
365 366 367 368 369 370 371 372 373 374 |
# File 'lib/accessibility/dsl.rb', line 365 def wait_for_descendant descendant, ancestor, filters, &block timeout = filters.delete(:timeout) || 5 start = Time.now until Time.now - start > timeout result = ancestor.search(descendant, filters, &block) return result unless result.blank? sleep 0.1 end nil end |
#wait_for_invalidation_of(element) ⇒ Boolean #wait_for_invalidation_of(kind, filters = {}, &block) ⇒ Boolean Also known as: wait_for_invalidation, wait_for_invalid
Simply wait for an element to disappear. Optionally wait for the element to appear first.
Like #wait_for, you can pass any search filters that you normally would, including blocks. However, this method also supports the ability to pass an AX::Element and simply wait for it to become invalid.
An example usage would be typing into a search field and then waiting for the busy indicator to disappear and indicate that all search results have been returned.
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/accessibility/dsl.rb', line 441 def wait_for_invalidation_of element, filters = {}, &block timeout = filters[:timeout] || 5 start = Time.now unless element.kind_of? AX::Element element = wait_for element, filters, &block # this is a tricky situation, return true unless element end until Time.now - start > timeout return true if element.invalid? sleep 0.1 end false end |