rocknrole : Working on dogtail nodes by creating objects with rolename-attributes

Creating RNR objects
Searching for nodes
Name
Index 
Accessing the nodes as attributes of RNR object directly
Waiting for a node to appear
Refresh
Actions on nodes
Count and Index
Helper
Verification methods provided for PyUnit
        State Checking
        Screenshot Comparison

Download rocknrole and examples

Creating RNR objects

  1. We can create an RNR object by passing a dogtail node to the RNR class's init.
                      rnr_object = RNR(dogtail_node)

  2. We can call the "rolename-methods" for the rnr_object.
                      rnr_object1 = rnr_object2.dialogR('Settings')
                      rnr_object1 will be None if the rolename is not found under the dogtail node represented by rnr_object2.

    Here we can access the dogtail node as :
                    dialog_dogtail_node = rnr_object1.node

    If we did not want to create an RNR object, just to get to its dogtail node, we can omit the 'R' in the end, as in :
                    dialog_dogtail_node = rnr_object2.dialog('Settings')

  3. runR('app') - launches application using dogtail.utils.run and returns (RNRObjectOfApp, pid)

  4. Create an RNR object of an application using appR('appname').
    appR('appname') is just there to simplify writing RNR(tree.root.application('appname'))

Searching for nodes

  1. Name

    All searches are case-sensitive.
    Search for a dialog whose name is 'Account Settings'

    Exact Name :
          dialog = rnr_object.dialogR('Account Settings', 'x')

    Starting with :
          dialog = rnr_object.dialogR('Account S', 'm')

    If we do not specify the searchType, then exact search is performed first, followed by matches (i.e., starting-with searches) and then substring search.
    We should note here that the first found item is returned. 
  2. Index 

    mnitem = rnr_object.menuitem(5)
  3. Accessing the nodes as attributes of RNR object directly

    Dogtail nodes can be accessed by directly accessing the rolename-attribute.

         rnrObject.RNRtablecell is a list of tablecells (dogtail nodes) under the rnrObject.
         rnrObject.RNRtablecell[9] is the dogtail node for the 10th tablecell.
  4. Waiting for a node to appear

    This call is useful when we have to wait for a particular node to come up.  e.g. a bluetooth device discovery dialog which shows BT devices in range.

    RNRObject.WaitFor<NSeconds><Rolename>(<name>)
    wait time, if not specified is 9 seconds.

    WaitFor should be thought of as wait-for-atleast, it can take longer than the specified time.

    myphone = rnr_object.WaitFor13tablecell('green')

    myphone = rnr_object.WaitFortablecell('blue')   - waits for atleast 9 seconds, can be more if a refresh action has started internally

Refresh

After each unsuccessful search, the object is "refreshed", ie, its RNR attributes are purged and re-created.
The number of times to search is governed by  searchCutoffCount defined in rocknrole, unless there is a WaitFor time specified and that elapses.

Sometimes when a node changes or new nodes appear, it is better to call refresh explicitly. rather than wait for the searches to fail and refresh internally.

    rnrObject.refresh()

The refreshes make the RNR approach slower than directly using dogtail, but when used judiciously, the tradeoff is not so bad.
In cases where the refreshes are not frequently needed, the search may be faster too.
If populating the rolename-attributes of an rnr object takes a long time, then we work on dogtail nodes only to find the node we need to work on and create an rnr object out of it.

Actions on nodes

    Anything starting with a capital letter after the rolename is taken as action to be performed on the found node.

    e.g. rnr_dialog.pushbuttonClick('OK') - click on pushbutton with name 'OK'

    press, release, rawclick, doubleclick are calls to actions as defined in the dogtail.rawinput module.

    posclick - rnr_object.tablecellPosclick_5_10 will click on the (x+5,y+10) co-ordinates, where (x,y) is the position of the node.

    do - do specified action on the dogtail node of the RNR object.

    Anything else translates to doAction from dogtail.tree module.

    We can specify refresh before or after an action with ARefresh or ZRefresh respectively.
    rnrobject.ZRefreshtablecellClick('green') - click on tablecell 'green' under rnrobject, and refresh the contents of rnrobject after the click.

