KEMBAR78
UIAutomation + Mechanic.js
Today I’d like to talk about UIAutomation,
          how you can use it to make your iOS apps
          better.

          After I’ve given you the downlow on UIA,
          I’m going to show you how to make it
          better with a framework I’ve created called
          mechanic.




mechanic.js
uiautomation++
So what is UIAutomation? UIAutomation is a
         software tool (and its accompanying
         framework) built by Apple that allows
         developers to automate interacting with their
         iOS apps for testing.

         UIAutomation makes it easy to script clicks,
         drags, location changes, etc. and allows you
         to assert on the state of your UI.




what is
uiautomation?
play time:
1. Open your favorite project in XCode
2. Cmd-I
3. Choose “Automation” as the Trace Template and click
  “Profile”
4. In the “Scripts” section, click “Add” and create a
  script
5. Automate!
                            4) You don’t have to create a new script, you can import an
                            existing script in your source directory.

                            - Scripts can be ran from the console using the ‘instruments’
                            cmd line utility, as well.

                            - The ‘bwoken’ gem can also be used - it allows you to write
                            tests in coffeescript and run them from the cmd line (though I
                            haven’t been able to get it to work for me just yet)

                            * open instruments and create a simple script that logs element
                            tree for frontMostApp().mainWindow() and describe it *
