Quantcast
Channel: Relevant Codes » QTP/Web
Viewing all 10 articles
Browse latest View live

QTP – Testing Multiple Browser Applications

$
0
0

Web applications due to their dynamic nature, make script development quite challenging. I am writing this article in an attempt to simplify one of its aspects that automation developers face while working with Web applications. We will see how QTP can be used to automation multiple browsers with the use of a Dictionary object, to which we can add Browsers, remove them, change the way we reference them and much more.

You will notice in the examples at the end of this article that, regardless of how many pages we navigate, we would never have to keep a track of changing properties. In other words, regardless of browser navigation and actions performed on each browser, this concept will help use the name we give them to work with them, instead of following their ever-changing properties.

Let’s begin by creating a global variable, that will hold the Browser Collection to be accessed by our class:

'Public Variable: Holds Browser Collection
Public colBrowser

Another reason to create a global variable is that as long as it is an object, it can be used as a reference by (local) class variables, thus being over-written as many number of times as we want. Next, we will create a Browser class, that will make use of the global variable (as a reference) we declared above:

Class clsBrowser
 
End Class

To ensure that we are not creating a new object each time our class initiates, we must create a Singleton, which will be stored in the initialization procedure of our class. It will also assure us that our code is highly efficient and our global variable is created only once, and not destroyed unless required.

' Purpose: Initializes the Scripting.Dictionary Singleton
Private Sub Class_Initialize
    Dim bInit: bInit = False        
 
    ' If colBrowser has already been instantiated, then Init = True
    If IsObject(colBrowser) Then
        If Not colBrowser Is Nothing Then
            bInit = True
        End If
    End If
 
    ' If colBrowser was destroyed or has not yet instantiated, then create it
    If bInit = False Then Set colBrowser = CreateObject("Scripting.Dictionary")
 
    ' colObject (local) acts as a reference to colBrowser
    colObject = colBrowser
End Sub

Above, colObject is a reference to our Global Collection object colBrowser.

Instead of creating a new object each time, we will reuse the same reference to add all the necessary Browsers. To add browsers to our collection, let’s create a simple method called “AddBrowser” and a public property “HWND”, that will store the Windows Handle of the Browser:

' Purpose: Adds Browsers and their HWNDs to a Collection
Sub AddBrowser(sName)
    ' If the Name already exists in the collection, then remove it so it can be re-added
    If colObject.Exists(sName) Then
        colObject.Remove sName
        colObject.Remove sName & "-HWND"
    End If
 
    ' Add the Browser with its corresponding handle
    ' Store the Handle Property
    With colObject            
        .Add sName, Browser("hwnd:=" & Me.HWND)
        .Add sName & "-HWND", Me.HWND
    End With
End Sub
 
Private Handle
 
' Purpose: Stores the Browser Handle
Public Property Let HWND(ByVal Val)
    Handle = val   
End Property
Public Property Get HWND()
    HWND = Handle   
End Property

AddUsingCreationTime

To provide ourselves with more options to add browsers, let’s create 3 more methods: AddUsingCreationTime, AddUsingTitle and AddLastOpen. As the name suggests, AddUsingCreationTime will enable us to add the browser in our collection object using its creationtime:

' Purpose: Uses the "AddBrowser" method to add browsers to the collection 
' using their CreationTime Property
Public Sub AddUsingCreationTime(sName, intCreationTime)
    Dim oBrowser, oCol
 
    ' Description object for Browser Class
    Set oBrowser = Description.Create
    oBrowser("micclass").Value = "Browser"        
 
    ' ChildObjects of Browser Class Description
    Set oCol = Desktop.ChildObjects(oBrowser)
 
    'If the supplied CreationTime is greater than the total number of open browsers, 
        'then Report Err.
    If intVal > oCol.Count Then
        Reporter.ReportEvent micWarning, "Add Browser Using CreationTime", "Browser " & _
                "with CreationTime " &intCreationTime& " was not found."
        Exit Sub
    End If
 
    ' Store the Browser Handle
    Me.HWND = Browser("creationtime:=" & intCreationTime).GetROProperty("HWND")
 
    ' Add the browser to the collection
    AddBrowser sName
End Sub

AddUsingTitle

Similarly, AddUsingTitle will enable us to store a Browser if we prefer using Browser’s Title:

' Purpose: Uses the "AddBrowser" method to add browsers to the collection 
' using their Title Property
Public Sub AddUsingTitle(sName, sTitle)
    ' Verify if the browser with the supplied title exists
    If Not Browser("title:=" & sTitle).Exist(1) Then
        Reporter.ReportEvent micWarning, "Add Browser Using Title", "Browser " & _
                "with Title " &sTitle& " was not found."
        Exit Sub
    End If
 
    ' Store the Browser Handle
    Me.HWND = Browser("title:=" & sTitle).GetROProperty("HWND")
 
    ' Add the browser to the collection
    AddBrowser sName
End Sub

AddLastOpen

Lastly, for greater flexibility, we will create another method, AddLastOpen, which as the name suggests, will add only the most current browser to our collection:

' Purpose: Uses the "AddBrowser" method to add the last (most recent) open browser
'    Note: The last open browser always has the greatest CreationTime
Public Sub AddLastOpen(sName)
    Dim oBrowser, oCol
 
    ' Description object for Browser Class
    Set oBrowser = Description.Create
    oBrowser("micclass").Value = "Browser"        
 
    ' ChildObjects of Browser Class Description
    Set oCol = Desktop.ChildObjects(oBrowser)
 
    ' Store the Browser Handle
    Me.HWND = Browser("creationtime:=" & oCol.Count - 1).GetROProperty("HWND")
 
    ' Add the browser to the collection
    AddBrowser sName
