QTP: Synchronization for AJAX Applications

by Anshoo Arora ON August 10, 2009 · Posted In All, QTP, QTP/Web · 27 comments


Creative Commons License photo credit: luisvilla

Ajax has been extremely popular amongst developers these days and is being integrated with hundreds of websites. We have also been recently working on a light-weight Ajax application – and its not being very easy, especially when the time it takes for all elements to load is high. I have also read on several forums about automation developers facing issue with Ajax synchronization, and obviously its quite challenging.

There are several ways this class can be used to synchronize with Ajax applications. It can be used to synchronize with either changes in WebTables or with changes in the number of objects existing at any given time (WebElement, WebCheckBox etc). I wanted to record a video of this class in action, but because of other obligations, this has not been possible. However, below you will find a textual representation of how this class will work to synchronize Ajax applications:

ObjectSync: Set this to ensure that the object exists on the page before verifying if its Ajax elements have completed loading.

'Setting the object sync:
AjaxUtil.ObjectSync = 20

StatusSync: Set this to ensure that after the object exists, code waits for StatusSync max seconds for all elements to load. The class will keep on waiting until no changes in the application occur for StatusSync seconds.

'Setting the status sync:
AjaxUtil.StatusSync = 20

Loading Objects: You can load the objects initially (or right before you need to execute them). This makes it easy to call your objects anywhere in the script. Also, it is mandatory to add the objects where synchronization occurs (only the WebTables and the Browsers need to be added here, since that’s where all the action takes place). When you’re checking if any elements are added or removed from the page, you only have to add the Browser object in the collection and use AjaxUtil.SyncObjects to sync with the changes. However, if you’re synchronizing your script with (text) changes in the WebTable, and would like to see what text changed, you would have to add the WebTable in the collection also (AjaxUtil.SyncWebTable). But, please note that if the only concern is to check for changes in the WebTable, you can simply add the browser and check for changes in the WebElements.

' Page 1
AjaxUtil.AddObject "MyBrowser1", Browser("title:=Browser1")
' Page 2
AjaxUtil.AddObject "MyBrowser2", Browser("title:=Browser2")
' Synchronize with changes in WebTable text in Page 3
AjaxUtil.AddObject "MyTable1", Browser("title:=Browser3").WebTable("innertext:=WebTable")
' Synchronize with changes in another WebTable text in Page 4
AjaxUtil.AddObject "MyTable2", Browser("title:=Browser4").WebTable("innertext:=WebTable")

How To: Synchronize with changes in object count

AjaxUtil.SetBrowser "MyBrowser1"   ' Mandatory step; must set the browser each time.
AjaxUtil.SyncObjects               ' This step will synchronize with WebElements in "MyBrowser1"

'Synchronize with changes in Page 2
AjaxUtil.SetBrowser "MyBrowser2"
AjaxUtil.SyncObjects

How To: Synchronize changes in WebTable

'Synchronize with "MyTable1" in Page 3
AjaxUtil.SyncWebTable "MyTable1"
 
'Synchronize with "MyTable2" in Page 4
AjaxUtil.SyncWebTable "MyTable2"

Simple! Isn’t it?

Working example:

SystemUtil.Run "iexplore.exe", "www.kayak.com"
 
If Not Browser("title:=Cheap Flights.*").Exist(10) Then ExitTest
 
AjaxUtil.ObjectSync = 30  ' Check if the added objects exist before we synchronize
AjaxUtil.StatusSync = 10    ' Wait for a max 10 seconds if there is no status change

'Add Objects to collection (Its mandatory that you add objects to the class)
AjaxUtil.AddObject "MyBrowser1", Browser("title:=Cheap Flights.*")
AjaxUtil.AddObject "MyTable", Browser("title:=Kayak.com Search Results")_
    .WebTable("innertext:=.*of.*roundtrips shown.*|.*forget all.*", "index:=0")
AjaxUtil.AddObject "MyBrowser2", Browser("title:=Kayak.com Search Results")
 
