TestRunner.js
Summary
Test runner framework
function TestRunner(name) {
this.name = name;
this.testGroupRunners = new Array();
this.testProcedures = new Array();
this.testMapper = new Array();
this.testGroupPrototype = new TestGroup();
this.testProcedurePrototype = new TestProcedure();
this.testReport = new TestReport();
var view = new OutlineNode(name, true);
if (typeof(view.expand) == "function") {
view.setContextMenu(["run", "clear", "report", "expand", "collapse"]);
} else {
view.setContextMenu(["run", "clear", "report"]);
}
view.setUserObject(this);
this.view = view;
view.show();
}
TestRunner.prototype.setReportDirectory = function(dir) {
this.reportDir = dir;
}
TestRunner.prototype.actionListener = function(source, actionName) {
switch(actionName) {
case "run" :
this.run();
break;
case "clear" :
this.clearResults();
break;
case "report" :
this.report();
break;
case "expand" :
this.expandAll();
break;
case "collapse" :
this.collapseAll();
break;
}
}
TestRunner.prototype.expandAll = function() {
for each (c in this.view.childs) {
c.expand();
}
}
TestRunner.prototype.collapseAll = function() {
for each (c in this.view.childs) {
c.collapse();
}
}
TestRunner.prototype.report = function() {
var fn = GPSystem.dateTimeByteString().toString(HEX) + "_TestReport.xml";
if (this.reportDir == undefined) {
var fn = GPSystem.mapFilename(fn, GPSystem.USR);
} else {
var fn = this.reportDir + "/" + fn;
}
var fn = Dialog.prompt("Select output file for report", fn, null, "*.xml");
if (fn != null) {
this.testReport.writeReport(fn);
print("Report written to " + fn);
}
}
TestRunner.prototype.addTestGroup = function(testGroup) {
var tgrs = this.testGroupRunners;
tgr = new TestGroupRunner(this, testGroup);
tgrs.push(tgr);
var view = this.view;
view.insert(tgr.view);
}
TestRunner.prototype.addTestGroupFromXML = function (file, parameter) {
var parser = new GPXML();
parser.defineArrayElement("/testgroup", "testcase,function", "id,Name");
parser.defineArrayElement("/testgroup/testcase/procedures", "procedure");
var xml = parser.parse(file);
var ctor = xml.constructor.Script;
if (!ctor) {
ctor = function(name, parameter) { TestGroup.call(this, name, parameter); };
}
ctor.prototype = new TestGroup();
ctor.prototype.constructor = ctor;
ctor.prototype.usedProcedures = new Array();
var testcases = xml.testcase;
for (var i in testcases) {
if (i != "arrayIndex") {
var s = testcases[i].Script;
s.XML = testcases[i];
ctor.prototype["case" + i] = s;
if (testcases[i].procedures) {
var procedures = testcases[i].procedures.procedure;
ctor.prototype.usedProcedures[i] = new Array();
for (var p = 0; p < procedures.length; p++) {
ctor.prototype.usedProcedures[i].push(procedures[p].id);
}
}
}
}
if (xml.setup) {
ctor.prototype["setUp"] = xml.setup.Script;
}
if (xml.teardown) {
ctor.prototype["tearDown"] = xml.teardown.Script;
}
var functions = xml["function"];
for (var i in functions) {
if (i != "arrayIndex") {
var s = functions[i].Script;
ctor.prototype[i] = s;
}
}
ctor.XML = xml;
var tc = new ctor(xml.id, parameter);
this.addTestGroup(tc);
}
TestRunner.prototype.addTestProcedure = function(proc) {
var name = proc.getName();
if (name) {
this.testProcedures[name] = proc;
}
}
TestRunner.prototype.addTestProcedureFromXML = function (file, parameter) {
var parser = new GPXML();
parser.defineArrayElement("/testprocedure", "teststep,function", "id,Name");
var xml = parser.parse(file);
var ctor = xml.constructor.Script;
if (!ctor) {
ctor = function(testgroup, name, parameter) { TestProcedure.call(this, testgroup, name, parameter); };
}
ctor.prototype = new TestProcedure();
ctor.prototype.constructor = ctor;
var teststeps = xml.teststep;
for (var i in teststeps) {
if (i != "arrayIndex") {
var s = teststeps[i].Script;
ctor.prototype["step" + i] = s;
}
}
if (xml.setup) {
ctor.prototype["setUp"] = xml.setup.Script;
}
if (xml.teardown) {
ctor.prototype["tearDown"] = xml.teardown.Script;
}
var functions = xml["function"];
for (var i in functions) {
if (i != "arrayIndex") {
var s = functions[i].Script;
ctor.prototype[i] = s;
}
}
ctor.XML = xml;
ctor.getName = function() { return xml.id; };
this.testProcedures[xml.id] = ctor;
}
TestRunner.prototype.getTestProcedure = function(name) {
return this.testProcedures[name];
}
TestRunner.prototype.addTest = function(name, listener) {
this.testMapper[name] = listener;
}
TestRunner.prototype.run = function() {
for (var i = 0; i < this.testGroupRunners.length; i++) {
var testGroupRunner = this.testGroupRunners[i];
testGroupRunner.run();
}
}
TestRunner.prototype.clearResults = function() {
for (var i in this.testMapper) {
var listener = this.testMapper[i];
if (listener) {
listener.clearResult();
}
}
this.testReport = new TestReport();
}
TestRunner.prototype.enable = function(name, state) {
var listener = this.testMapper[name];
if (listener && listener.enable) {
return listener.enable(state);
} else {
throw new GPError("TestRunner", GPError.OBJECT_NOT_FOUND, 0, name);
}
}
TestRunner.prototype.isEnabled = function(name) {
var listener = this.testMapper[name];
if (listener) {
return listener.isEnabled();
}
return true;
}
TestRunner.prototype.hasPassed = function(name, log) {
var listener = this.testMapper[name];
if (listener) {
listener.hasPassed(log);
if (listener.getXML) {
var result = new TestResult(name, true, log, listener.getXML());
this.testReport.addResult(result);
}
} else {
print("No receiver for passed notification : " + name);
for (var i in this.testMapper) {
print("- " + i);
}
}
}
TestRunner.prototype.hasFailed = function(name, log) {
var listener = this.testMapper[name];
if (listener) {
listener.hasFailed(log);
if (listener.getXML) {
var result = new TestResult(name, false, log, listener.getXML());
this.testReport.addResult(result);
}
}
}
function TestGroupRunner(testRunner, testGroup) {
this.testRunner = testRunner;
this.testGroup = testGroup;
var view = new OutlineNode(testGroup.getName());
view.setContextMenu(["run"]);
view.setUserObject(this);
this.view = view;
var testcases = testGroup.getTestCaseNames();
for (var i = 0; i < testcases.length; i++) {
var tcr = new TestCaseRunner(this, testcases[i]);
view.insert(tcr.view);
}
}
TestGroupRunner.prototype.actionListener = function(source, action) {
switch(action) {
case "run" :
this.run();
break;
}
}
TestGroupRunner.prototype.run = function() {
var test = this.testGroup;
test.run(this.testRunner);
}
function TestCaseRunner(testGroupRunner, testCase) {
this.testGroupRunner = testGroupRunner;
this.testCase = testCase;
this.selected = true;
var testRunner = testGroupRunner.testRunner;
testRunner.addTest(testGroupRunner.testGroup.getName() + "/" + testCase, this);
this.xml = testGroupRunner.testGroup.getTestCase(testCase).XML;
var view = new OutlineNode(testCase + " " + this.xml.name.elementValue);
view.setUserObject(this);
view.setIcon("selected");
view.setContextMenu(["select", "deselect", "run"]);
this.view = view;
var testGroup = testGroupRunner.testGroup;
var testprocedures = testGroup.getUsedTestProceduresForTestCase(testCase);
if (testprocedures) {
for (var i = 0; i < testprocedures.length; i++) {
var tpr = new TestProcedureRunner(this, testprocedures[i]);
view.insert(tpr.view);
}
}
}
TestCaseRunner.prototype.actionListener = function(source, actionName) {
print("Action " + actionName);
switch(actionName) {
case "select":
this.selected = true;
source.setIcon("selected");
break;
case "deselect":
this.selected = false;
source.setIcon("deselected");
break;
case "run":
this.run();
break;
}
}
TestCaseRunner.prototype.run = function() {
var test = this.testGroupRunner.testGroup;
test.runTestCase(this.testCase, this.testGroupRunner.testRunner);
}
TestCaseRunner.prototype.isEnabled = function() {
return this.selected;
}
TestCaseRunner.prototype.addLog = function(log) {
var view = this.view;
var lognode = new TestLogFile(this, log);
this.log = lognode;
view.insert(lognode.view);
}
TestCaseRunner.prototype.getXML = function() {
return this.xml;
}
TestCaseRunner.prototype.hasPassed = function(log) {
this.failed = false;
var view = this.view;
view.setIcon("passed");
this.addLog(log);
}
TestCaseRunner.prototype.hasFailed = function(log) {
this.failed = true;
var view = this.view;
view.setIcon("failed");
this.addLog(log);
}
TestCaseRunner.prototype.clearResult = function() {
this.failed = false;
var view = this.view;
if (this.selected) {
view.setIcon("selected");
} else {
view.setIcon("deselected");
}
}
TestCaseRunner.prototype.enable = function(state) {
var view = this.view;
this.selected = state;
if (this.selected) {
view.setIcon("selected");
} else {
view.setIcon("deselected");
}
}
function TestLogFile(parent, log) {
this.log = log;
var view = new OutlineNode("Log from " + Date());
this.view = view;
view.setUserObject(this);
}
TestLogFile.prototype.selectedListener = function() {
print("--------------------------------------------------------------------------------");
print(this.log);
}
function TestProcedureRunner(testCaseRunner, testProcedure) {
this.testCaseRunner = testCaseRunner;
this.testProcedure = testProcedure;
var view = new OutlineNode(testProcedure);
this.view = view;
var tp = this.testCaseRunner.testGroupRunner.testRunner.testProcedures[testProcedure];
if (tp) {
var list = new Array();
for (var i in tp.prototype) {
if (i.substr(0, 4) == "step") {
var step = i.substr(4);
list.push(step);
}
}
list.sort();
for (var i = 0; i < list.length; i++) {
var tpsr = new TestStepRunner(this, list[i]);
view.insert(tpsr.view);
}
} else {
print("No test procedure implementation found for " + testProcedure);
}
}
function TestStepRunner(testProcedureRunner, testStep) {
this.testProcedureRunner = testProcedureRunner;
this.testStep = testStep;
var view = new OutlineNode(testStep);
this.view = view;
var testCaseRunner = testProcedureRunner.testCaseRunner;
var testGroupRunner = testCaseRunner.testGroupRunner;
var testRunner = testGroupRunner.testRunner;
var testName = testGroupRunner.testGroup.getName() + "/" +
testCaseRunner.testCase + "/" +
testProcedureRunner.testProcedure + "/" +
testStep;
testRunner.addTest(testName, this);
}
TestStepRunner.prototype.hasPassed = function() {
var view = this.view;
view.setIcon("passed");
}
TestStepRunner.prototype.clearResult = function() {
var view = this.view;
view.setIcon();
}
function TestReport() {
this.testResults = [];
}
TestReport.prototype.addResult = function(result) {
this.testResults.push(result);
}
TestReport.prototype.writeReport = function(filename) {
var xml = <testreport/>
for (var i = 0; i < this.testResults.length; i++) {
var r = this.testResults[i];
var x = r.toXML();
xml.testcaseresult += x;
}
var os = new java.io.FileOutputStream(filename);
var fw = new java.io.OutputStreamWriter(os, "UTF-8");
fw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fw.write("<?xml-stylesheet type=\"text/xsl\" href=\"docreport.xsl\" ?>\n");
fw.write(xml.toXMLString());
fw.close();
}
function TestResult(id, verdict, log, tcxml) {
this.id = id;
this.verdict = verdict;
this.log = log;
this.tcxml = tcxml;
}
TestResult.prototype.toXML = function() {
var source = this.id.split("/")[0];
var sourceid = this.id.split("/")[1];
var xml = <testcaseresult id={this.id} source={source} sourceid={sourceid}/>;
xml.name = <name>{this.tcxml.name.elementValue}</name>;
xml.verdict = <verdict>{ this.verdict ? "Passed" : "Failed" }</verdict>;
xml.log = <log>{ "\n" + this.log + "\n" }</log>;
return xml;
}
Documentation generated by
JSDoc on Tue Apr 15 22:10:49 2025