23 November 2012

Dojo Automation with QuickTest Professional 11 - Incompatibility, Workarounds and Framework


Dojo happens to be one of the trickiest of technologies that is supported by QTP 11. Dojo is an open source Javascript Toolkit/Framework which allows faster development in the simplest of ways. Now QTP does provide support for Dojo in essence but it is not that simple. Since, Dojo is an open source technology, it is adopted by various organizations and customized as per their requirement. For example, if QTP 11 recognizes a Dojo Tree in one application developed by Company A, it might not in an application developed by Company B. Now to get around the problem, you can use the Extensibility Accelerator (EA) with QTP 11. 

Dojo Toolkit Versions QTP Support
================== ==========
Dojo 1.7.3 Not Officially Known
Dojo 1.6.1 Not Officially Known
Dojo 1.5.2 Officially Not Supported
Dojo 1.4.4 Not Officially Known
Dojo 1.3.3 Not Officially Known
Dojo 1.2.4 Not Officially Known
Dojo 1.2.3 Officially Supported - Yes
Dojo 1.1.2 Not Officially Known
Dojo 1.0.3 Not Officially Known
Dojo 0.4.4 Not Officially Known

Using the Extensibility Accelerator (EA)

Now Extensibility Accelerator (EA) is nothing but a set of (JavaScript) JS files that you will typically find in the folder where QTP is installed. These JS files hold the key as to how QTP recognizes the various controls in your application. If your organization uses customized dojo controls or a dojo toolkit version not officially supported by QTP, you will need to play around with these JS files or use the logic in these files and convert them into VBScript to get QTP 11 to work with the dojo controls. You can directly use the EA to create new addins as well but I liked the idea of converting the logic to VBScript and implementing the same as that provided more flexibility in my perception. So technically, you end up creating a framework sort of structure in VBScript where you create functions to handle each of the dojo controls. 

Factors that affect the use of  Extensibility Accelerator (EA) or the creation of a similar framework in VBScript:

1. Your application needs to be extremely stable which means if the developer later customizes the control you might end up changing a lot of code.
2. An IE version change from version 7 to 8 to 9 or 10 may require a lot of rework.
3. A corresponding Dojo Toolkit version for the AUT change may require a lot of rework.
4. You need proper collaboration with the developer when you automate a dojo application.
5. At times in a worst case scenario, you might need to use QTP functions like Highlight in combination with DeviceReplay functions.  

Creating the Dojo VBScript framework in QTP

For example, I will use the Dojo Tree control. To find the Dojo Tree JS File, simply browse to the following location - C:\Program Files (x86)\HP\QuickTest Professional\dat\Extensibility\Web\Toolkits\Dojo\\JavaScript\DojoTree.js



This file has the follow JS functions -


function get_property_value(prop)
function Collapse(Path)
function Expand(Path)
function Select(Path)
function ListenToEvents( elem )
function onMouseUp(node, eventObj)
function popupHandler()
function ensureItemVisible(Path)
function getParentNode(node)
function getNodePath(node)
function getNodeName(node)
function isNodeFocused(node)
function getNodeState(node)
function setNodeState(node, expand)
function getAllNodes()
function getFocusedNode()
function getVisibleItems(nodeList)
function isHiddenNode(node)
function getRootList()
function getChildrenList(node)
function isOpenOnClick()


Consider a scenario where you want to select a node in a Dojo Tree. Example, let us consider a tree with 4 primary nodes A1, A2, A3, A4 with sub nodes as B1, B2, B3, B4 with sub nodes as C1, C2, C3, C4. We have to select the node c1. This tree is identified as an object say 'objTree'.
___________________
|-A1                    
|    -B1                        
|        -C1                  
|+A2                          
|+A3                          
|+A4                          
|__________________



A typical QTP statement would be Browser("IE").Page("IE").DojoTree("objQTP").Select "A1;B1;C1"

Now internally QTP calls a combination of these functions to finally select the desired node. Here is a sequence of all the functions that may get called -

function getAllNodes() - To get the list existing nodes in the tree initially
function ensureItemVisible(Path) - To check if the node to be selected is visible; This will be called several time until the desired node is visible for actions.
function Collapse(Path) - to collapse the expanded tree
function Expand(Path) - to expand a collapsed tree
function setNodeState(node, expand) - This is called by the Collapse/Expand methods.
function Select(Path) - If the final node to be selected is visible, then this function clicks it.

The sequence above might be different in actual sense but this is primarily what really happens.

Now when I say creating a 'Dojo VBScript Framework', I mean creating a DojoTree.vbs with all the above functions converted to VBScript format so it can be customized with ease within QTP and can use the QTP utility functions as well. This will aid in rapid development and maintenance than using EA (Extensibility Accelerator).

How to convert the JS functions into VBScript functions?

Here is an example of the same.