End Sub

To simplify calling of objects, we will use the names we give to each browser. Instead of using .item, we can use .Name which is more descriptive. This part can be omitted, but for the sake of completion, let’s create this method anyways:

Public Function Name(Key)
    Dim Keys
 
    Keys = colObject.Keys
 
    If IsNumeric(Key) Then
        Key = Keys(Key)
    End If
 
    If IsObject(colObject.Item(Key)) Then
        Set Name = colObject.Item(Key)
    Else
        Name = colObject.Item(Key)
    End If
End Function

Finally, we must create an instance of the object, that will enable us to call class methods:

' Create a new instance of Class clsBrowser
Set BrowserObject = New clsBrowser

We’re done! You can download the class here, or view the text version here

Demonstration: AddUsingCreationTime

As a demonstration, you can associate (or ExecuteFile) the library and run the following lines of code:

SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com", "", "", 3 : Wait(4)
'Add the First open browser (creationtime=0) to the collection
BrowserObject.AddUsingCreationTime "DemoAUT", 0
 
SystemUtil.Run "iexplore.exe", "http://relevantcodes.com", "", "", 3 : Wait(4)
'Add the Second open browser (creationtime=1) to the collection
BrowserObject.AddUsingCreationTime "RelevantCodes", 1
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("DemoAUT")
    .WebEdit("name:=userName").Set "test"
    .WebEdit("name:=password").Set "test"
    .Image("name:=login").Click
 
    .Sync
 
    If .WebList("name:=fromPort").Exist(10) Then
        .WebList("name:=fromPort").Select "Frankfurt"
        .WebList("name:=fromMonth").Select "December"
        .WebList("name:=toPort").Select "Paris"
        .WebList("name:=toMonth").Select "December"
        .WebRadioGroup("name:=servClass").Select "#1"
        .WebList("name:=airline").Select "Unified Airlines"
        .Image("name:=findFlights").Click
    End If
End with
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("RelevantCodes")
    .Link("text:=Articles", "index:=0").Click
    .Link("text:=Home", "index:=0").Click
    .Link("text:=QTP\/Web", "index:=0").Click
End with
 
With BrowserObject
    .Name("DemoAUT").Close
    .Name("RelevantCodes").Close
End with
 
'Release
BrowserObject.Destroy

Demonstration: AddUsingTitle

As stated earlier, this method will store any browser with the provided title.

SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com", "", "", 3 : Wait(4)
'Add the above open browser using its title
BrowserObject.AddUsingTitle "DemoAUT", ".*Mercury Tours.*"
 
SystemUtil.Run "iexplore.exe", "http://relevantcodes.com", "", "", 3 : Wait(4)
'Add the above open browser using its title
BrowserObject.AddUsingTitle "RelevantCodes", ".*Relevant Codes.*"
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("DemoAUT")
    .WebEdit("name:=userName").Set "test"
    .WebEdit("name:=password").Set "test"
    .Image("name:=login").Click
 
    .Sync
 
    If .WebList("name:=fromPort").Exist(10) Then
        .WebList("name:=fromPort").Select "Frankfurt"
        .WebList("name:=fromMonth").Select "December"
        .WebList("name:=toPort").Select "Paris"
        .WebList("name:=toMonth").Select "December"
        .WebRadioGroup("name:=servClass").Select "#1"
        .WebList("name:=airline").Select "Unified Airlines"
        .Image("name:=findFlights").Click
    End If
End with
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("RelevantCodes")
    .Link("text:=Articles", "index:=0").Click
    .Link("text:=Home", "index:=0").Click
    .Link("text:=QTP\/Web", "index:=0").Click
End with
 
With BrowserObject
    .Name("DemoAUT").Close
    .Name("RelevantCodes").Close
End with
 
'Release
BrowserObject.Destroy

Demonstration: AddLastOpen

As stated earlier, this method will add the last open browser to the global browser collection.

SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com", "", "", 3 : Wait(4)
'Add the last open browser to the collection
BrowserObject.AddLastOpen "DemoAUT"
 
SystemUtil.Run "iexplore.exe", "http://relevantcodes.com", "", "", 3 : Wait(4)
'Add the last open browser to the collection
BrowserObject.AddLastOpen "RelevantCodes"
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("DemoAUT")
    .WebEdit("name:=userName").Set "test"
    .WebEdit("name:=password").Set "test"
    .Image("name:=login").Click
 
    .Sync
 
    If .WebList("name:=fromPort").Exist(10) Then
        .WebList("name:=fromPort").Select "Frankfurt"
        .WebList("name:=fromMonth").Select "December"
        .WebList("name:=toPort").Select "Paris"
        .WebList("name:=toMonth").Select "December"
        .WebRadioGroup("name:=servClass").Select "#1"
        .WebList("name:=airline").Select "Unified Airlines"
        .Image("name:=findFlights").Click
    End If
End with
 
'Use the names we gave the browser, and use the same name regardless of changes in its properties
With BrowserObject.Name("RelevantCodes")
    .Link("text:=Articles", "index:=0").Click
    .Link("text:=Home", "index:=0").Click
    .Link("text:=QTP\/Web", "index:=0").Click
End with
 
With BrowserObject
    .Name("DemoAUT").Close
    .Name("RelevantCodes").Close
End with
 
'Release
BrowserObject.Destroy

Notice the demos above. We only have to use the custom name we gave to the browser to perform events on the objects that exist inside of it. Our custom names can be used throughout the automation cycle, but I would recommend you to look into the “ChangeName” method available in the class. This would make object naming easier, and more descriptive, as the titles change the moment we navigate to another page.

Download clsBrowser | View as Plain Text | Download Demo Test QTP9.2 | Download Demo Test QTP9.5


