Bert, can you expand on your JScript library idea please? |
Sure. Here is a (trivial) example of some test code I would write using the script based approach:
//USEUNIT WebForms
function Main()
{
var url = "http://smartbear.com";
//open up a browser and navigate to smartbear
var ie = TestedApps.iexplore.Run();
while(!ie.Exists)
{
delay(1000);
}
var $ = new WebForm(ie.WaitPage("*", 5000));
$.NavigateToURL(url);
//search for testcomplete
var searchBox = $.Find([["idStr","*_queryText*"],["ObjectType","Textbox"]],10); //1
$.SetValue(searchBox, "TestComplete"); //2
$.Click([["idStr","*_searchButton"],["ObjectType","Button"]],10); //3
$.CloseBrowserWindow();
}
Note on lines 1-3 are the most comment operations you will perform on a web page during a test, finding an item, setting a value, or clicking something. You really don't even need line one, you could just do:
$.SetValue([["idStr","*_queryText*"],["ObjectType","Textbox"]], "TestComplete");
A couple of notes about it. I find the way TestComplete's Find method works to be non-intuitive; it seems more logical to me to search for an array of paired properties like [property, value] rather than to separate the properties and the values into separate arrays like they do. You mentioned performance; on any of our pages I've never had a problem with the performance of finding our page elements this way. We still run TestComplete7 ($2k is a pretty big sum to drop for a very small company for v8), and I've noticed this method runs slower on in TestComplete7 on Windows7 than on WindowsXP; but not enough that I worry about it on an overnight test.
One of the big wins here is that all I really need is a Page object. As long as you can get a Page object that you can wrap with WebForm, you should be able to find the elements on the page that you need to work with. I haven't actually done a lot of cross browser testing, but assuming TestComplete8 delivers a FireFox Page object that works with Find and FindChild in the same way, or Chrome or whatever other browser they choose to support in the future, all that should fall out naturally.
I wrote the library because when I started out with TestComplete in 2008, replaying the recorded scripts seemed extremely hit or miss on whether the namemapping/aliases would hold up from run to run. That, plus we're relatively agile with respect to our web pages and the the structure of the page could change frequently enough that it was painful to rely on a particular structure.
The heart of the library is the Find and FindChild functions in the WebForm object. Those are mostly wrappers around TestCompletes Find and FindChild, but they take care of the above mentioned property/value oddity, and also allow for multiple attempts to find a particular object if you have a slow loading page at the point in time you run the test.
Anyway, you can take a peek at the code; I'm attaching a sample project that contains the library as I'm using it now. I should probably go back in at some point and clean out some unused functions or other cleanup, but if you stick to the functions I mentioned above you should be on solid ground. Our company runs several web based services and we've converted almost all of the testing for the web apps over to TestComplete using this library. At times I feel like I'm working around TestComplete a bit and there may be a better way to do it, but TestComplete helps out in other areas like making it easy to do database comparisons and things like that. Below is an example of a test I wrote for one of our new pages yesterday. You can see in certain cases it's a little bit of a mix of our library, and TestComplete methods like WaitWindow. The findIEModalWindow function is something that should ideally be part of the WebForm or some other include that I just haven't gotten around to yet.
function TestOilDataSubmission()
{
var DEFAULT_DELAY = 3000;
var errorMsgs = ["The specified XML could not be loaded.",
"There was an error. The complete message is displayed above the Oil Data box."];
//close the open browsers
oilographyForm.CloseBrowserWindow();
while(oilographyForm.Page.Parent.Exists)
{
Delay(1000);
}
//Test Data
var data =
[
//Test submit Sample Points
{
SubmissionMode: "Sample Points",
OilLabGUID: "D080AB0A-94F5-4C3C-A569-E9E3B1D50455",
UniqueSubmissionCode: "12345678",
OilDataXML: XML.OilDataSubmission_SamplePoints.Document.xml
},
//Test submit Oil Data
{
SubmissionMode: "Oil Test Data",
OilLabGUID: "D080AB0A-94F5-4C3C-A569-E9E3B1D50455",
UniqueSubmissionCode: "87654321",
OilDataXML:XML.OilDataSubmission_OilDataSet.Document.xml
}
];
//Open the test page
$ = new WebForm(TestedApps.Oilography.Run().WaitPage("*", 4000));
var url = "http://localhost/concert/oilography/oildatasubmission.aspx";
$.NavigateToURL(url);
for (var currData=0; currData < data.length; currData++)
{
$.SetValue([["idStr","SubmissionMode"],["ObjectType","Select"]],data[currData].SubmissionMode);
$.SetValue([["idStr","OilLabGuid"],["ObjectType","Textbox"]], data[currData].OilLabGUID);
$.SetValue([["idStr","UniqueSubmissionCode"],["ObjectType","Textbox"]], data[currData].UniqueSubmissionCode);
$.SetValue([["idStr","OilDataXml"],["ObjectType","Textarea"]], data[currData].OilDataXML);
$.Click([["idStr","SubmitButton"],["ObjectType","SubmitButton"]]);
var modalWin = findIEModalWindow("Message from webpage");
if (!modalWin.Exists) Log.Error("Could not locate the messagebox.")
var responseCaption = modalWin.WaitWindow("Static","*",2,DEFAULT_DELAY).WndCaption;
for (var i=0; i <= errorMsgs.length; i++)
{
if (responseCaption.contains(errorMsgs))
{
Log.Message(responseCaption);
$.Click(modalWin.WaitWindow("Button","OK",1,DEFAULT_DELAY));
Log.Message($.Find([["idStr","ErrorMsg"],["ObjectType","TextNode"]]).outerText);
Log.Error("Sample Points could not be saved.");
return;
}
}
$.Click(modalWin.WaitWindow("Button","OK",1,DEFAULT_DELAY));
}
DBTables.OilDataSubmission_OilDataSet.Compare(true, 3);
DBTables.OilDataSubmission_OilDataSetComments.Compare(true,3);
DBTables.OilDataSubmission_OilDataSetStatus.Compare(true,3);
DBTables.OilDataSubmission_OilDataSetSubmission.Compare(true,3);
DBTables.OilDataSubmission_SamplePoint.Compare(true,3);
DBTables.OilDataSubmission_SamplePointSchedule.Compare(true,3);
function findIEModalWindow(caption, refresh)
{
if (refresh || true) Sys.Refresh();
for (var i = 0; i < Sys.ChildCount; i++)
{
p=Sys.Child(i);
// If the process is iexplore.exe
if (p.ProcessName=="iexplore")
{
// Search for IEFrame window
w=p.WaitChild("Window(\"#32770\", \"" + caption + "\", 1)", 100);
if (w.Exists)
return w;
}
}
}
}