Web site testing

From Chickenfoot Script Repository

This is just an example of how chickenfoot can be used to run test cases. To use on your site, you'll need to modify the useCase object and add a function for each step you wish to perform. Then, just point the object to the next step in test case using whenLoaded(function(){now.stopStep(true); now.myNextStep()});

include("fileio.js");

/*********************************
* Create each indivual test case *
*********************************/
testSuite = new Array();
testSuite[testSuite.length] = new useCase("MiniSDHC");
testSuite[testSuite.length] = new useCase("Compact Flash");
testSuite[testSuite.length] = new useCase("Secure Digital");

/***********************************
* Try to loop through each useCase *
***********************************/
try {
	var actNum, errNum;
	var errBln = false;
	var gStartTime = new Date();
	for (var cnt = 0; cnt < testSuite.length; cnt++) {
		actNum = errNum = 0;
		output("================================");
		output("Use Case " + (cnt+1));
		output("================================");
		testSuite[cnt].startTest();
		while (testSuite[cnt].isRunning) {
			sleep(1);
		}
	}
	gEndTime = new Date();
	totalTime = (gEndTime.getTime() - gStartTime.getTime())/1000;
}

catch (e) {output(e);}

finally {
	if (errBln) {
		output("The following errors were recorded:");
		for (var i = 0; i < testSuite.length; i++) {
			for (var j = 0; j < testSuite[i].step.length; j++) {
				if (testSuite[i].step[j].error) {
					output("\nTest Case " + (i+1))
					output("===========");
					output(j+1 + ". " + testSuite[i].step[j].error);
				}
			}
		}
	} else {
		totalTime = 0;
		for (var j = 0; j < testSuite.length; j++) {
			totalTime += testSuite[j].loadTime;
		}
		totalTime = Math.round(totalTime*1000)/1000
		output("Script ran successfully in " + totalTime + " seconds");
	}
}

/*******************************************************************************
* Use Case Object:
* I only have one custom attribute in this example, "searchTerm", but one could 
* add username, password, or anything they need to change from each run.
* I assign now to the current object so that I can manipulate the page
* with something like now.document.formName.eleName.value = "blah". I store the
* tab reference, so I can switch tabs while it's runing, and it will continue the 
* use case in that tab, in the background. The logger, which keeps track of start 
* time, stop time, and action title, is stored on the step attribute.
*******************************************************************************/
function useCase(s) {
	var now = this;
	this.searchTerm = s;	
	
	this.startTime = null;
	this.stopTime  = null;
	this.loadTime  = null;
	this.errors    = 0;	
	this.step      = new Array();
	this.isRunning = true;
	this.tab       = null;
	this.document  = null;

	this.startTest = function() {
		now.startTime = new Date();
		now.tab = tab;
		now.goToGoogle();
	}

	this.goToGoogle = function() {
		now.startStep("Go to Google", false)
		try {
			go("http://www.google.com/prdhp?hl=en&tab=wf");
			whenLoaded(function(){now.stopStep(true); now.enterSearch()});
		} catch(e) {
			output(e);
			now.logError(e, arguments.callee);
		}
	}
	
	this.enterSearch = function() {
		now.startStep("Submit search term", false);
		try {
			enter('Search Products', now.searchTerm);
			click('Search Products');
			whenLoaded(function(){now.stopStep(true); now.sortByPrice();});
		} catch(e) {
			now.logError(e, arguments.callee);
		}
	}

	this.sortByPrice = function() {
		now.startStep("Sort by Price", false);
		try {
			pick("Sort by price: low to high");
			sleep(1);
			whenLoaded(function(){now.stopStep(true); now.goToBuy();});
		} catch(e) {
			now.logError(e, arguments.callee);
		}
	}
	
	this.goToBuy = function() {
		now.startStep("Go to buy.com", false);
		try {
			click("first buy.com");
			whenLoaded(function(){now.stopStep(true); now.complete();});
		} catch(e) {
			now.logError(e, arguments.callee);
		}
	}
	
	/*****************************************
	* Stop object timer, and display summary *
	*****************************************/
	this.complete = function() {
		now.stopTime = new Date();
		now.loadTime = (now.stopTime.getTime() - now.startTime.getTime())/1000;
		output("====================");
		output("Use Case " + (cnt+1) + " Summary:");
		output("====================");
		output("Began:  " + formatTime(now.startTime));
		output("Ended:  " + formatTime(now.stopTime));
		output("Lasted: " + now.loadTime + " seconds");
		output("Errors: " + now.errors + "\n");
		for (var st = 0; st > now.step.length; st++) {
			output("Action(" + st + "): " + now.step[st].error);
		}
		output("----------------------------------------\n");
		now.isRunning = false;
	}
	
	/**************************
	* Initialize now.document *
	**************************/
	this.init = function() {
		now.document = now.tab.document.wrappedJSObject;
	}
	
	/***********************************************
	* Instantiate a new logger and start the timer *
	***********************************************/
	this.startStep = function(strName, blnLog) {
		idx = now.step.length;
		now.step[idx] = new Logger(strName);
		now.step[idx].start();
		now.init();
		if (blnLog) {
			now.savePage();
		}
	}
	
	/*****************
	* Stop the timer *
	*****************/
	this.stopStep = function(blnLog) {
		try {
			now.step[now.step.length-1].stop();
			if (blnLog) {
				now.savePage();
			}
		} catch (e) {
			alert(e);
		}
	}
	
	/******************
	* Save the result *
	******************/
	this.savePage = function() {
		for (var tbox in find("textbox")) {
			tbox.element.setAttribute("value", tbox.element.value)
		}
		for (var pbox in find("password")) {
			pbox.element.setAttribute("value", pbox.element.value)
		}
		write(formatFileName(gStartTime) + '.testSuite' + (cnt+1) + '.step' + (now.step.length) + '.html', 
				'<html><base href="' + location.protocol + location.host + '">' + tab.document.documentElement.innerHTML + '</html>');
	}

	/************************************
	* Report error to the logger object *
	************************************/
	this.logError = function(e, where) {
		gErr++;
		now.savePage();
		now.errors++;
		now.step[now.step.length-1].logError(e, where);
		now.complete();
	}
}


/*****************
* Logging Object *
*****************/
function Logger(strName) {
	this.name  = strName;
	this.error = null;
	this.startTime = null;
	this.stopTime  = null;
	this.loadTime  = null;
	
	this.start = function() {
		this.startTime = new Date();
		output("Action " + (idx+1) + ": " + this.name);
		output("...began at " + formatTime(this.startTime));
	}
	
	this.stop = function() {
		this.stopTime = new Date();
		this.loadTime = (this.stopTime.getTime() - this.startTime.getTime())/1000;
		output("...was successful in " + this.loadTime + " secs\n");
	}
	
	this.logError = function(e, where) {
		this.stopTime = new Date();
		this.loadTime = (this.stopTime.getTime() - this.startTime.getTime())/1000;
		output("...ERRORED at " + formatTime(this.stopTime) + " (" + this.loadTime + " secs)");
		output(e);
		this.error = e;
		errBln = true;
	}
}


/***********************************************
* Helper functions to format time and filename *
***********************************************/
function formatTime(oDate) {
	currTime  = ((oDate.getHours()%12 > 0) ? oDate.getHours()%12 : 12) + ":";
	currTime += pad(oDate.getMinutes()) + ":";
	currTime += pad(oDate.getSeconds()) + " ";
	currTime += (oDate.getHours() > 11) ? "PM" : "AM";
	return currTime;
}

function formatLongTime(oDate) {
	strTime  = (oDate.getYear()+1900) + "-" + pad(oDate.getMonth()+1) + "-";
	strTime += pad(oDate.getDate()+1) + "_";
	strTime += pad(oDate.getHours()) + "h_";
	strTime += pad(oDate.getMinutes()) + "m_";
	strTime += pad(oDate.getSeconds()) + "s";
	return strTime;
}

function formatFileName(oDate) {
	return "Result " + formatLongTime(oDate);
}

function pad(num) {
	return (num < 10) ? "0"+num : num;
}