QTP – Get Link’s Mouse Over Color

$
0
0

This post describes a simple technique that can enable retrieval of a Link’s Mouse Over (onMouseOver) color. The only trick is to change the ReplayType setting to Mouse Events while firing an onMouseOver event on the link. Changing the event cause an actual FireEvent action, that you would encounter when you hover the mouse on the link manually.

Below, you will see that the hover event is triggered with the ReplayType set to Mouse Events:

Setting.WebPackage("ReplayType") = 2
Browser("Browser").Link("Link").FireEvent "onMouseOver"
MsgBox Browser("Browser").Link("Link").Object.currentStyle.color
Setting.WebPackage("ReplayType") = 1

The above snippet can be simplified and be reused using the function below:

Function GetHoverColor(oLink)
    Setting.WebPackage("ReplayType") = 2
        oLink.FireEvent "onMouseOver"
        GetHoverColor = oLink.Object.currentStyle.color
    Setting.WebPackage("ReplayType") = 1
End Function
 
RegisterUserFunc "Link", "GetHoverColor", "GetHoverColor"

Now, whenever the link color is to be retrieved, you can simply call the “GetHoverColor” function as you would normally use the Click event:

MsgBox Browser("Browser").Page("Page").Link("Link").GetHoverColor

I hope you find this useful.

QTP – Browser’s Activate Maximize Minimize

$
0
0

This article demonstrates a quick tip to activate, minimize or maximize browsers. Unlike a Standard Windows Window object, Browser does not support the Activate, Minimize, Maximize methods. Therefore, we can create our custom function and tie it with the Browser object using RegisterUserFunc.

The only trick is to retrieve the Browser Handle and substitute the handle in the description of a Window object, and use the Window’s Activate method instead.

Activate Browser
Function BrowserActivate(Object)
    Dim hWnd
 
    hWnd = Object.GetROProperty("hwnd")
 
    On Error Resume Next
        Window("hwnd:=" & hWnd).Activate
 
        If Err.Number <> 0 Then
            Window("hwnd:=" & Browser("hwnd:=" & hWnd).Object.hWnd).Activate
            Err.Clear
        End If
    On Error Goto 0
End Function
 
RegisterUserFunc "Browser", "Activate", "BrowserActivate"

After registering the BrowserActivate function with the Browser object as Activate we can use it just like we would use it for a Window object:

Browser("title:=Relevant Codes.*").Activate

BrowserActivate can be extended to maximize and minimize a browser window as well. The only extra statement to be included in the function would be the maximize and minimize methods of the window object.

Minimize Browsers
Function BrowserMinimize(Object)
    Dim hWnd
 
    hWnd = Object.GetROProperty("hwnd")
 
    On Error Resume Next
        Window("hwnd:=" & hWnd).Activate
 
        If Err.Number <> 0 Then
            hWnd = Browser("hwnd:=" & hWnd).Object.hWnd
            Window("hwnd:=" & hWnd).Activate
            Err.Clear
        End If
 
        Window("hwnd:=" & hWnd).Minimize
    On Error Goto 0
End Function
 
RegisterUserFunc "Browser", "Minimize", "BrowserMinimize"
Maximize Browsers
Function BrowserMaximize(Object)
    Dim hWnd
 
    hWnd = Object.GetROProperty("hwnd")
 
    On Error Resume Next
        Window("hwnd:=" & hWnd).Activate
 
        If Err.Number <> 0 Then
            hWnd = Browser("hwnd:=" & hWnd).Object.hWnd
            Window("hwnd:=" & hWnd).Activate
            Err.Clear
        End If
 
        Window("hwnd:=" & hWnd).Maximize
    On Error Goto 0
End Function
 
RegisterUserFunc "Browser", "Maximize", "BrowserMaximize"

If you would like to use the above 3 methods through a single function or class, they can be coupled together through Execute statements or through If-Then or Switch-Case blocks. Happy reading!

QTP – Automating Gmail

$
0
0

This article is a tutorial to show how parts of Gmail can be automated using QTP. Gmail is an extremely dynamic UI and always quite challenging to automate successfully. Its dynamic behavior also makes it an excellent candidate to practice QTP with and sharpen your skills. I will try to show a few techniques that can be helpful in automating Gmail, and through it, automating any dynamic application that you encounter.

Gmail Login

I’m sure everyone who has worked with Gmail would have already created this part of the script and chances are that it would have been created as a function. The same has been done here with the help of conditional statements:

Function GmailLogin(sUserName, sPassword)
    GmailLogin = False
 
    With Browser("title:=Gmail.*").Page("micclass:=Page")
        'Check if the UserName field exists
        If .WebEdit("html id:=Email").Exist(0) Then
            .WebEdit("html id:=Email").Set sUserName    'Set UserName
            .WebEdit("html id:=Passwd").SetSecure sPassword    'Set Password
            .WebButton("name:=Sign in").Click        'Click Submit
            .Sync
        End If
 
        'Check for Link Inbox(xyz)
        If .Link("innertext:=Inbox.*").Exist(15) Then GMailLogin = True
    End With
End Function
 
'Usage 1:
MsgBox GmailLogin("yourUserName", "yourPassword")
 
'Usage 2:
If GmailLogin("yourUserName", "yourPassword") = True Then
    'Continue with test
Else
    'Stop
End If

Sign Out of Gmail

No tricks here. A simple inline DP or OR statement would accomplish Signing out of Gmail:

Browser("title:=Gmail.*").Page("micclass:=Page").Link("innertext:=Sign Out").Click
 
'Update March 15, 2011:  The Gmail interface has changed slightly. 
'If the above does not work, please try this:
Browser("title:=Gmail.*").Page("micclass:=Page").Link("innertext:=Sign Out", "class:=gbml1").Click