I am taking the example of a dummy Dojo Tree and show you how to convert/tweak the code from the JS file. Remember that for different Dojo versions, this code will be tweaked differently. I am working on IE9, hence, this tweak will differ on a different browser. This is so because the HTML hierarchy of these Dojo objects tend change in a different environment.

Browser("Dojo Campus - Feature").Page("Dojo Campus - Feature").DojoTree("tree2").Expand "Africa"

The above statement throws a web extensibility error. This may be due to the incompatibility issue. The "Expand" method in the statement uses the following JS code to perform the action.
'Dojo Adaptation - DojoTree.js
'///////////////////////////////////////////////////////////////////////////////
'// This function supports the Expand test object method. 
'// It expands the specified node.
'//
'// Parameters: Path - The full tree path of the node to expand.
'//             Tree path format: ;

Now we will convert this code into vbscript and tweak a little to make the 'Expand' method work.
'Declaration
Set oTree = Browser("Dojo Campus - Feature").Page("Dojo Campus - Feature").DojoTree("tree2")
node = "Africa"

'Call the function that will expand the node or say set the status on the node only if it is collapsed
'You can further create wrapper function and use "RegisterUserFunc" to create a neat usable command by overriiding "Expand"
Call setNodeState(oTree, node)


'=========================================================
'This function uses the same logic which is used in the JScript function. 
'We first find the node which contains the node identified by the keyword. Example "Africa"
'After we get the HTMLstructure is identified, we parse that strcuture to narrow down to the tag which has the actual node.
'Once we have the actual node, we Instr to find the class if it is dijitTreeExpandoClosed, that means it is collpased and vice-versa
'=========================================================
Function getNodeState(oTree, node)
  For i = 0 to 100
    strNode = oTree.Object.children(0).children(i).outerHTML
    If Instr(strNode, Node)>0 Then
      iNode = i
      Exit For
    End If
  Next
  sNodeState = oTree.Object.children(0).children(iNode).children(0).children(0).children(0).outerHTML
  If Instr(sNodeState, "dijitTreeExpandoOpened") Then
   getNodeState = "0;"& iNode 'Node Expanded
  ElseIf Instr(sNodeState, "dijitTreeExpandoClosed") Then
   getNodeState = "1;"& iNode 'Node Collapsed
  ElseIf Instr(sNodeState, "dijitTreeExpandoLeaf") Then
   getNodeState = "2;"& iNode 'Node Childless
  End If
End Function

'===========================================================
'This function will expand the node if it is collpased
'We narrow down to the actual node tag containing the node name and fireevent just as it was done in JScript
' A simulation/firevent of onmousedown->onmouseup->onclick expands the node
'This sequence must be followed to trigger the action.
'===========================================================
Function setNodeState(oTree, node)
  rc = Split(getNodeState(oTree, node),";")
  If rc(0) = "1" Then
    iNode = CInt(rc(1))
    oTree.Object.children(0).children(iNode).children(0).children(0).children(0).FireEvent "onmousedown"
    oTree.Object.children(0).children(iNode).children(0).children(0).children(0).FireEvent "onmouseup"
    oTree.Object.children(0).children(iNode).children(0).children(0).children(0).FireEvent "onclick"
  End If
End Function


Tips:
1) Use the debug viewer in QTP at runtime by putting a breakpoint to find the right location of a node.
Ex - oTree.Object.children(0).children(iNode).children(0).children(0).children(0).outerHTML
First try, oTree.Object.children(0).outerHTML, study this HTML code to find the node hierarchy. Then by adding "children(iNode).children(0).children(0).children(0).outerHTML" one by one try to reach the right node. It is a time taking process for the first few times, however, after that it is a matter of few minutes.

2) To find the right sequence of events to fire, look for the Events property of the object "oTree.Object.children(0).children(iNode).children(0).children(0).children(0)". It will list down a large number events, however, the events that need to be called will have some java function associated with them and the rest will just say NULL.

The video below shows the error thrown when you try to use the inbuilt method "Expand" to expand the tree and then we try the converted and tweaked code in VBS from the JS file to perform the same action.

3 comments:

  1. Hi,

    Excellent info. I am having difficulty converting the Select (rather than Expand as in yur example) to Vb script

    Any insight on Select based on your example, say if i want to Select "Africa" and nothing is under it

    Thanks, Sarat

    ReplyDelete
    Replies
    1. Sarat, even for a 'Select' the same logic will apply i.e. simulation of 'onclick' once you have the correct node. Where exactly are you facing an issue? I believe the issue if any will be at identifying the right child node series.
      "oTree.Object.children(0).children(iNode).children(0).children(0).children(0)"
      So if that is the case you need to analyze the correct html structure from "oTree.Object.outerHTML" and checking the correct position of the childnode.

      Delete
  2. Hi all,

    I have a problem with a dijiitInput field, because I record the correct value in this filed, but during the replay the system wirtes "No Correct Value". Any ideas to fix this?

    ReplyDelete