Browser("title:=Cheap Flights.*").WebEdit("html id:=destination")_
    .Set "Atlanta, GA - Hartsfield-Jackson (ATL)"
 
' Its mandatory that you set a browser for which you will run the test for changes in elements
AjaxUtil.SetBrowser "MyBrowser1"        ' Required Step

' Synchronize for changes in objects:
AjaxUtil.SyncObjects "WebElement"
 
Browser("title:=Cheap Flights.*").WebButton("html id:=fdimgbutton").Click
 
'You can modify the ObjectSync and StatusSync times here for the next operations.
'Example: StatusSync is increased
AjaxUtil.StatusSync = 15       ' increase the StatusSync

'Synchronize with the flights table
AjaxUtil.SyncWebTable "MyTable"
 
'Test Complete - release dictionary
AjaxUtil.DestroyDict


Notice the results below. When StatusSync was 10, the changes in Page verified was 10 times. Similarly, in the case of the WebTable, the statusSync was 15, thus, the changes were verified 15 times over a course of 15 seconds.

How its done:

You can download the code or copy it to your clipboard using the code below:

Public oGlobalDict
 
'—————————————————————————————————————————————
''
' Class clsAjaxUtil
'
' Methods:
'    AddObject
'    DestroyDict
'    RemoveObject
'    SetBrowser
'    SyncObjects *
'    SyncWebTable *
'
' Author: Anshoo Arora
'
' Version: v1.0
''
'—————————————————————————————————————————————
Class clsAjaxSync
'—————————————————————————————————————————————
 
    Public StatusSync       ' Synchronization with changes in application
    Public ObjectSync       ' To synchronize while the object loads  
    Public oBrowser         ' Reference to the target browser: SetBrowser "MyBrowser"
    Public oTable           ' Reference to the target table: SyncWebTable "MyTable"
    Public intVisCnt
 
    Private sClass          ' Class used in SyncObjects
    Private intObjectCount  ' Changes in Object Counts in SyncObjects
    Private oLocalDict      ' Dictionary

 
    '—————————————————————————————————————————
    ' Name: Class_Initialize (Private)
    ' 
    ' Purpose: Scripting.Dictionary Singleton
    ' 
    ' Parameters: 
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Private Sub Class_Initialize
    '—————————————————————————————————————————
        Dim bInit 'As Boolean
    
        bInit = False
 
        'Singleton Pattern (see references in remarks above)
        If IsObject(oGlobalDict) = True Then
            If Not oGlobalDict is Nothing Then
                bInit = True
            End If
        End If
 
        'Only create new object if needed
        If bInit = False Then Set oGlobalDict = CreateObject( "Scripting.Dictionary" )
 
        'Set the local class excel reference to the global Singleton object
        Set oLocalDict = oGlobalDict
    End Sub 
 
    '—————————————————————————————————————————
    ' Name: AddObject (Public)
    ' 
    ' Purpose: Add object to collection
    ' 
    ' Parameters:
    '    sObjectName: Name of the object stored as refereces
    '    oObject: Reference of the object
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Public Sub AddObject( sObjectName, ByRef oObject )
    '—————————————————————————————————————————
        If oLocalDict.Exists(sObjectName) Then
            RemoveObject sObjectName
        End If
 
        oLocalDict.Add sObjectName, oObject    
    End Sub 
 
    '—————————————————————————————————————————
    ' Name: SyncWebTable (Public)
    ' 
    ' Purpose: Synchronize the table for StatusSync seconds to make sure no text has changed.
    ' 
    ' Parameters:
    ' 
    ' Author: 
    ' 
    ' Date: 
    '
    ' Remarks:
    '    Uses recursion
    '—————————————————————————————————————————
    Public Sub SyncWebTable( sTableName )
    '—————————————————————————————————————————
        If IsObject(Me.oTable) Then Set Me.oTable = Nothing
        Set Me.oTable = oLocalDict.Item( sTableName )
 
        If ObjectSync = "" Then ObjectSync = 1
 
        ' Check if the Table exists
        If oTable.Exist(ObjectSync) Then
            ' Make sure the table is visible
            If oTable.GetROProperty( "x" ) <> 0 Then
                ' Sync for changes in Table
                SyncText
            Else
                Reporter.ReportEvent micWarning, sTableName, "Object not visible."
                Me.intVisCnt = Me.intVisCnt + 1
                ' Maybe the table is still loading its elements, use recursion and check again.
                If Not Me.intVisCnt >= 2 Then SyncWebTable sTableName
            End If
        Else
            Reporter.ReportEvent micWarning, sTableName, "Object not found."
        End If
    End Sub
 
    '—————————————————————————————————————————
    ' Name: SyncText
    ' 
    ' Purpose: Verify if the table text has changed. If the text
    ' changes, the original text string is reset. The loop runs again until it 
    ' reaches its max: StatusSync.
    ' 
    ' Parameters:
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Private Sub SyncText
    '—————————————————————————————————————————
        Dim intWait, sNewText, sReportChanges
        Dim sDivider: sDivider = "================================"
        Dim sRefText: sRefText = GetTableText
 
        If StatusSync = 0 Then StatusSync = 1
 
        Do
            ' Get the updated innerText from the Table
            sNewText = GetTableText
 
            sReportChanges = sRefText &vbLf&sDivider& sNewText &vbLf&sDivider& sReportChanges
 
            ' Verify if there were changes
            If sRefText <> sNewText Then
                intWait = 0
                sRefText = sNewText
            Else
                intWait = intWait + 1
            End If
            Wait(1)
        Loop Until intWait = StatusSync
 
        Reporter.ReportEvent micInfo, "WebTable Sync", sReportChanges
    End Sub 
 
    '—————————————————————————————————————————
    ' Name:SyncObjects (Public)
    ' 
    ' Purpose: Checks whether the object count has changed.
    ' 
    ' Parameters:
    '  
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Public Sub SyncObjects( ClassName )
    '—————————————————————————————————————————
        Dim intWait, intNewCount, sReportChanges
        Dim sDivider: sDivider = "================================"
 
        sClass = ClassName
        Dim intObjectCount: intObjectCount = CountObjects
 
        If StatusSync = 0 Then StatusSync = 1
 
        Do 
            ' Get the current number of objects count for ClassName
            intNewCount = CountObjects
 
            sReportChanges = "Old: " & intObjectCount &vbLf& "New: " &_
                            intNewCount &vbLf&sDivider&vbLf& sReportChanges &vbLf
 
            ' Verify if there were any changes in the count for ClassName
            If intObjectCount <> intNewCount Then
                intWait = 0
                intObjectCount = intNewCount
            Else
                intWait = intWait + 1
            End If
            Wait(1)
        Loop Until intWait = StatusSync
 
        Reporter.ReportEvent micInfo, "Sync Objects", sReportChanges
    End Sub    
 
    '—————————————————————————————————————————
    ' Name: SetBrowser (Public)
    ' 
    ' Purpose: Set the browser in which the objects count is being searched for
    ' 
    ' Parameters:
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Public Sub SetBrowser( sBrowserName )
    '—————————————————————————————————————————
        Set Me.oBrowser = oLocalDict.Item( sBrowserName )
    End Sub    
 
    '—————————————————————————————————————————
    ' Name: RemoveObject (Public)
    ' 
    ' Purpose: Remove object from collection
    ' 
    ' Parameters:
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Public Sub RemoveObject( sObjectName )
    '—————————————————————————————————————————
        If oLocalDict.Exists(sObjectName) Then
            oLocalDict.Remove(sObjectName)
        End If
    End Sub
 
    '—————————————————————————————————————————
    ' Name: DestroyDict (Public)
    ' 
    ' Purpose: Releases Dictionary
    ' 
    ' Parameters:
    ' 
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Public Sub DestroyDict
    '—————————————————————————————————————————
        oLocalDict.RemoveAll
        Set oLocalDict = Nothing
        Set oGlobalDict = Nothing
    End Sub
 
    '—————————————————————————————————————————
    ' Name: CountObjects (Private)
    ' 
    ' Purpose: Internal Function to retrieve visible object count
    ' 
    ' Parameters: 
    ' 
    ' Return:
    '    Integer
    '   
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Private Function CountObjects
    '—————————————————————————————————————————
        Dim pDesc: Set pDesc = Description.Create
        pDesc( "micclass" ).Value = sClass
 
        '* Get all objects with micClass = sClass
        CountObjects = oBrowser.Page("micclass:=Page").ChildObjects(pDesc).Count
 
        '* Get only visible objects
        pDesc( "x" ).Value = 0
        CountObjects = CountObjects - oBrowser.Page("micclass:=Page").ChildObjects(pDesc).Count
    End Function
 
    '—————————————————————————————————————————
    ' Name: GetTableText (Private)
    ' 
    ' Purpose: Retrieves the innertext of the table
    ' 
    ' Parameters:
    ' 
    ' Return:
    '    String
    '
    ' Author: 
    ' 
    ' Date: 
    '—————————————————————————————————————————
    Private Function GetTableText
    '—————————————————————————————————————————
        Reporter.Filter = rfDisableAll
        On Error Resume Next
            oTable.Init
            GetTableText = oTable.object.innerText
 
            If Err.Number <> 0 Then
                Err.Clear
            End If
        On Error Goto 0
        Reporter.Filter = rfEnableAll
    End Function
 