Get New Email Count

Each automation developer prefers a different approach of retrieving desired values from blocks or text. For each task which requires a value to be retrieved, 3 techniques are demonstrated for the retrieval of expected values: Split, RegExp and Left/Right. But first, we must retrieve the entire string containing the number of Unread emails:

Unread Emails

Retrieve ‘Inbox (3)’
sLink = Browser("title:=Gmail.*").Page("title:=Gmail.*").Link("innertext:=Inbox.*")_
    .GetROProperty("innertext")

Once the string containing the number of unread e-mails is retrieved, one of the following approaches can be used to produce the same result:

Split
iEmails = Split(sLink, " ")(1) '(3)
iEmails = Replace(iEmails, "(", "") '3)
iEmails = Replace(iEmails, ")", "") '3
Print iEmails
RegExp
'Updated 03/12/2012
Set oRegExp = New RegExp
oRegExp.Global = True
oRegExp.Pattern = "\d+"
Set oMatches = oRegExp.Execute(sLink) 'oMatches(0) = 3
iEmails = oMatches(0)
If oMatches.Count = 2 Then iEmails = iEmails & "" & oMatches(1)
Print iEmails
Left, Right
iPosition = InStr(1, sLink, "(")
iEmails = Right(sLink, Len(sLink) - iPosition) '3
iEmails = Left(iEmails, Len(iEmails) - 1)
Print iEmails

Get Total Emails Count

Unlike the scenario above, which retrieved the number of unread e-mails in the AUT, this section shows how the total number of e-mails can be retrieved. Just like the previous scenario, a simple inline DP statement can be used to retrieve the number string that contains the value we are looking for:

Total Emails

Retrieve ’1 – 4 of 4′
'Updated 03/15/2012
sText = Browser("title:=Gmail.*").Page("title:=Gmail.*")_
    .WebElement("innertext:=\d+–\d+ of \d+.*", "index:=0").GetROProperty("innertext")
 
'Alternate:
sText = Browser("title:=Gmail.*").Page("title:=Gmail.*")_
    .WebElement("class:=J-J5-Ji amH J-JN-I").GetROProperty("innertext")

After retrieving the entire string, one of the following approaches can be used to produce the result:

Split
iEmails = Split(sText, "of")(1) ' 4
iEmails = Split(iEmails, " ")(1) '4
Print iEmails
RegExp
'Updated 03/12/2012
Set oRegExp = New RegExp
oRegExp.Global = True
oRegExp.Pattern = "of .*"
Set oMatches = oRegExp.Execute(sText)
sMatch = oMatches(oMatches.Count - 1)
 
oRegExp.Pattern = "\d+"
Set oMatches = oRegExp.Execute(sMatch)
iEmails = oMatches(0)
If oMatches.Count = 2 Then iEmails = iEmails & "" & oMatches(1)
Print iEmails
Left, Right
iLoc_Of = InStr(1, sText, "of")
iTotals = Right(sText, Len(sText) - iLoc_Of - 1)
iTotals = Trim(iTotals)
Print iTotals

Space Used by Emails

One important, and a little complex (in comparison to the above scenarios) one: retrieving the space used by Emails. The process will remain the same, but notice the usage of the wild card character for the WebElement:

Space Used

Retrieve ‘You are currently using 0 MB (0%) of your 7430 MB.’
'Updated 03/15/2012
sText = Browser("title:=Gmail.*").Page("title:=Gmail.*")_
    .WebElement("innertext:=.*Using.*of your.*", "index:=0")_
    .GetROProperty("innertext")

The above inline DP statement will retrieve and store the entire string with sText. Once executed, one of the following methods can be used to retrieve the result:

Split
iSpace = Trim(Split(sText, "Using")(1))
iSpace = Split(iSpace, " ")(0) '0
Print iSpace
RegExp
'Updated 03/12/2012
Set oRegExp = New RegExp
oRegExp.Pattern = "\d+ MB"
Set oMatches = oRegExp.Execute(sText)
iSpace = oMatches(0)
Print iSpace
Left, Right
iLoc_MB = InStr(1, sText, "MB")
sText = Trim(Left(sText, iLoc_MB - 1)) 'You are currently using xx
iSpace = Right(sText, Len(sText) - InStrRev(sText, " ")) '0
Print iSpace

Gmail Auto-Generated Response Message

If you would like to check the existence of any of the messages as shown below, accessing the class of the Element will suffice to retrieve the entire text and verify it against our expected result.

Message Sent
Mark Spam
Send to Trash
Undo Spam

Out of the numerous ways these messages could be checked, I am going to show 2 possible uses with a description object and an inline DP statement.

Inline DP
Browser("title:=Gmail.*").Page("micclass:=Page")_
    .WebElement("class:=vh", "html tag:=TD", "index:=0").GetROProperty("innertext")
Description Object + ChildObjects
Dim oDesc, colObject
 
Set oDesc = Description.Create
oDesc("micclass").Value = "WebElement"
oDesc("class").Value = "vh"
 
Set colObject = Browser("title:=Gmail.*").Page("micclass:=Page").ChildObjects(oDesc)
 
MsgBox colObject(0).GetROProperty("innertext")

Finding Row with Containing Text

To find an e-mail row using text, we can either create a custom function or use the GetRowWithCellText method of the WebTable. However, chances are that the custom function will not prove to be quite as fast. A custom function has been created to find the row containing the specified text:

Custom Function
Function FindMailRow(sText)
    Dim oTable, iRows, ix
 
    FindMailRow = -1
 
    With Browser("title:=Gmail.*").Page("micclass:=Page").WebTable("class:=F cf zt")
        iRows = .GetROProperty("rows")
 
        For ix = 1 to iRows
            sMailText = .GetCellData(ix, 3) & .GetCellData(ix, 5) & .GetCellData(ix, 7)
            If InStr(1, LCase(Replace(sMailText, vbLf, " ")), LCase(sText)) Then
                FindMailRow = ix
                Exit Function
            End If
        Next
    End With
End Function
 
'Usage:
MsgBox FindMailRow("Text")

The outcome will be the same when using the GetRowWithCellText method, but with a smaller performance footprint.

GetRowWithCellText
MsgBox Browser("title:=Gmail.*").Page("micclass:=Page").WebTable("class:=F cf zt")_
    .GetRowWithCellText("Redefining")

The custom function took 2.45 seconds to find the row whereas GetRowWithCellText took only 1.22 seconds.

Reading Emails

The above method can be coupled with a click event to find and open the e-mail that is to be read. A simple inline DP statement can be used to click the target row and open the e-mail. In this example, we’re going to click on the 2nd Email:

'Updated 03/12/2012
'I have used 'Access Gmail' but you can use any (unique) text on that row
iRow = Browser("title:=Gmail.*").Page("micclass:=Page").WebTable("class:=F cf zt")_
    .GetRowWithCellText("Access Gmail")
 
With Browser("title:=Gmail.*").Page("micclass:=Page").WebTable("class:=F cf zt")
    Setting.WebPackage("ReplayType") = 2
        .ChildItem(iRow, 5, "WebElement", 0).Click
    Setting.WebPackage("ReplayType") = 1
End With

When the row is clicked, the Email is opened for reading:

Row 2: Access Gmail

Compose

This can be tricky. Breaking down each component below:

Clicking Compose
Setting.WebPackage("ReplayType") = 2
    Browser("title:=Gmail.*").WebElement("innertext:=COMPOSE", "index:=1").Click
Setting.WebPackage("ReplayType") = 1
Recipient, Subject, Body
With Browser("title:=Gmail.*")
    .WebEdit("html id:=:1b6").Set "test@test.com" 'Recipient
    .WebEdit("html id:=:1c9").Set "Subject" 'Subject
    .WebElement("html id:=:1cl", "index:=1").Object.innerText = "Message Body" 'Body
End With
Click Send
Setting.WebPackage("ReplayType") = 2
    Browser("title:=Gmail.*").WebElement("html id:=:1d3", "index:=1").Click
Setting.WebPackage("ReplayType") = 1

I hope this article provides more in-depth knowledge of testing complex Web applications. I hope to find more such applications in the future to share with everyone. If you feel there is a scenario that this article lacks, or will become more useful with the addition of one, please do let me know.

QTP – Regular Expressions for Select Method (ListBox)

$
0
0

This post describes a few ways to use Regular Expressions to select the target item from List objects. All examples of this post demonstrate techniques to be used in Web Applications, but they can be easily extended to technologies that store all list items with delimiters.

Regex Select Using QTP Methods

The below method uses QTP’s technique of retrieving the all items property from the WebList. It also uses RegExp object, which means, regular expressions will be supported. If the pattern does not match the pattern or the exact string from the List, the first item will be selected by default. If the default selection does not fit your requirement, please feel free to modify the code as per your needs.

Function RegexSelectQTP(Object, sPattern)
	Dim oRegExp, arrAllItems, ix
 
	'Create RegExp Object
	Set oRegExp = New RegExp
	oRegExp.IgnoreCase = False
	oRegExp.Pattern = sPattern
 
	'Split Object's all_items property
	arrAllItems = Split(Object.GetROProperty("all items"), ";")
	For ix = LBound(arrAllItems) To UBound(arrAllItems)
		'If RegExp pattern matches list item, we're done!
		If oRegExp.Test(arrAllItems(ix)) Then
			Object.Select "#" &amp; ix
			Set oRegExp = Nothing
			Exit Function
		End If
	Next
 
	'Select Item #1 by default
	Object.Select "#0"
End Function
RegisterUserFunc "WebList", "RegexSelectQTP", "RegexSelectQTP"
Usage:
Browser("").Page("").WebList("").RegexSelectQTP "London - Heathrow" 'Select London-Heathrow
Browser("").Page("").WebList("").RegexSelectQTP "London - Heath.*"  'Select London-Heathrow
Browser("").Page("").WebList("").RegexSelectQTP "London - \D+"      'Select London-Heathrow

Regex Select Using DOM Methods

This is quite similar to above, but instead of using the all items property, it uses the HTML DOM options. In general, the HTML of a WebList is like this:

<select>
	<option>Acapulco</option>
	<option>London</option>
	<option>New York</option>
	<option>San Francisco</option>
</select>

The code below retrieves all the items within the option /option tag and loops through each to determine if there is a regexp match. Also, like the above method, if a match is not found, the first item in the list will be selected by default. Note: This method will not work for technologies other than Web.

Function RegexSelectDOM(Object, sPattern)
	Dim oRegExp, oOptions, ix
 
	'Create RegExp Object
	Set oRegExp = New RegExp
	oRegExp.IgnoreCase = False
	oRegExp.Pattern = sPattern
 
	'DOM options
	Set oOptions = Object.Object.Options
	For ix = 0 to oOptions.Length - 1
		'If RegExp pattern matches list item, we're done!
		If oRegExp.Test(oOptions(ix).Text) Then
			Object.Select "#" &amp; ix
			Set oRegExp = Nothing
			Exit Function
		End If
	Next
 
	'Select Item #1 by default
	Object.Select "#0"