* show uiautomation/jasmine demo. Explain how it is set
           up (i.e. how to use #import, etc.) *

           * for those of you not familiar with jasmine, it’s an
           RSpec-like framework for writing Javascript specs




uiautomation and
jasmine are pretty cool..
UIAutomation is not without it’s blemishes. Though it’s Apple’s official tool for this
              sort of automation (one reason I’d be wary of using tools like Square’s KIF and
              Frankified), it’s very young

              1. The API isn’t shaped like a modern JS framework like we expect (underscore,
              jQuery, requireJS, Knockout, etc.)

              2. The API is relatively verbose (and at times redundant)

              3. The mechanisms to navigate your app’s “DOM” make it difficult to “get” the
              elements you’re trying to interact with and assert on




what’s the catch?
    What’s the answer to these problems? Mechanic is (or I hope it is)!

    Mechanic servers as a shim to alleviate these pains.
So...


        What’s in
          it for me?
So I’ve given you the elevator pitch.. Now the hard sell:




actions speak louder
than words...
var mainWindow =
UIATarget.localTarget().frontMostApp.mainWindow();
mainWindow.tableViews[‘members’].cells()[‘First row’].tap();
UIATarget.localTarget().delay(2);
var navBar = mainWindow.navigationBars()[‘userDetails’];

assertEquals(‘Back’, navBar.buttons()[0].label());
assertEquals(‘Close’, navBar.buttons()[1].label());


                                 vs                   (describe what the code is
$(‘#members cell’).first()                             doing)
                                                      * # of lines is not much
 .tap()                                               different buuuutttt...
                                                      * code density
 .delay(2);                                           * law of demeter
                                                      * cheated a bit, top code
                                                      would span more lines if
var buttons = $(‘#userDetails button’);               abstracted to the same level

assertEquals(‘Back’, buttons[0].label());
assertEquals(‘Close’, buttons[0].last().label());
and another...
// click all buttons
 var mainWindow = UIATarget.localTarget().frontMostApp.mainWindow();
 var i, j, k, l, m, n, o, p;
 var someButtonElements = mainWindow.elements[‘some_buttons’].elements();
 for (i = 0; i < someButtonElements.length; i++) {
    if (someButtonElements typeof UIAButton) {
      someButtonElements[i].tap();
    }
 }
 var moreButtons = mainWindow.scrollViews()[‘first scrollview’].elements();
 for (i = 0; i < moreButtons.length; i++) {
    if (moreButtons typeof UIAButton) {
      moreButtons[i].tap();
    }



                                         vs
 }
 // ...snip




                                                       (describe what the code is doing - trying to tap all
                                                       of the buttons in the app’s window)

                                                       * the non-mechanic version is intrinsically more
$(‘button’).tap();                                     difficult since there’s no easy mechanism for
                                                       searching the window’s “DOM”
                                                       * This example might be unfair - is it a realistic use
                                                       case?
* mechanic-core is the heart of
                mechanic
                * it’s the reason I wrote / am writing
                mechanic
                * gives you the DOM searching/
                traversing that’s missing from
                UIAutomation, similar to jQuery,
                Prototype, etc.
                * gives you the chaining that we
                know and love and have come to
                expect in selector engines.
                * The other “modules” in mechanic
                are really just niceties or chained
                wrappers on top of the existing
                  UIAutomation APIs.




act i.
mechanic-core
selector                         * UIAutomation places different element
                                     types (buttons, text, images, table cells,



    shortcuts
                                     etc.) into rather verbose classes. When
                                     searching for elements of a certain type,
                                     I’ve provided shorter class names to
                                     decrease the signal-to-noise ratio.




The UIAutomation environment is
pretty minimal. Mechanic provides
                                    functional
                                    extensions
some simple functional-type
functions like map, each, slice,
reduce, etc.




      dom
                                            Most of the UIAutomation scripting
                                            I’ve done, most of the work goes
                                            into “getting” the element you’re



      traversal
                                            looking for. Mechanic provides a
                                            number of means of filtering and
                                            expanding sets of matched
                                            elements.
find stuff:
           (+ more)

$(‘#my-scroll-view image’).each(function(img) { img.log(); });


$(‘text’, aPopover).siblings(‘image’);


var names = $(‘*’).map(function() { return this.name() });


var allNonTextEls = $(‘window’).children().not(‘text’);


var el = $(‘*’).predicate(‘where label == “Some label”’);
act ii.
events
device
                                            We can change the device’s volume,
                                            location, lock the device, etc.




manipulation

Simulate screen touches, rotations, etc.
                                           screen
                                           actions

element
                                              taps, touches, rotations on
                                              buttons, pickers, text, etc.




interaction
do stuff:
             (+ more)


$.orientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT);

$.volume(‘down’, 2);

$(‘#my-scrollview’).dragInside(
 {startOffset : {x:0,y:2}, endOffset: {x:20,y:30}, duration:2});


$(‘#password’, loginScreen).input(‘my password’);


$(‘#my-scroll-view text’).last().scrollToVisible();
act iii.
data
application
preferences

         element
         details
  app
  info
get stuff:
            (+ more)

$.message($(aStaticTextElement).value());


var firstImageLabel = $(‘image’).first().label();


$.message($.bundleId());


$.prefs({ prefA: 1, prefB: ‘some value’ });


var lastElIsVisible = $(‘*’).last().isVisible();
act iv.
logging
screen
  capture
            console
            logging
element
information
record stuff:
        (+ more.. well, not really..)

$.warn(‘An element was not where it should have been!’);


$(‘text’).log();


$(‘window’).logTree();


$(‘image’).capture();

$(‘#my-button’).tap()
 .parent().capture()
 .message(‘tapped the button and then captured a picture!’);
act v.
act v.
choose your
own adventure!
selectors
    documentation
                         more coverage
                                               assertions??
Big thing is that only simple selectors are
                                                create issues
supported, though the functions in mechanic-        use it!!!
core make it easy to construct complex               please...?
constructors.

Reworking mechanic-core based on Sizzle
and qwery currently, which should expose
more complex queries.
submit issues. read docs. fork. download. commit. write specs. add
new features. maintain examples. submit issues. read docs. fork.
download. commit. write specs. add new features. maintain
examples. submit issues. read docs. fork. download. commit. write
specs. add new features. maintain examples. submit issues. read
docs. fork. download. commit. write specs. add new features.
maintain examples. submit issues. read docs. fork. download.
commit. write specs. add new features. maintain examples. submit
issues. read docs. fork. download. commit. write specs. add new
features. maintain examples. submit issues. read docs. fork.
download. commit. write specs. add new features. maintain
                                    find out more @
examples.submit issues. read docs. fork. download. commit. write
             github.com/jaykz52/mechanic
specs. add new features. maintain examples. submit issues. read
docs. fork. download. commit. write specs. add new features.
maintain examples. submit issues. read docs. fork. download.
commit. write specs. add new features. maintain examples. submit
issues. read docs. fork. download. commit. write specs. submit
QUESTIONS???

@jaykz52
I L OV E TO TA L K

UIAutomation + Mechanic.js

  • 1.
    Today I’d liketo talk about UIAutomation, how you can use it to make your iOS apps better. After I’ve given you the downlow on UIA, I’m going to show you how to make it better with a framework I’ve created called mechanic. mechanic.js uiautomation++
  • 2.
    So what isUIAutomation? UIAutomation is a software tool (and its accompanying framework) built by Apple that allows developers to automate interacting with their iOS apps for testing. UIAutomation makes it easy to script clicks, drags, location changes, etc. and allows you to assert on the state of your UI. what is uiautomation?
  • 3.
    play time: 1. Openyour favorite project in XCode 2. Cmd-I 3. Choose “Automation” as the Trace Template and click “Profile” 4. In the “Scripts” section, click “Add” and create a script 5. Automate! 4) You don’t have to create a new script, you can import an existing script in your source directory. - Scripts can be ran from the console using the ‘instruments’ cmd line utility, as well. - The ‘bwoken’ gem can also be used - it allows you to write tests in coffeescript and run them from the cmd line (though I haven’t been able to get it to work for me just yet) * open instruments and create a simple script that logs element tree for frontMostApp().mainWindow() and describe it *
  • 4.
    * show uiautomation/jasminedemo. Explain how it is set up (i.e. how to use #import, etc.) * * for those of you not familiar with jasmine, it’s an RSpec-like framework for writing Javascript specs uiautomation and jasmine are pretty cool..
  • 5.
    UIAutomation is notwithout it’s blemishes. Though it’s Apple’s official tool for this sort of automation (one reason I’d be wary of using tools like Square’s KIF and Frankified), it’s very young 1. The API isn’t shaped like a modern JS framework like we expect (underscore, jQuery, requireJS, Knockout, etc.) 2. The API is relatively verbose (and at times redundant) 3. The mechanisms to navigate your app’s “DOM” make it difficult to “get” the elements you’re trying to interact with and assert on what’s the catch? What’s the answer to these problems? Mechanic is (or I hope it is)! Mechanic servers as a shim to alleviate these pains.
  • 6.
    So... What’s in it for me?
  • 7.
    So I’ve givenyou the elevator pitch.. Now the hard sell: actions speak louder than words...
  • 8.
    var mainWindow = UIATarget.localTarget().frontMostApp.mainWindow(); mainWindow.tableViews[‘members’].cells()[‘Firstrow’].tap(); UIATarget.localTarget().delay(2); var navBar = mainWindow.navigationBars()[‘userDetails’]; assertEquals(‘Back’, navBar.buttons()[0].label()); assertEquals(‘Close’, navBar.buttons()[1].label()); vs (describe what the code is $(‘#members cell’).first() doing) * # of lines is not much .tap() different buuuutttt... * code density .delay(2); * law of demeter * cheated a bit, top code would span more lines if var buttons = $(‘#userDetails button’); abstracted to the same level assertEquals(‘Back’, buttons[0].label()); assertEquals(‘Close’, buttons[0].last().label());
  • 9.
  • 10.
    // click allbuttons var mainWindow = UIATarget.localTarget().frontMostApp.mainWindow(); var i, j, k, l, m, n, o, p; var someButtonElements = mainWindow.elements[‘some_buttons’].elements(); for (i = 0; i < someButtonElements.length; i++) { if (someButtonElements typeof UIAButton) { someButtonElements[i].tap(); } } var moreButtons = mainWindow.scrollViews()[‘first scrollview’].elements(); for (i = 0; i < moreButtons.length; i++) { if (moreButtons typeof UIAButton) { moreButtons[i].tap(); } vs } // ...snip (describe what the code is doing - trying to tap all of the buttons in the app’s window) * the non-mechanic version is intrinsically more $(‘button’).tap(); difficult since there’s no easy mechanism for searching the window’s “DOM” * This example might be unfair - is it a realistic use case?
  • 11.
    * mechanic-core isthe heart of mechanic * it’s the reason I wrote / am writing mechanic * gives you the DOM searching/ traversing that’s missing from UIAutomation, similar to jQuery, Prototype, etc. * gives you the chaining that we know and love and have come to expect in selector engines. * The other “modules” in mechanic are really just niceties or chained wrappers on top of the existing UIAutomation APIs. act i. mechanic-core
  • 12.
    selector * UIAutomation places different element types (buttons, text, images, table cells, shortcuts etc.) into rather verbose classes. When searching for elements of a certain type, I’ve provided shorter class names to decrease the signal-to-noise ratio. The UIAutomation environment is pretty minimal. Mechanic provides functional extensions some simple functional-type functions like map, each, slice, reduce, etc. dom Most of the UIAutomation scripting I’ve done, most of the work goes into “getting” the element you’re traversal looking for. Mechanic provides a number of means of filtering and expanding sets of matched elements.
  • 13.
    find stuff: (+ more) $(‘#my-scroll-view image’).each(function(img) { img.log(); }); $(‘text’, aPopover).siblings(‘image’); var names = $(‘*’).map(function() { return this.name() }); var allNonTextEls = $(‘window’).children().not(‘text’); var el = $(‘*’).predicate(‘where label == “Some label”’);
  • 14.
  • 15.
    device We can change the device’s volume, location, lock the device, etc. manipulation Simulate screen touches, rotations, etc. screen actions element taps, touches, rotations on buttons, pickers, text, etc. interaction
  • 16.
    do stuff: (+ more) $.orientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT); $.volume(‘down’, 2); $(‘#my-scrollview’).dragInside( {startOffset : {x:0,y:2}, endOffset: {x:20,y:30}, duration:2}); $(‘#password’, loginScreen).input(‘my password’); $(‘#my-scroll-view text’).last().scrollToVisible();
  • 17.
  • 18.
    application preferences element details app info
  • 19.
    get stuff: (+ more) $.message($(aStaticTextElement).value()); var firstImageLabel = $(‘image’).first().label(); $.message($.bundleId()); $.prefs({ prefA: 1, prefB: ‘some value’ }); var lastElIsVisible = $(‘*’).last().isVisible();
  • 20.
  • 21.
    screen capture console logging element information
  • 22.
    record stuff: (+ more.. well, not really..) $.warn(‘An element was not where it should have been!’); $(‘text’).log(); $(‘window’).logTree(); $(‘image’).capture(); $(‘#my-button’).tap() .parent().capture() .message(‘tapped the button and then captured a picture!’);
  • 23.
  • 24.
  • 25.
    selectors documentation more coverage assertions?? Big thing is that only simple selectors are create issues supported, though the functions in mechanic- use it!!! core make it easy to construct complex please...? constructors. Reworking mechanic-core based on Sizzle and qwery currently, which should expose more complex queries.
  • 26.
    submit issues. readdocs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain find out more @ examples.submit issues. read docs. fork. download. commit. write github.com/jaykz52/mechanic specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. add new features. maintain examples. submit issues. read docs. fork. download. commit. write specs. submit
  • 27.