...use Window.TextSelect if you can not identify something

This is the final part of my hands-on review of TestPartner. Here I will try to demonstrate the old-style Visual Basic scripting approach, which I find to be more reliable. I will again use my GMail scenario.
As I mentioned before, the only place I find recording useful is in such cases when you want to get to know how the tool ‘sees’ the UI. I have no experience with the UI of GMail, so I tried to record the scenario first.
This is the script that I got:
Sub Main()
' Begin record on Monday, 13. September 2009 at
' 11:17:07 by Admin
' Attach to Gmail Email from Google -
' Microsoft Internet Explorer IEWindow
IEWindow("Gmail Email from Google - IEWindow").Attach
' Attach to Caption='Gmail: Email from
' Google'
HTMLBrowser("Caption='Gmail: Email from Google'").Attach
HTMLEditBox("Name=Email").SetText "testautomationblog"
HTMLEditBox("Name=Passwd").SetPasswordText "***"
HTMLButton("Name=signIn").Click
' Attach to Gmail - Inbox (2) -
' testautomationblog@gmailcom - Microsoft
' Internet Explorer IEWindow
IEWindow("Gmail - Inbox (2) - IEWindow").Attach
' Attach to Name=cgudh0fxq7w2n
HTMLFrame("Name=cgudh0fxq7w2n").Attach
HTMLSpan("ID=':r3'").Click 43, 12
' Attach to Gmail - Compose Mail -
' testautomationblog@gmailcom - Microsoft
' Internet Explorer IEWindow
IEWindow("Gmail - Compose Mail - IEWindow").Attach
' Attach to ID=':kl'
HTMLFrame("ID=':kl'").Attach
HTMLFrame("ID=':kl'").Click 33, 19
HTMLFrame.Type "Lorem Ipsum Dolor"
' Attach to Name=cgudh0fxq7w2n
HTMLFrame("Name=cgudh0fxq7w2n").Attach
HTMLImage("ID=':ia'").Click
HTMLDiv("ID='' Index=589").Click 48, 7
HTMLAnchor("Caption='Drafts (1)'").Click
HTMLSpan("ID='' Index=38").MouseDown 42, 7
HTMLDiv("ID='' Index=702").MouseUp 358, 25
HTMLDiv("ID='' Index=733").Click 35, 12
HTMLAnchor("Caption='Sign out'").Click
' End record on Monday, 13. September 2009 at
' 11:18:22 by Admin
End Sub
As I expected, the recorded script could not be run successfully at all. So what is wrong with it?
The recording has used two ways of addressing the controls. The first one is used with controls that TestPartner attaches to, those seem to be the controls it sees as more important, for example see line 12. Those controls are identified using something called object maps. The object maps are artifacts that represent definitions of UI controls. When you access a control in a script via an object map, you provide only the name of the map. The actual properties used to identify the control are stored in the map itself. This is the definition of the object map from line 12:

Basically this says that the window we are interested in is an Internet Explorer window with a caption 'Gmail: Email from Google - Microsoft Internet Explorer'. The idea of object maps is that they try to separate how controls are identified from the test logic. If something changes in some particular control, you will have to modify only the relevant object map, but not the script itself. This looks like a nice idea, but I found that in practice it does not always work that well.
The second way of addressing controls is called 'Raw attach names'. You can see it for example in rows 12-15. Here you just provide sets of properties and their values as a string. Notice how TestPartner identifies controls with expressions like "Name=cgudh0fxq7w2n" and "ID=':r3'". Unfortunately as we saw before, those IDs and Names are dynamically generated and change each time you log in GMail. We need a better way to locate those controls. Unfortunately GMail does not provide easy and reliable way to locate some of them (like persistent names or IDs for example), and TestPartner on the other hand does not know how to identify controls based on their relative location in the page.
Still, with some dirty hacks, I was able to quickly come up with this version of the script which can be executed reliably:
Sub Main()
sText = "Lorem Ipsum Dolor"
' -- Login
IEWindow("Caption='Gmail*'").Attach
HTMLEditBox("Name=Email").SetText "testautomationblog"
HTMLEditBox("Name=Passwd").SetPasswordText "********"
HTMLButton("Name=signIn").Click
' -- Go to compose mail and type the text
HTMLSpan("InnerText='Compose Mail'").Click
HTMLFrame("Name='' Index=1").Click
IEWindow.Type sText
' -- Center and save
HTMLImage("Width=20 Height=20 Index=16").Click
Window.TextSelect "Save Now"
' -- Wait for the draft to get saved
Sleep 2
Window.TextSelect "Draft saved"
' -- Go to Drafts
HTMLAnchor("Caption='Drafts*'").Click
HTMLSpan("InnerText='*" & sText & "'").Click
' -- Find the text and discard the draft
Window.TextSelect sText
Window.TextSelect "Discard"
' -- Logout
HTMLAnchor("Caption='Sign out'").Click
End Sub
This is a quick summary:
At line 6 I attach to the IE window. This is the only place I attach in the script as I only work in one window. I used raw attach instead of object map. Note how I used a wilcard for the window caption. Lines 7-12 are self explainotary. What you see in lines 13 and 14 is really a small hack. The editor area in GMail is contained in a HTMLFrame. TestPartner can not find anything meaningful in it to identify it, so I used HTMLFrame("Name='' Index=1"), which means basically the first HTMLFrame with empty name. Because the HTMLFrame object does not support the SetText method (like the HTMLEditBox in line 7 for example), I first click on it (line 13) and then just type in the text (line 14). I do not feel very good about this solution, but it was the first quick hack I could think of.
Identifying the center button in the toolbar of GMail was also problematic (line 17). All the buttons in GMail also lack unique IDs or Names, so I was able to identify the button only as HTMLImage("Width=20 Height=20 Index=16") - the 16th HTMLImage with Width=20 and Height=20 in the page.
Clicking the 'Save Now' button (line 18) also proved more difficult than I anticipated. For some reason it appeared as an empty unidentifiable Div when I tried to locate it with the object browser. I used the Window.TextSelect trick, which is the most universal way to make TestPartner click on some text you can not identify otherwise. This is actually a helpful tip - use Window.TextSelect if you can not identify something. After clicking the 'Save Now' button we have to wait for the backend to actually save the page before moving on with the test. A quick and somewhat dirty way to do this is shown on lines and - wait for 2 seconds and then verify that the "Draft saved" text appears on the page. I think the rest of the script needs no explanation.
To sum it up - TestPartner can be buggy and confusing, but after all, it is powerful enough to let you automate almost anything. Maybe you'll need some time to find the right workarounds. Probably they will be ugly. Overall there are much better tools, especially if you want to do web automation. There are worse too, but I am happy that I don't have to use TestPartner anymore.