End Class
 
Set Ajax = New clsAjaxSync
 
Public Function AjaxUtil
    Set AjaxUtil = Ajax
End Function

I hope you find this useful.

References

  1. Singleton Pattern, by Yaron Assa
  2. Microsoft Developer Networks – Implementing Singleton in C#

If you have any questions, please ask them in the comments section. If your query is confidential, please use the Contact Form to send me an e-mail instead.

Subscribe to Relevant Codes (by Anshoo Arora)

Hello! We're always posting interesting articles on Relevant Codes. Why not subscribe so you don't miss out?

Leave a Comment

{ 27 comments… read them below or add one }

nishanth April 16, 2012 at 1:54 pm

Hi Anshoo,

You are referring to a webtable in the code above. I am using qtp 11 and I dont find any webtable in that page using object spy.
Am I wrong somewhere or has the application changed?

Reply

Anshoo Arora April 18, 2012 at 9:22 am

Nishanth, this is a very old article and I am in the process of updating it. This approach is quite outdated and there is a much simpler way that requires less than 10 lines of code. I have a few more article left before I get to this though, but I plan to do this by the end of this month.

For your query though, the site must’ve changed which is why you do not see WebTables..

Reply

Shelma Joseph February 17, 2012 at 6:27 am

Hi Anshoo,