Count and Index

    rnrObject.menuIndex('Applications') - returns index of menu Applications or -1 if not found
   
    rnrObject.menuCount() - returns number of menus under rnrObject.
   
    rnrObject.ARefreshmenuCount() - refreshes the object and then returns count of menus.

    rnrObject.ARefreshtablecellIndex('yellow') - refreshes the object and then returns the index of 'yellow' tablecell.

Helper

    Helper is RNR's equivalent of dogtail's dump.
    The helper method shows the RNR object's attributes.

    rnrObject.dialogR(0).helper()

#################################################################################################
Node roleName='dialog' name='Password needed' description=''
#################################################################################################


##### RNRlabel(1):
0 : name='', extents=(293, 190, 293, 28)', actions=''

##### RNRpanel(2):
0 : name='User name', extents=(293, 218, 293, 32)', actions='click'
1 : name='Password:', extents=(293, 250, 293, 32)', actions='click'

##### RNRpushbutton(2):
0 : name='Cancel', extents=(442, 292, 105, 47)', actions='press release click'
1 : name='OK', extents=(331, 292, 105, 47)', actions='press release click'

##### RNRpasswordtext(1):
0 : name='control', extents=(414, 250, 172, 32)', actions='activate'

##### RNRtext(1):
0 : name='control', extents=(414, 218, 172, 32)', actions='activate'

##### RNRfiller(2):
0 : name='', extents=(293, 190, 293, 159)', actions=''
1 : name='', extents=(293, 282, 293, 67)', actions=''

Verification methods provided for PyUnit

        Apart from the PyUnit's asserts, RNR provides additional checks.

1. State Checking

         assertState(dogtailNode, states)
            'states' are the AT-SPI states.  A dogtail node is checked if its in the mentioned state(s).
             e.g. assertState(dogtailNode, 'checked') - asserts that the state of the node is  'checked'.
                    assertState(dogtailNode, 'checked', 'focused')  checks if the node is in 'checked' and 'focused' state.

        assertNotState(dogtailNode, states)
            It's the negate of assertState.  The node is ascertained not to be in the mentioned states.

        assertStateDict(dogtailNode, dictStates)
            The keys of the dict are 'states' and 'notstates'.  Values  are the AT-SPI states.
             e.g.  assertStateDict(dogtailNode, {'states': ('pressed', 'focussed'), 'notstates' : ('checked', 'selected')})

    The above three asserts are to be used in PyUnit test cases. They in turn use checkState and it can be used outside of PyUnit.

     checkState(dogtailNode, states)

          If the dogtail node is not in (all of) the state(s), the check fails. returns a tuple - (True/False,  formatted message string printing out the node's stateSet).

2. Screenshot Comparison

        Image comparison is useful  in cases where the State checks do not fulfill the need. e.g, if there is a need to verify the appearance of an icon/image.

        assertImage( dogtailNode, 'screenshotname.png')  is to be used in PyUnit test cases.
        It in turn calls createImage and most of the code has been reused from screenshots in dogtail.utils with minor modifications to use node's extents.
       
        Works in two modes based on the env variable 'TAKEIMAGE'.
    1. If TAKEIMAGE is set, then the current screenshot is considered as the expected/reference, i.e., screenshotname_exp.png  and is stored in location set by config.scratchDir.
      If we don't specify  the screenshot name then the name is constructed based on unittest.TestCase class name and the testMethod name. We would however need to specify the names when more than
      one assertImage calls are made inside same test.

    2. In actual test runs, TAKEIMAGE is not set and the captured screenshot is compared against expected using imageMagick.
      assertImage is then true/false based on the image comparison results.
        Note that the parameter dogtailNode is optional. If not specified, the screenshot of the entire screen is captured or else of that particular node is captured.


        createImage(
'screenshotname.png', dogtailNode)
            Takes screenshot of the entire screen or of the node if dogtailNode is specified. Raises  an exception if not able to take the screenshot or else returns True on success.