End Function
RegisterUserFunc "WebList", "RegexSelectDOM", "RegexSelectDOM"
Usage:
Browser("").Page("").WebList("").RegexSelectDOM "London - Heathrow" 'Select London-Heathrow
Browser("").Page("").WebList("").RegexSelectDOM "London - Heath.*"  'Select London-Heathrow
Browser("").Page("").WebList("").RegexSelectDOM "London - \D+"      'Select London-Heathrow

Select Using VBScript (InStr/Mid) Methods

This method does not support Regular Expressions as it is based on VBScript’s InStr and Mid methods. Instead, it parses the correct value depending upon the supplied complete or partial values without the regexp meta characters.

Public Function VBSSelect(Object, sString)
	Dim sAllItems, varLocation, varEnd, varBeginning
 
	'Retrieve Object's all_items property
	sAllItems = Object.GetROProperty("all items")
 
	'Verify if the supplied string is found in list's all_items property
	varLocation = InStr(1, sAllItems, sString)
	'If found:
	If varLocation &gt; 0 Then
        varEnd = InStr(varLocation, sAllItems, ";")
		If varEnd = 0 Then varEnd = Len(sAllItems) + 1
		varBeginning = InStrRev(sAllItems, ";", varLocation)
		Object.Select "" &amp; Mid(sAllItems, varBeginning + 1, varEnd - varBeginning - 1)
		Exit Function
	End If
 
	'Select Item #1 by default
	Object.Select "#0"
End Function
RegisterUserFunc "WebList", "VBSSelect", "VBSSelect"
Usage:
Browser("").Page("").WebList("").VBSSelect "London - Heathrow" 'Select London-Heathrow
Browser("").Page("").WebList("").VBSSelect "London - Heath"    'Select London-Heathrow
Browser("").Page("").WebList("").VBSSelect "London - "         'Select London-Heathrow

Performance Comparison

The above 3 methods were tested on QTP 10 against a Web Application with 500 iterations each on a Dell XPS M1210 Core2Duo 2.0GHz 3GB Laptop. The table below presents the average time taken by each method to successfully select a value from the WebList in QTP’s Normal and Fast run modes:

Performance Comparison between Select Methods
Run Mode Normal Fast
RegexSelectQTP 0.44 seconds 0.38 seconds
RegexSelectDOM 0.45 seconds 0.40 seconds
VBSSelect 0.39 seconds 0.35 seconds

QTP – Is Browser required in Object Hierarchy?

$
0
0

This has been tested to work correctly on QTP versions: 9.5+.

There is a common perception that we must include the Browser object in hierarchies when working in the Web environment. The truth is that, we really don’t need to include the Browser object if the Page object has been included in the hierarchy.

In other words, the commonly written inline statements for Web environment:

Browser("title:=Google").Page("title:=Google").WebEdit("name:=q").Set "Test"
Browser("title:=Google").WebEdit("name:=q").Set "Test"

can also be written like this:

Page("title:=Google").WebEdit("name:=q").Set "Test"

Quick tip! Thanks for visiting Relevant Codes! :)

QTP – Browser CreationTime

$
0
0

I’ve generally seen some confusion around CreationTime. I think between the 3 Ordinal Identifiers, this one may be the easiest to understand and implement. That’s mostly because CreationTime is used only for the Browser object. Below is how CreationTime is applied to browsers:

1st open browser -> CreationTime of -> 0
2nd open browser -> CreationTime of -> 1
3rd open browser -> CreationTime of -> 2
4th open browser -> CreationTime of -> 3

According to QTP help:

This value indicates the order in which the browser was opened relative to other open browsers. For example, if QuickTest learns three browsers that are opened at 9:01 pm, 9:03 pm, and 9:05 pm, QuickTest assigns the CreationTime values, as follows: CreationTime = 0 to the 9:01 am browser, CreationTime = 1 to the 9:03 am browser, and CreationTime = 2 to the 9:06 am browser.

Really, that’s it! No tricks here! To test it for proof, you can open 4 browsers (with different websites) and run the following code in QTP:

For ix = 0 to 3
	Print "CreationTime->" & ix & "->" & Browser("creationtime:=" & ix).GetROProperty("title")
Next

On my desktop, I’ve 4 open IE windows in the following order: Google, Bing, Yahoo, Microsoft. See snapshot below:

My taskbar

My taskbar: Click to view original size

After running the above code, this is what I see in my print log:

Print log

Print log

The output shows the order in which the IE windows are placed on the Desktop, which is same as the order in which they were opened.

The tricky part

The only tricky part in this concept is its applicability when there is only one browser open. With one open browser, regardless of the CreationTime value supplied, QTP will always identify the only open browser. This is because, CreationTime values are generated when there are multiple browsers open – with a single open browser, this value is generally has no usage. This is at least true for QTP 10.0 and previous versions.

IE Error: A script is causing IE to run slowly

$
0
0

While testing a script on IE8, me and my colleague kept getting the error “A script on this page is causing Internet Explorer to run slowly”. Below is a snapshot of the error:

After some research, I came across an article on MSDN which already had the solution: Microsoft KB # 175500. The part we are concerned about is in the section “Let me fix it myself”:

1.Using a Registry Editor such as Regedt32.exe, open this key: HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Styles
Note: If the Styles key is not present, create a new key that is called Styles.
2. Create a new DWORD value called “MaxScriptStatements” under this key and set the value to the desired number of script statements. If you are unsure of what value you need to set this to, you can set it to a DWORD value of 0xFFFFFFFF to completely avoid the dialog.

For the curious ones, the article states that, to encounter the error, the DWord value of 0xFFFFFFFF must be added. The value equates to -1, which is what has been used in the function below.