I am working with a Java web application in Spring and EJB 3 platforms.
They are planning to implement AJAX technology in future.
I have seen the QTP 11 supports AJAX and have ASP.Net AJAX add in under web.
I want to know that that add in can be used for Java application and whether it works fine with QTP 11.
Please reply.

Regards,
Shelma

Reply

Anshoo Arora March 15, 2012 at 6:48 am

Shelma, if you’re wondering about compatibility and it being a Web app, there shouldn’t be an issue.

Reply

sudhakar May 4, 2011 at 10:12 am

Hi Anshoo
I am working on a web Application which makes Ajax calls, I am trying to use descriptive programming and trying to read some dynamic text, QTP is not able to recognize no matter the number of unique properties I use. I asked the developer and he said when I click on couple of twisties(to read the text) the application makes Ajax calls and also no matter how much wait time I use it does not help. Finally I came across your code and I get a message ‘Object Required’ which I am unable to figure out.
When I spy I see only web elements but no Tables as I was told the developers use templates to create the UI fields.

I am trying to figure out how I can read this text. Can you please give me your thoughts – Thanks

Reply

sudhakar May 4, 2011 at 10:11 am

Hi Anshoo
I am working on a web Application which makes Ajax calls, I am trying to use descriptive programming and trying to read some dynamic text, QTP is not able to recognize no matter the number of unique properties I use. I asked the developer and he said when I click on couple of twisties(to read the text) the application makes Ajax calls and also no matter how much wait time I use it does not help. Finally I came across your code and I get a message ‘Object Required’ which I am unable to figure out.
When I spy I see only web elements but no Tables as I was told the developers use templates to create the UI fields.

