Skip to content
Bernard Farrell edited this page May 15, 2013 · 29 revisions

The core module provides the foundation for traversing the UIAutomation element tree. It provides a number of functions that filter and navigate based on matched elements.

Mechanic selectors are much like selectors in frameworks such as jQuery or Dojo. They can be iterated over and also have a number of additional methods made available by other modules.

$()

The mechanic (shortcut to $ for convenience) forms the backbone to the framework. Its signature is:

$(selector, context = frontMostApp())

The 1st argument can take a number of forms. If a UIAElement or an array of UIAElements is passed into it, the matched elements will simply be the element or elements passed in. If present, the 2nd argument (context) is ignored in this case.

If a selector is passed as the 1st argument, the resulting selector is simply the selector originally passed in. The 2nd argument is ignored in this case. To better drive this home:

// ...
var sel1 = $(win);    // 'win' is a UIAWindow
var sel2 = $(sel1, someOtherWin);   // sel2 == sel1

If a string is passed as the selector, a number of scenarios occur. To match by an element name/label, prefix the string passed with a '#' character. This is similar to other CSS-style selector frameworks:

// assume there's a button named 'submitButton'
var selForBtn = $('#submitButton');
// selForBtn now contains the button!

A wildcard selector ('*') works as expected, matching all UIAElements in the context.

UIAElements can also be matched by type using strings. Simply pass the name of the UIAElement subclass you wish to match on to create a selector with elements of that type:

var selForAllLabels = $('UIALabel');
// selForAllLabels contains all the app's labels!

To make selecting by type a bit more terse and to provide a similar feel to other selector frameworks, There are several 'shortcut' strings that can be used instead of the actual type name. For example, passing 'image' is the same as passing 'UIAImage':

var sel1 = $('image');
var sel2 = $('UIAImage');
// sel1 == sel2

The mapping between UIAElement subclasses and shortcuts can be found in the source.

Searching by name and element type can be combined into a single call

// Look for the details button
var detailsBtn = $('#Details button');
// detailsBtn now contains the button!

The optional 2nd argument is used to limit the tree used to search and match elements. The context works much in the same manner as the 1st argument (accepts UIAElements and matcher strings). Only children of the context will be matched against.

Future Plans

Currently, selectors cannot be 'chained' (i.e. $('label#myLabel')) and only matchers for type and name/label are available. There are a number of methods available (see below!) for further filtering/traversing, but these features have not been implemented in the matcher space as of the 0.1.2 version of Mechanic.

Selector functions

Array functions

Since Mechanic.js selectors are essentially "souped up" array-like objects, they have a number of Array functions available to them: forEach, reduce, push, indexOf, and concat

See Mozilla's documentation for more details on these functions.


.map(fn)

Create an array by applying the function specified to each matched element.

The map selector function internally calls mechanic's global map function, passing the function specified and the selector itself. map returns an array based on the result of iterating and applying the function specified.


.each(fn)

Iterate over the matched elements, passing each element to the callback.

The each function is a chained version of mechanic's global each. Internally, the each function uses the global version, passing the callback specified to it, along with the selector itself.


.slice(*args)

Grab a slice of the matched elements.

slice takes the same arguments as Array version of the function, but instead returns a selector from the sliced elements.


.get(index)

Get the matched element at the index specified.


.size()

Get the number of matched elements in the selector.


.find(selector)

Find elements that match the passed selector using the current set of matched elements as the context.

The find function will allow you to select children elements of the current matched elements. For instance, to select all cells under the UITableView named 'my-tableview', you could do the following:

$('#my-tableview').find('cell');

.filter(selector)

Further filters the currently matched elements using the passed selector.

Chaining filter calls is a way of honing in on a particular element or set of elements using a combination of selectors.


.andSelf()

Adds the previously matched elements in the chain to the current set of matched elements.

andSelf is helpful for joining sets of matched elements together. It allows you to build a set through chaining various selector functions together.


.end()

Returns the previously matched elements in the chain.

Use end to "step back" to the previous set of matched elements. This can be useful when you need to "walk" up and down some part of the application tree without breaking the function chain.


.add(selector, context)

Joins the current set of matched elements with those matched by the selector/context passed.

Internally, add(selector, context) simply calls $(selector, context) and returns you the unique union of elements from the current set and the newly matched elements.


.is(selector)

Returns whether or not the first matched element matches the passed selector.


.not(selector)

Filters out all elements in the matched array that match the selector passed.

The not function will return you the complement of filter.

.not(arr)

Filters out all matched elements present in the passed array.

.not(fn)

Filters out all matched elements that return true when passed to the specified function.

The function passed in should have the signature function(index) { ... }, where index refers to the index of the matched element; note that this can be used within the passed function to get a handle on the current element.


.eq(index)

Returns the element at the position specified by the passed index within the current set of matched elements.


.first()

Returns the first element in the current list of matched elements.


.last()

Returns the last element in the current list of matched elements.


.parent()

Returns the set of (unique) elements that are the immediate parents of each element in the current set of matched elements.


.ancestry()

Return the set of (unique) ancestors of each matched element. Accordingly, an element that is the ancestor of multiple matched elements will appear only once.


.closest(selector, context)

Returns the nearest ancestor that matches the selector passed for each matched element. An optional context can be passed to limit the search scope to those elements that are children of the context.

The closest function is similar to the ancestry function, with the caveats mentioned above.

.children(selector)

Returns the immediate children of each element in the current matched set, matching based on the selector parameter, if present.

The selector parameter is optional. It is useful for filtering out additional child elements when necessary.


.siblings(selector)

Returns all elements that are siblings to each matched element, matching based on the selector parameter, if present.

The selector parameter is optional. It is useful for filtering out additional sibling elements when necessary.


.index(element)

Returns the index of the element's position in the set of matched elements.

If the element parameter does not appear in the matching set, -1 is returned.


.pluck(property)

Returns an array of values, where each value is the value of the passed property key for each matched element. If the corresponding property is a function, the function is evaluated and the return value is returned.

An example of what the pluck function could be used for:

var labels = $("button").pluck('label');
$.each(labels, function(idx, el) { ... });

Non-selector functions

mechanic.extend(target, *args)

Extends the target by adding properties from object literals specified.

extend takes the target that you wish to extend as the first argument. You additionally should pass an object literal (or many object literals) with the key/values you wish to extend the object with. For example, to add the onTap and onDrag functions to the specialButton variable:

$.extend(specialButton, {
  onTap: function() { ... },
  onDrag: function() { ... }
});

The extend functionality is used to implement parts of mechanic.


mechanic.map(arrOrHash, callback)

Create a new array by applying the callback given to each element in the array/hash specified.

The map function's callback will be applied to each element in the array. The result of this callback will be added to the array which is returned from the map function. If the callback returns null for an element, map will not add a result for that element.

When an array is passed to the map function, map will pass the iterated element, as well as its index in the array to the callback.

When an object literal is passed into map, each key/value is iterated over, and the callback will receive the value as the 1st argument and the key as the 2nd argument.


mechanic.each(arrOrHash, callback)

Iterate over the array/hash specified, passing each element to the callback specified.

each works in a similar fashion to map. Instead of returning a new array, it will simply return the array passed to it. It's real utility is not in what it returns, but what is performed in the callback. each iterates the array/hash in the same fashion as map.

To break out of the iteration, simply return false from your callback.