Code
Sub IE_ChangeScriptTimeOut()
    Dim Registry, sKeyPath, sValueName, dwValue, sComputer
    CONST HKEY_CURRENT_USER = &H80000001
 
    sKeyPath = "Software\Microsoft\Internet Explorer\Styles"
    sValueName = "MaxScriptStatements"
    dwValue = -1
    sComputer = "."
 
    On Error Resume Next
        Set Registry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_ 
                sComputer & "\root\default:StdRegProv")
 
        Registry.CreateKey HKEY_CURRENT_USER, sKeyPath
        Registry.SetDWORDValue HKEY_CURRENT_USER, sKeyPath, sValueName, CLng(dwValue)
    On Error Goto 0
 
    Set Registry = Nothing
End Sub

Thanks for reading, and thanks for visiting Relevant Codes! :)


Get Row/Column Of An Object in a WebTable

$
0
0

This article shows a simple way of finding out in which cell a QTP’s Test Object resides. I find the method shown in this article a more effective and faster way of finding the cell I’m looking for. I have found that this method performs better than traversing rows/cells of a WebTable using in-built WebTable methods such as ChildItem, ChildItemCount and GetCellData. Also, for test objects, it is also not possible to find an exact match with the methods provided for WebTable – it is only possible for strings.

A workaround to find objects inside WebTable using DOM table/tr/td is shown in this article. The code snippets below show how to retrieve the row and column of a given object from a WebTable.

Consider the element “Doe” in the table below. We can visually see that the link is in the 5th row (starting at the heading) and the 3rd column.

ID First Name Last Name Gender Attending class?
12345 John Smith M
12346 Anne Johnson F
12347 Adam Roberts M
12348 Mary Doe F
12349 Tiffany Smith F

Executing the following code will provide us our expected output:

Set element = Browser("creationtime:=0").WebElement("innertext:=Doe", "index:=0")

MsgBox "Row# " & element.GetRow()
MsgBox "Col# " & element.GetColumn()

The above example uses WebElement, but this approach works for all Web objects. Similarly, the code for finding the 2nd WebCheckBox for Anne Johnson will give us: Row# 3 and Column#5 with the following code:

MsgBox Browser("creationtime:=0").WebCheckBox("name:=attending", "index:=1").GetRow
MsgBox Browser("creationtime:=0").WebCheckBox("name:=attending", "index:=1").GetColumn

The Code

The following two methods can be used directly for the object and will retrieve ‘either’ the row or the column. The below method retrieves the Row for an object residing in a WebTable:

Find Row of the Object from WebTable
Function GetRow(ByVal TObject)
    GetRow = -1
 
    Set TObject = TObject.Object
 
    Do
        If TObject.nodeName = "TR" Then
            GetRow = TObject.rowIndex + 1
            Exit Function
        End If
 
        Set TObject = TObject.parentNode
    Loop Until TObject.nodeName = "HTML"
End Function
 
RegisterUserFunc "Image", "GetRow", "GetRow"
RegisterUserFunc "Link", "GetRow", "GetRow"
RegisterUserFunc "WebEdit", "GetRow", "GetRow"
RegisterUserFunc "WebList", "GetRow", "GetRow"
RegisterUserFunc "WebCheckBox", "GetRow", "GetRow"
RegisterUserFunc "WebElement", "GetRow", "GetRow"
RegisterUserFunc "WebRadioGroup", "GetRow", "GetRow"
Example
MsgBox Browser("title:=myBrowser").Link("innertext:=myLink", "index:=1").GetRow

This method returns the column of the object inside a WebTable:

Find Column of the Object from WebTable
Function GetColumn(ByVal TObject)
    GetColumn = -1
 
    Set TObject = TObject.Object
 
    Do
        If TObject.nodeName = "TD" Then
            GetColumn = TObject.cellIndex + 1
            Exit Function
        End If
 
        Set TObject = TObject.parentNode
    Loop Until TObject.nodeName = "HTML"
End Function
 
RegisterUserFunc "Image", "GetColumn", "GetColumn"
RegisterUserFunc "Link", "GetColumn", "GetColumn"
RegisterUserFunc "WebEdit", "GetColumn", "GetColumn"
RegisterUserFunc "WebList", "GetColumn", "GetColumn"
RegisterUserFunc "WebCheckBox", "GetColumn", "GetColumn"
RegisterUserFunc "WebElement", "GetColumn", "GetColumn"
RegisterUserFunc "WebRadioGroup", "GetColumn", "GetColumn"
Example
MsgBox Browser("title:=myBrowser").Link("innertext:=myLink", "index:=1").GetColumn

The below implementation retrieves both row and column as a Scripting.Dictionary.

Find Row & Column Info as Scripting.Dictionary
Function CellInfo(ByVal TObject)
    Dim dic
 
    Set dic = CreateObject("Scripting.Dictionary")
    dic.Add "row", -1
    dic.Add "col", -1
 
    Set TObject = TObject.Object
 
    Do
        If TObject.nodeName = "TD" Then dic("col") = TObject.cellIndex + 1
 
        If TObject.nodeName = "TR" Then
            dic("row") = TObject.rowIndex + 1
            Exit Do
        End If
 
        Set TObject = TObject.parentNode
    Loop Until TObject.nodeName = "HTML"
 
    Set CellInfo = dic
End Function
 
RegisterUserFunc "Image", "CellInfo", "CellInfo"
RegisterUserFunc "Link", "CellInfo", "CellInfo"
RegisterUserFunc "WebEdit", "CellInfo", "CellInfo"
RegisterUserFunc "WebList", "CellInfo", "CellInfo"
RegisterUserFunc "WebRadioGroup", "CellInfo", "CellInfo"
RegisterUserFunc "WebElement", "CellInfo", "CellInfo"
RegisterUserFunc "WebCheckBox", "CellInfo", "CellInfo"
Example
Set cells = Browser("title:=myBrowser").Link("innertext:=myLink", "index:=1").CellInfo()

MsgBox cells("row")
MsgBox cells("col")

cells.RemoveAll
Set cells = Nothing

I hope you find this helpful. As always, thanks for visiting Relevant Codes :)

QTP – Testing Dojo Slider and Combobox

$
0
0

In this article, I am going to show how to automate 2 complex Dojo controls without creating a separate Web Extensibility solution.

Dojo Slider

A Dojo slider (also known as trackbar) is simply a scale that can be dragged vertically or horizontally to select a value. It’s generally referred to as digit.form.HorizontalSlider or dijit.form.VerticalSlider. To understand how to work with this complex control, we have used the simple slider example from Dojo Forms Demo located here: Dojo Form Widgets Test. Below is a snapshot of the slider in question.

This slider uses 4 possible selection values: High school, College, Masters and PhD. Let’s also analyze the HTML to find out cues to help us choose a value from the selection using QTP.

Click here to see the HTML that makes up our simple trackbar.

You may wonder now: that’s a lot of HTML and complex set of DIVs for a simple trackbar. It is indeed quite complex. After analyzing the source, below are a few possible mistakes made to select the desired value.

'Click the Percentage DIV: 0%
'<DIV style="LEFT: 0%" class="dijitRuleMark dijitRuleMarkH"></DIV>
With Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")
    .WebElement("html tag:=DIV", "class:=dijitRuleMark dijitRuleMarkH", "index:=0").Click
End With
 
'Click the text DIV: high school
'<DIV class="dijitRuleLabel dijitRuleLabelH">high school</DIV>
With Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")
    .WebElement("html tag:=DIV", "class:=dijitRuleLabel dijitRuleLabelH", "index:=0").Click
End With

If you have tested this control, you may know the above solution will not work. The trick to select a value lies with the data-dojo-attach-point=”progressBar” in the HTML source:

<DIV style="WIDTH: 100%" 
    class="dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH" 
    role=presentation 
    data-dojo-attach-event="press:_onBarClick" 
    data-dojo-attach-point="progressBar">

So, to select a value, we simply do this:

'Select high school
Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")_
    .WebElement("class:=.*dijitSliderProgressBarH", "index:=0")_
        .Object.style.width = "0%"

The value “0%” was selected because there are 4 possible choices:

<DIV style="LEFT: 0%" class="dijitRuleMark dijitRuleMarkH"></DIV>
<DIV style="LEFT: 33.33%" class="dijitRuleMark dijitRuleMarkH"></DIV>
<DIV style="LEFT: 66.66%" class="dijitRuleMark dijitRuleMarkH"></DIV>
<DIV style="LEFT: 100%" class="dijitRuleMark dijitRuleMarkH"></DIV>

It is even possible to further simplify this to select the desired value by specifying the text-content.

Sub SelectEducationLevel(ByVal level)
    Select Case LCase(level)
        Case "high school" : level = "0%"
        Case "college" : level = "33.33%"
        Case "masters" : level = "66.66%"
        Case "phd" : level = "100%"
    End Select
 
    Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")_
        .WebElement("class:=.*dijitSliderProgressBarH", "index:=0")_
        .Object.style.width = level
End Sub

To select a value, it’s as simple as running the following line of code:

SelectEducationLevel "High School"

Dojo ComboBox

Like most JavaScript toolkits, Dojo’s ComboBox is also a combination of a ListBox (SELECT) and a Textbox (INPUT). Unlike a traditional ComboBox, with a Dojo ComboBox as the user types, partially matched selections are shown. Below is the ComboBox used from same page as the TrackBar example: Dojo Form Widgets Test.

The ComboBox has 6 possible options: None, Paragraph, Heading, Subheading, Sub-subheading, Pre-formatted.

Click here to see the HTML that makes up our ComboBox.

Unlike the TrackBar control we saw earlier, this one has only a few DIV tags that make up its structure. Also, unlike the TrackBar control, there is a straight-forward value choosing mechanism – innerText of the DIV. That also makes it a bit easier to work with this control. However, like a normal ComboBox or ListBox, we cannot use the Select method to make the selection. Since it’s a WebElement (DIV) we are dealing with, we will have to use Click() instead.

Still, there is a catch here. The control we want to select will only be visible for selection once the drop-down is displayed. Once the drop-down is displayed, all the drop-down elements will be added to the HTML source dynamically. Note: the button must be clicked at-least once.

The code below selects the option “Heading” from the ComboBox.

'Select option: Click DownArrow button
Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")_
  .WebElement("html tag:=DIV", "class:=.*dijitDownArrowButton.*", "index:=4")_
  .Click
 
Wait(1)
 
'Select option: Heading
Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")_
  .WebElement("html tag:=DIV", "class:=.*dijitMenuItem", "innertext:=Heading").Click

Further simplification of this to work in cases where one selection is made and the drop-down button is clicked.

Sub SelectFormat(ByVal format)
    With Browser("Dojo Form Widgets Test").Page("Dojo Form Widgets Test")
        If Not .WebElement("html tag:=DIV", "class:=.*dijitMenuItem", "innertext:=Heading").Exist(0) Then
            'Index is used here because there are other
            'dijitDownArrayButton controls present
            .WebElement("html tag:=DIV", "class:=.*dijitDownArrowButton.*", "index:=4").Click
            Wait(1)
        End If
 
        .WebElement("html tag:=DIV", "class:=.*dijitMenuItem", "innertext:=" & format).Click
    End With
End Sub

To select a value, it’s as simple as running the following line of code:

Call SelectFormat("Pre-formatted")
Viewing all 10 articles
Browse latest View live