I am trying to figure out how I can read this text. Can you please give me your thoughts – Thanks

Reply

Anshoo Arora May 19, 2011 at 7:23 pm

Sudhakar, a snapshot of the UI and the Object Spy will be helpful..

Reply

Monika March 14, 2011 at 11:57 am

Hi Anshoo,

I am working on a website and recently due to .Net 4 adaptation one of the page does not load. In the status bar it says one item remaining and that status stays there. I would really appreciate some help here.

Thanks,
Monika

Reply

Srinivas March 2, 2011 at 2:27 pm

Hi,
Can any one throw some lite on interacting with TO properties. In my Case i need to interact with the webtable results which is having different states and the final state is complete. Though the page and other objects on the webpage are loading completely the webtable is still in loading condition. I need to interact with this webtable after its loaded completely. how to check this. i tried to use exists(), wait() and also tried to check other properties which are useless for my situation. Please help me asap.

Reply

Jiten March 2, 2011 at 3:24 pm

Hi Srini,
though your question is not very clear , if you could post some more details
http://www.advancedqtp.com/knowledge-base/articles/qtp-tricks4/qtp-hacks/override-the-object-exist-property-with-registeruserfunc/
you can also query the readyState Runtime object property using
Brow.Page.webtable.object.readystate…
Please see if you are able to access the native properties of objects in ur app.
happy testing !
jiten

Reply

Govardhan December 21, 2010 at 2:34 am

We have a web application which we need to automate with QTP 9.5. We have added some object in Object Repository and created script accordingly. If we highlight the added objects in Object Repository, those are identifying well in the application.

We have some webedit and WebList and webButton controls in the application. While running the QTP Script, it will enter the value in the first WebEdit box and it goes fail to identify second edit box (or any other object). And sometimes script will run till 5-6 web controls and unable to recognize next immediate control.

I have gone the source code and found that some AJAX code has embedded in the source code. Whenever we try to enter some value in the webedit box it shows “Loading content please wait” message. So we have implemented IE browser readyState 4 (or busy) concept, but still we are unable to run the script completely.

But we are able to highlight the objects through object repository without entering any values in the application.

Reply

SRI December 6, 2010 at 1:40 pm

Hi Anshoo,

Great that you are putting great efforts and time to share a knowledge with the world.Kudos.Keep Going.
Recently I’m working on DODO Toolkit controls.

Working on QTP 10.0 Version and Installed Web 2.0 add-in
Unable to select a value in DojoFilterComboBox.
when try to set ,getting the error Object is null or not found.

Can you help me.

Sri

Reply

Anshoo Arora December 19, 2010 at 7:13 pm

SRI,

I’m currently working with an application that employs both DOJO and GWT – automating both technologies without the use of the Web 2.0 add-in. Its one of those items that have been pending in my list and much research needs to be done. Btw, does ‘Select’ work?

Reply

venkat October 13, 2010 at 1:08 am

Hi Anshu,

In my organization we use rich amount flex and flash components for development of RIA applications. The applications are built using Flex Builder (and contains code of Action Script 2 and 3 versions). Now we are in the process of automating those applications using QTP.

We can automate some part of application where it uses only Flex components. But our application uses some third party controls like Fusion charts and ExtJS components in the flash applications. At this point in time the Adobe add-in for QTP does not facilitate in recognizing the components. It just treats every object as ‘WebElement’ (QTP’s generic detection) which does not allow me to script on specific object.

