1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/testing/mochitest/browser-harness.xul Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,291 @@ 1.4 +<?xml version="1.0"?> 1.5 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> 1.6 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.7 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.9 + 1.10 +<window id="browserTestHarness" 1.11 + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.12 + onload="TestStart();" 1.13 + title="Browser chrome tests" 1.14 + width="1024"> 1.15 + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/MozillaLogger.js"/> 1.16 + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/LogController.js"/> 1.17 + <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"/> 1.18 + <script type="application/javascript" src="chrome://mochikit/content/manifestLibrary.js" /> 1.19 + <script type="application/javascript" src="chrome://mochikit/content/chunkifyTests.js"/> 1.20 + <style xmlns="http://www.w3.org/1999/xhtml"><![CDATA[ 1.21 + #results { 1.22 + margin: 5px; 1.23 + background-color: window; 1.24 + -moz-user-select: text; 1.25 + } 1.26 + 1.27 + #summary { 1.28 + color: white; 1.29 + border: 2px solid black; 1.30 + } 1.31 + 1.32 + #summary.success { 1.33 + background-color: #0d0; 1.34 + } 1.35 + 1.36 + #summary.failure { 1.37 + background-color: red; 1.38 + } 1.39 + 1.40 + #summary.todo { 1.41 + background-color: orange; 1.42 + } 1.43 + 1.44 + .info { 1.45 + color: grey; 1.46 + } 1.47 + 1.48 + .failed { 1.49 + color: red; 1.50 + font-weight: bold; 1.51 + } 1.52 + 1.53 + .testHeader { 1.54 + margin-top: 1em; 1.55 + } 1.56 + 1.57 + p { 1.58 + margin: 0.1em; 1.59 + } 1.60 + 1.61 + a { 1.62 + color: blue; 1.63 + text-decoration: underline; 1.64 + } 1.65 + ]]></style> 1.66 + <script type="application/javascript;version=1.7"><![CDATA[ 1.67 + if (Cc === undefined) { 1.68 + var Cc = Components.classes; 1.69 + var Ci = Components.interfaces; 1.70 + } 1.71 + 1.72 + var gConfig; 1.73 + 1.74 + var gDumper = { 1.75 + get fileLogger() { 1.76 + let logger = null; 1.77 + if (gConfig.logFile) { 1.78 + try { 1.79 + logger = new MozillaFileLogger(gConfig.logFile) 1.80 + } catch (ex) { 1.81 + dump("TEST-UNEXPECTED-FAIL | (browser-harness.xul) | " + 1.82 + "Error trying to log to " + gConfig.logFile + ": " + ex + "\n"); 1.83 + } 1.84 + } 1.85 + delete this.fileLogger; 1.86 + return this.fileLogger = logger; 1.87 + }, 1.88 + 1.89 + dump: function (str) { 1.90 + dump(str); 1.91 + 1.92 + if (this.fileLogger) 1.93 + this.fileLogger._foStream.write(str, str.length); 1.94 + }, 1.95 + 1.96 + done: function () { 1.97 + if (this.fileLogger) 1.98 + this.fileLogger.close(); 1.99 + } 1.100 + } 1.101 + 1.102 + function TestStart() { 1.103 + gConfig = readConfig(); 1.104 + 1.105 + // If MochiTest was started with the --test-path flag specifying a subset 1.106 + // of tests to run, put that path in the label of the "Run Tests" button 1.107 + // so the tester knows which tests will run when they press that button. 1.108 + if (gConfig.testPath) 1.109 + document.getElementById("runTestsButton").label = 1.110 + "Run " + gConfig.testPath + " tests"; 1.111 + 1.112 + // Similarly, update the title for --start-at and --end-at. 1.113 + if (gConfig.startAt || gConfig.endAt) 1.114 + document.getElementById("runTestsButton").label = 1.115 + "Run subset of tests"; 1.116 + 1.117 + if (gConfig.autorun) 1.118 + setTimeout(runTests, 0); 1.119 + } 1.120 + 1.121 + var gErrorCount = 0; 1.122 + 1.123 + function browserTest(aTestFile) { 1.124 + this.path = aTestFile; 1.125 + this.dumper = gDumper; 1.126 + this.results = []; 1.127 + this.scope = null; 1.128 + this.duration = 0; 1.129 + this.unexpectedTimeouts = 0; 1.130 + this.lastOutputTime = 0; 1.131 + } 1.132 + browserTest.prototype = { 1.133 + get passCount() { 1.134 + return this.results.filter(function (t) !t.info && !t.todo && t.pass).length; 1.135 + }, 1.136 + get todoCount() { 1.137 + return this.results.filter(function (t) !t.info && t.todo && t.pass).length; 1.138 + }, 1.139 + get failCount() { 1.140 + return this.results.filter(function (t) !t.info && !t.pass).length; 1.141 + }, 1.142 + 1.143 + addResult: function addResult(result) { 1.144 + this.lastOutputTime = Date.now(); 1.145 + this.results.push(result); 1.146 + 1.147 + this.dumper.dump(result.result + " | " + this.path + " | " + result.msg + "\n"); 1.148 + }, 1.149 + 1.150 + setDuration: function setDuration(duration) { 1.151 + this.duration = duration; 1.152 + }, 1.153 + 1.154 + get htmlLog() { 1.155 + let txtToHTML = Cc["@mozilla.org/txttohtmlconv;1"]. 1.156 + getService(Ci.mozITXTToHTMLConv); 1.157 + function _entityEncode(str) { 1.158 + return txtToHTML.scanTXT(str, Ci.mozITXTToHTMLConv.kEntities); 1.159 + } 1.160 + var path = _entityEncode(this.path); 1.161 + var html = this.results.map(function (t) { 1.162 + var classname = t.info ? "info" : "result " + (t.pass ? "passed" : "failed"); 1.163 + var text = t.result + " | " + path + " | " + _entityEncode(t.msg); 1.164 + if (!t.info && !t.pass) { 1.165 + return '<p class="' + classname + '" id=\"ERROR' + (gErrorCount++) + '">' + 1.166 + text + " <a href=\"javascript:scrollTo('ERROR" + gErrorCount + "')\">NEXT ERROR</a></p>"; 1.167 + } 1.168 + return '<p class="' + classname + '">' + text + "</p>"; 1.169 + }).join("\n"); 1.170 + if (this.duration) { 1.171 + html += "<p class=\"info\">TEST-END | " + path + " | finished in " + 1.172 + this.duration + " ms</p>"; 1.173 + } 1.174 + return html; 1.175 + } 1.176 + }; 1.177 + 1.178 + // Returns an array of browserTest objects for all the selected tests 1.179 + function runTests() { 1.180 + gConfig.baseurl = "chrome://mochitests/content"; 1.181 + getTestList(gConfig, loadTestList); 1.182 + } 1.183 + 1.184 + function loadTestList(links) { 1.185 + if (!links) { 1.186 + createTester({}); 1.187 + return; 1.188 + } 1.189 + 1.190 + // load server.js in so we can share template functions 1.191 + var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. 1.192 + getService(Ci.mozIJSSubScriptLoader); 1.193 + var srvScope = {}; 1.194 + scriptLoader.loadSubScript('chrome://mochikit/content/server.js', 1.195 + srvScope); 1.196 + 1.197 + var fileNames = []; 1.198 + var fileNameRegexp = /browser_.+\.js$/; 1.199 + srvScope.arrayOfTestFiles(links, fileNames, fileNameRegexp); 1.200 + 1.201 + if (gConfig.startAt || gConfig.endAt) { 1.202 + fileNames = skipTests(fileNames, gConfig.startAt, gConfig.endAt); 1.203 + } 1.204 + 1.205 + if (gConfig.totalChunks && gConfig.thisChunk) { 1.206 + fileNames = chunkifyTests(fileNames, gConfig.totalChunks, 1.207 + gConfig.thisChunk, gConfig.chunkByDir); 1.208 + } 1.209 + 1.210 + createTester(fileNames.map(function (f) { return new browserTest(f); })); 1.211 + } 1.212 + 1.213 + function setStatus(aStatusString) { 1.214 + document.getElementById("status").value = aStatusString; 1.215 + } 1.216 + 1.217 + function createTester(links) { 1.218 + var windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']. 1.219 + getService(Ci.nsIWindowMediator); 1.220 + var winType = gConfig.testRoot == "browser" ? "navigator:browser" : 1.221 + gConfig.testRoot == "metro" ? "navigator:browser" : 1.222 + gConfig.testRoot == "webapprtChrome" ? "webapprt:webapp" : 1.223 + null; 1.224 + if (!winType) { 1.225 + throw new Error("Unrecognized gConfig.testRoot: " + gConfig.testRoot); 1.226 + } 1.227 + var testWin = windowMediator.getMostRecentWindow(winType); 1.228 + 1.229 + setStatus("Running..."); 1.230 + testWin.focus(); 1.231 + var Tester = new testWin.Tester(links, gDumper, testsFinished); 1.232 + Tester.start(); 1.233 + } 1.234 + 1.235 + function sum(a, b) { 1.236 + return a + b; 1.237 + } 1.238 + 1.239 + function getHTMLLogFromTests(aTests) { 1.240 + if (!aTests.length) 1.241 + return "<div id=\"summary\" class=\"failure\">No tests to run." + 1.242 + " Did you pass an invalid --test-path?</div>"; 1.243 + 1.244 + var log = ""; 1.245 + 1.246 + var passCount = aTests.map(function (f) f.passCount).reduce(sum); 1.247 + var failCount = aTests.map(function (f) f.failCount).reduce(sum); 1.248 + var todoCount = aTests.map(function (f) f.todoCount).reduce(sum); 1.249 + log += "<div id=\"summary\" class=\""; 1.250 + log += failCount != 0 ? "failure" : 1.251 + passCount == 0 ? "todo" : "success"; 1.252 + log += "\">\n<p>Passed: " + passCount + "</p>\n" + 1.253 + "<p>Failed: " + failCount; 1.254 + if (failCount > 0) 1.255 + log += " <a href=\"javascript:scrollTo('ERROR0')\">NEXT ERROR</a>"; 1.256 + log += "</p>\n" + 1.257 + "<p>Todo: " + todoCount + "</p>\n</div>\n<div id=\"log\">\n"; 1.258 + 1.259 + return log + aTests.map(function (f) { 1.260 + return "<p class=\"testHeader\">Running " + f.path + "...</p>\n" + f.htmlLog; 1.261 + }).join("\n") + "</div>"; 1.262 + } 1.263 + 1.264 + function testsFinished(aTests) { 1.265 + // Focus our window, to display the results 1.266 + window.focus(); 1.267 + 1.268 + if (gConfig.closeWhenDone) { 1.269 + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup); 1.270 + appStartup.quit(Ci.nsIAppStartup.eForceQuit); 1.271 + return; 1.272 + } 1.273 + 1.274 + // UI 1.275 + document.getElementById("results").innerHTML = getHTMLLogFromTests(aTests); 1.276 + setStatus("Done."); 1.277 + } 1.278 + 1.279 + function scrollTo(id) { 1.280 + var line = document.getElementById(id); 1.281 + if (!line) 1.282 + return; 1.283 + 1.284 + var boxObject = document.getElementById("results").parentNode.boxObject; 1.285 + boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject); 1.286 + boxObject.scrollToElement(line); 1.287 + } 1.288 + ]]></script> 1.289 + <button id="runTestsButton" oncommand="runTests();" label="Run All Tests"/> 1.290 + <label id="status"/> 1.291 + <scrollbox flex="1" style="overflow: auto" align="stretch"> 1.292 + <div id="results" xmlns="http://www.w3.org/1999/xhtml" flex="1"/> 1.293 + </scrollbox> 1.294 +</window>