2 * TestRunner: A test runner for SimpleTest
5 * * Avoid moving iframes: That causes reloads on mozilla and opera.
10 TestRunner.logEnabled = false;
11 TestRunner._currentTest = 0;
12 TestRunner.currentTestURL = "";
13 TestRunner._urls = [];
15 TestRunner.timeout = 300; // seconds
16 TestRunner.maxTimeouts = 4; // halt testing after too many timeouts
19 * Make sure the tests don't hang indefinitely.
21 TestRunner._numTimeouts = 0;
22 TestRunner._currentTestStartTime = new Date().valueOf();
24 TestRunner._checkForHangs = function() {
25 if (TestRunner._currentTest < TestRunner._urls.length) {
26 var runtime = (new Date().valueOf() - TestRunner._currentTestStartTime) / 1000;
27 if (runtime >= TestRunner.timeout) {
28 var frameWindow = $('testframe').contentWindow.wrappedJSObject ||
29 $('testframe').contentWindow;
30 frameWindow.SimpleTest.ok(false, "Test timed out.");
32 // If we have too many timeouts, give up. We don't want to wait hours
33 // for results if some bug causes lots of tests to time out.
34 if (++TestRunner._numTimeouts >= TestRunner.maxTimeouts) {
35 TestRunner._haltTests = true;
36 frameWindow.SimpleTest.ok(false, "Too many test timeouts, giving up.");
39 frameWindow.SimpleTest.finish();
41 TestRunner.deferred = callLater(30, TestRunner._checkForHangs);
46 * This function is called after generating the summary.
48 TestRunner.onComplete = null;
51 * If logEnabled is true, this is the logger that will be used.
53 TestRunner.logger = MochiKit.Logging.logger;
56 * Toggle element visibility
58 TestRunner._toggle = function(el) {
59 if (el.className == "noshow") {
61 el.style.cssText = "";
63 el.className = "noshow";
64 el.style.cssText = "width:0px; height:0px; border:0px;";
70 * Creates the iframe that contains a test
72 TestRunner._makeIframe = function (url, retry) {
73 var iframe = $('testframe');
74 if (url != "about:blank" && (!document.hasFocus() ||
75 document.activeElement != iframe)) {
76 // typically calling ourselves from setTimeout is sufficient
77 // but we'll try focus() just in case that's needed
81 window.setTimeout('TestRunner._makeIframe("'+url+'", '+(retry+1)+')', 1000);
85 if (TestRunner.logEnabled) {
86 var frameWindow = $('testframe').contentWindow.wrappedJSObject ||
87 $('testframe').contentWindow;
88 TestRunner.logger.log("Error: Unable to restore focus, expect failures and timeouts.");
91 window.scrollTo(0, $('indicator').offsetTop);
99 * TestRunner entry point.
101 * The arguments are the URLs of the test to be ran.
104 TestRunner.runTests = function (/*url...*/) {
105 if (TestRunner.logEnabled)
106 TestRunner.logger.log("SimpleTest START");
108 TestRunner._urls = flattenArguments(arguments);
109 $('testframe').src="";
110 TestRunner._checkForHangs();
112 $('testframe').focus();
113 TestRunner.runNextTest();
117 * Run the next test. If no test remains, calls makeSummary
119 TestRunner._haltTests = false;
120 TestRunner.runNextTest = function() {
121 if (TestRunner._currentTest < TestRunner._urls.length &&
122 !TestRunner._haltTests) {
123 var url = TestRunner._urls[TestRunner._currentTest];
124 TestRunner.currentTestURL = url;
126 $("current-test-path").innerHTML = url;
128 TestRunner._currentTestStartTime = new Date().valueOf();
130 if (TestRunner.logEnabled)
131 TestRunner.logger.log("Running " + url + "...");
133 TestRunner._makeIframe(url, 0);
135 $("current-test").innerHTML = "<b>Finished</b>";
136 TestRunner._makeIframe("about:blank", 0);
137 if (TestRunner.logEnabled) {
138 TestRunner.logger.log("Passed: " + $("pass-count").innerHTML);
139 TestRunner.logger.log("Failed: " + $("fail-count").innerHTML);
140 TestRunner.logger.log("Todo: " + $("todo-count").innerHTML);
141 TestRunner.logger.log("SimpleTest FINISHED");
143 if (TestRunner.onComplete)
144 TestRunner.onComplete();
149 * This stub is called by SimpleTest when a test is finished.
151 TestRunner.testFinished = function(doc) {
152 var finishedURL = TestRunner._urls[TestRunner._currentTest];
154 if (TestRunner.logEnabled)
155 TestRunner.logger.debug("SimpleTest finished " + finishedURL);
157 TestRunner.updateUI();
158 TestRunner._currentTest++;
159 TestRunner.runNextTest();
165 TestRunner.countResults = function(doc) {
166 var nOK = withDocument(doc,
167 partial(getElementsByTagAndClassName, 'div', 'test_ok')
169 var nNotOK = withDocument(doc,
170 partial(getElementsByTagAndClassName, 'div', 'test_not_ok')
172 var nTodo = withDocument(doc,
173 partial(getElementsByTagAndClassName, 'div', 'test_todo')
175 return {"OK": nOK, "notOK": nNotOK, "todo": nTodo};
178 TestRunner.updateUI = function() {
179 var results = TestRunner.countResults($('testframe').contentDocument);
180 var passCount = parseInt($("pass-count").innerHTML) + results.OK;
181 var failCount = parseInt($("fail-count").innerHTML) + results.notOK;
182 var todoCount = parseInt($("todo-count").innerHTML) + results.todo;
183 $("pass-count").innerHTML = passCount;
184 $("fail-count").innerHTML = failCount;
185 $("todo-count").innerHTML = todoCount;
187 // Set the top Green/Red bar
188 var indicator = $("indicator");
190 indicator.innerHTML = "Status: Fail";
191 indicator.style.backgroundColor = "red";
192 } else if (passCount > 0) {
193 indicator.innerHTML = "Status: Pass";
194 indicator.style.backgroundColor = "green";
197 // Set the table values
198 var trID = "tr-" + $('current-test-path').innerHTML;
200 replaceChildNodes(row,
202 {'backgroundColor': results.notOK > 0 ? "#f00":"#0d0"}}, results.OK),
204 {'backgroundColor': results.notOK > 0 ? "#f00":"#0d0"}}, results.notOK),
205 TD({'style': {'backgroundColor':
206 results.todo > 0 ? "orange":"#0d0"}}, results.todo)