I came across the Web Extensibility feature provided by the QTP. It’s really awesome the way QTP has given flexibility to extend their current functionality. But it do does not serve my problem.

I tried few of the examples and successfully extended the capabilities of QTP to recognize some of the web toolkits components (I tried DOJO Progressbar control).

Few questions for me regarding QTP’s Support:

1)Will it be possible to extend functionality of QTP in recognizing the flash components apart from the custom web controls or is there any other way.

2)Are there any plug-ins (add-ins) from QTP to support those controls(Fusion Charts)

I will very much thankful to you if you can guide me in this aspect.

Thanks,
Venkat

Reply

Animesh September 12, 2010 at 6:13 am

Hi Anshoo,
I have read this article…and as per me, this is one of the best article on automate Ajax.This is good for experienced as well as freshers. Really nice. I have referred this link for synchronization
http://askqtp.blogspot.com/2010/09/synchronization-in-qtp.html
Please let me know if you are updating your ajax syncronization part

Regards,
Animesh

Reply

Anshoo Arora September 29, 2010 at 2:43 pm

Hi Animesh,

Thank you for your kind words. This article is quite old and was written as a workaround before HP introduced the Web 2.0 Extensibility package. I don’t intend to write a follow up on this anytime soon as there is very little we can do with VBScript out-of-the-box to handle such issues.

Reply

Eshwari August 11, 2010 at 1:08 am

Hi Anshoo,
Thank you for the utility that you have provided for using Ajax controls. Could you please help me in using the same Ajax controls/DOJO controls with QTP Web 2.0 Extensibility Accelerator as well. I am able to recognize the controls as Dojo controls with this Add-In, but didn’t find any clue in using them programmatically in QTP.

Reply

Anshoo Arora August 11, 2010 at 3:22 pm

Eshwari,

I still need to learn to configure and use the Web 2.0 Accelerator :)

I’ve done some automation with Dojo toolkit without its Extensibility support, and I could automate a lot by using mostly DOM. Maybe you can share some techniques you can used with us? I would love to share your findings with the readers.

Reply

Sunil July 17, 2010 at 9:33 am

Hi Anshoo,

I was wondering if I need to install ajax addin for your sample code.

Sunil

Reply

Anshoo Arora July 30, 2010 at 8:42 am

Sunil,

Please see here. There is no AJAX add-in in particular, but you can use the Web 2.0 extension instead.

Reply

Jiten April 17, 2010 at 2:26 am

Thanks Anshoo… This example would help me a lot in solving synchronisation problem in current project.
I would use it with your reference… thanks.

I have always found advanced qtp guyz going ahead in time, and help us with innovations like these.

Jiten

Reply

Anshoo Arora April 17, 2010 at 10:53 am

Thanks, Jiten for your kind words. But, please note that this approach may not prove to be very helpful if you’re using a custom toolkit.

Reply

ramani April 14, 2010 at 1:45 pm

Hello Sir,

I have used above code in my script. But it is giving error “Object required” on the line AjaxUtil.AddObject “MyBrowser1″, Browser(“title:=Cheap Flights.*”)

Here is the line after I changed it to my application : AjaxUtil.AddObject “MyBrowser”, Browser(” mic:”)

Any help is appreciated on this issue.
Thanks

Reply

Anshoo Arora April 14, 2010 at 3:30 pm

Ramani,

This approach may not prove to be very helpful if you’re using a custom toolkit.

To answer your question though, have you associated the AjaxUtil class with your test?

Reply

Vishal Singh April 11, 2010 at 6:41 pm

Hi Sir,
Please can you send me a QTP framework where i can write scripte and can prepare data sheet.
I want this for Understanding the QTP Framework
Email ID: vishal04061986@gmail.com
Thanks & Regards
Vishal Singh

Reply

Polprav October 16, 2009 at 12:04 pm

Hello from Russia!
Can I quote a post in your blog with the link to you?

Reply

Anshoo Arora October 16, 2009 at 6:57 pm

Sure. Thank you.

Reply

Previous post:

Next post: