setup.js (10649B)
1 /* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 "use strict"; 8 9 // This file expects the following files to be loaded. 10 /* import-globals-from TestRunner.js */ 11 12 // From the harness: 13 /* import-globals-from ../../chrome-harness.js */ 14 /* import-globals-from ../../chunkifyTests.js */ 15 16 TestRunner.logEnabled = true; 17 TestRunner.logger = LogController; 18 19 if (!("SpecialPowers" in window)) { 20 dump("SimpleTest setup.js found SpecialPowers unavailable: reloading...\n"); 21 setTimeout(window.location.reload); 22 } 23 24 /* Helper function */ 25 function parseQueryString(encodedString, useArrays) { 26 // strip a leading '?' from the encoded string 27 var qstr = 28 encodedString.length && encodedString[0] == "?" 29 ? encodedString.substring(1) 30 : encodedString; 31 var pairs = qstr.replace(/\+/g, "%20").split(/(\&\;|\&\#38\;|\&|\&)/); 32 var o = {}; 33 var decode; 34 if (typeof decodeURIComponent != "undefined") { 35 decode = decodeURIComponent; 36 } else { 37 decode = unescape; 38 } 39 if (useArrays) { 40 for (var i = 0; i < pairs.length; i++) { 41 var pair = pairs[i].split("="); 42 if (pair.length !== 2) { 43 continue; 44 } 45 var name = decode(pair[0]); 46 var arr = o[name]; 47 if (!(arr instanceof Array)) { 48 arr = []; 49 o[name] = arr; 50 } 51 arr.push(decode(pair[1])); 52 } 53 } else { 54 for (i = 0; i < pairs.length; i++) { 55 pair = pairs[i].split("="); 56 if (pair.length !== 2) { 57 continue; 58 } 59 o[decode(pair[0])] = decode(pair[1]); 60 } 61 } 62 return o; 63 } 64 65 /* helper function, specifically for prefs to ignore */ 66 function loadFile(url, callback) { 67 let req = new XMLHttpRequest(); 68 req.open("GET", url); 69 req.onload = function () { 70 if (req.readyState == 4) { 71 if (req.status == 200) { 72 try { 73 let prefs = JSON.parse(req.responseText); 74 callback(prefs); 75 } catch (e) { 76 dump( 77 "TEST-UNEXPECTED-FAIL: setup.js | error parsing " + 78 url + 79 " (" + 80 e + 81 ")\n" 82 ); 83 throw e; 84 } 85 } else { 86 dump( 87 "TEST-UNEXPECTED-FAIL: setup.js | error loading " + 88 url + 89 " (HTTP " + 90 req.status + 91 ")\n" 92 ); 93 callback({}); 94 } 95 } 96 }; 97 req.send(); 98 } 99 100 // Check the query string for arguments 101 var params = parseQueryString(location.search.substring(1), true); 102 103 var config = {}; 104 if (window.readConfig) { 105 config = readConfig(); 106 } 107 108 if (config.testRoot == "chrome" || config.testRoot == "a11y") { 109 for (var p in params) { 110 // Compare with arrays to find boolean equivalents, since that's what 111 // |parseQueryString| with useArrays returns. 112 if (params[p] == [1]) { 113 config[p] = true; 114 } else if (params[p] == [0]) { 115 config[p] = false; 116 } else { 117 config[p] = params[p]; 118 } 119 } 120 params = config; 121 params.baseurl = "chrome://mochitests/content"; 122 } else if (params.xOriginTests) { 123 params.baseurl = "http://mochi.test:8888/tests/"; 124 } else { 125 params.baseurl = ""; 126 } 127 128 if (params.testRoot == "browser") { 129 params.testPrefix = "chrome://mochitests/content/browser/"; 130 } else if (params.testRoot == "chrome") { 131 params.testPrefix = "chrome://mochitests/content/chrome/"; 132 } else if (params.testRoot == "a11y") { 133 params.testPrefix = "chrome://mochitests/content/a11y/"; 134 } else if (params.xOriginTests) { 135 params.testPrefix = "http://mochi.test:8888/tests/"; 136 params.httpsBaseUrl = "https://example.org:443/tests/"; 137 } else { 138 params.testPrefix = "/tests/"; 139 } 140 141 // set the per-test timeout if specified in the query string 142 if (params.timeout) { 143 TestRunner.timeout = parseInt(params.timeout) * 1000; 144 } 145 146 // log levels for console and logfile 147 var fileLevel = params.fileLevel || null; 148 var consoleLevel = params.consoleLevel || null; 149 150 // repeat tells us how many times to repeat the tests 151 if (params.repeat) { 152 TestRunner.repeat = params.repeat; 153 } 154 155 if (params.runUntilFailure) { 156 TestRunner.runUntilFailure = true; 157 } 158 159 // closeWhenDone tells us to close the browser when complete 160 if (params.closeWhenDone) { 161 TestRunner.onComplete = SpecialPowers.quit.bind(SpecialPowers); 162 } 163 164 if (params.failureFile) { 165 TestRunner.setFailureFile(params.failureFile); 166 } 167 168 // Breaks execution and enters the JS debugger on a test failure 169 if (params.debugOnFailure) { 170 TestRunner.debugOnFailure = true; 171 } 172 173 // logFile to write our results 174 if (params.logFile) { 175 var mfl = new MozillaFileLogger(params.logFile); 176 TestRunner.logger.addListener("mozLogger", fileLevel + "", mfl.logCallback); 177 } 178 179 // A temporary hack for android 4.0 where Fennec utilizes the pandaboard so much it reboots 180 if (params.runSlower) { 181 TestRunner.runSlower = true; 182 } 183 184 if (params.dumpOutputDirectory) { 185 TestRunner.dumpOutputDirectory = params.dumpOutputDirectory; 186 } 187 188 if (params.dumpAboutMemoryAfterTest) { 189 TestRunner.dumpAboutMemoryAfterTest = true; 190 } 191 192 if (params.dumpDMDAfterTest) { 193 TestRunner.dumpDMDAfterTest = true; 194 } 195 196 // We need to check several things here because mochitest-chrome passes 197 // `jsdebugger` and `debugger` directly, but in other tests we're reliant 198 // on the `interactiveDebugger` flag being passed along. 199 if (params.interactiveDebugger || params.jsdebugger || params.debugger) { 200 TestRunner.interactiveDebugger = true; 201 } 202 203 if (params.jscovDirPrefix) { 204 TestRunner.jscovDirPrefix = params.jscovDirPrefix; 205 } 206 207 if (params.maxTimeouts) { 208 TestRunner.maxTimeouts = params.maxTimeouts; 209 } 210 211 if (params.cleanupCrashes) { 212 TestRunner.cleanupCrashes = true; 213 } 214 215 if (params.xOriginTests) { 216 TestRunner.xOriginTests = true; 217 TestRunner.setXOriginEventHandler(); 218 } 219 220 if (params.timeoutAsPass) { 221 TestRunner.timeoutAsPass = true; 222 } 223 224 if (params.conditionedProfile) { 225 TestRunner.conditionedProfile = { 226 knownServiceWorkers: null, 227 }; 228 // Asynchronously populate knownServiceWorkers above. Because we only check 229 // this list after awaiting a different call to registeredServiceWorkers() in 230 // SimpleTest.js's afterCleanup, we are guaranteed that the list will be 231 // populated before we check it. 232 // 233 // That said, the question is whether the list was sampled before the test 234 // could start and add a ServiceWorker. And the answer is mainly yes because 235 // the request will make it to the parent process main thread before any call 236 // to register() can get there with very high probability. (We are dealing 237 // with different top-level protocols so there are some theoretical 238 // opportunities for pathological scheduling but practically speaking it is 239 // very unlikely to happen.) 240 SpecialPowers.registeredServiceWorkers(/* aForce */ true).then(workers => { 241 TestRunner.conditionedProfile.knownServiceWorkers = workers; 242 }); 243 } 244 245 if (params.comparePrefs) { 246 TestRunner.comparePrefs = true; 247 } 248 249 // Log things to the console if appropriate. 250 TestRunner.logger.addListener( 251 "dumpListener", 252 consoleLevel + "", 253 function (msg) { 254 dump(msg.info.join(" ") + "\n"); 255 } 256 ); 257 258 var gTestList = []; 259 var RunSet = {}; 260 261 RunSet.runall = function () { 262 // Filter tests to include|exclude tests based on data in params.filter. 263 // This allows for including or excluding tests from the gTestList 264 // TODO Only used by ipc tests, remove once those are implemented sanely 265 if (params.testManifest) { 266 getTestManifest( 267 getTestManifestURL(params.testManifest), 268 params, 269 function (filter) { 270 gTestList = filterTests(filter, gTestList, params.runOnly); 271 RunSet.runtests(); 272 } 273 ); 274 } else { 275 RunSet.runtests(); 276 } 277 }; 278 279 RunSet.runtests = function () { 280 // Which tests we're going to run 281 var my_tests = gTestList; 282 283 if (params.startAt || params.endAt) { 284 my_tests = skipTests(my_tests, params.startAt, params.endAt); 285 } 286 287 if (params.shuffle) { 288 for (var i = my_tests.length - 1; i > 0; --i) { 289 var j = Math.floor(Math.random() * i); 290 var tmp = my_tests[j]; 291 my_tests[j] = my_tests[i]; 292 my_tests[i] = tmp; 293 } 294 } 295 TestRunner.setParameterInfo(params); 296 TestRunner.runTests(my_tests); 297 }; 298 299 RunSet.reloadAndRunAll = function (e) { 300 e.preventDefault(); 301 //window.location.hash = ""; 302 if (params.autorun) { 303 window.location.search += ""; 304 // eslint-disable-next-line no-self-assign 305 window.location.href = window.location.href; 306 } else if (window.location.search) { 307 window.location.href += "&autorun=1"; 308 } else { 309 window.location.href += "?autorun=1"; 310 } 311 }; 312 313 // UI Stuff 314 function toggleVisible(elem) { 315 elem.classList.toggle("invisible"); 316 } 317 318 function isVisible(elem) { 319 // you may also want to check for 320 // getElement(elem).style.display == "none" 321 return !elem.classList.contains("invisible"); 322 } 323 324 function toggleNonTests(e) { 325 e.preventDefault(); 326 var elems = document.getElementsByClassName("non-test"); 327 for (var i = 0; i < elems.length; i++) { 328 toggleVisible(elems[i]); 329 } 330 if (!elems.length) { 331 $("toggleNonTests").textContent = "No Non-Tests"; 332 } else if (isVisible(elems[0])) { 333 $("toggleNonTests").textContent = "Hide Non-Tests"; 334 } else { 335 $("toggleNonTests").textContent = "Show Non-Tests"; 336 } 337 } 338 339 // hook up our buttons 340 function hookup() { 341 if (params.manifestFile) { 342 getTestManifest( 343 getTestManifestURL(params.manifestFile), 344 params, 345 hookupTests 346 ); 347 } else { 348 hookupTests(gTestList); 349 } 350 } 351 352 function getPrefList() { 353 if (params.ignorePrefsFile) { 354 loadFile(getTestManifestURL(params.ignorePrefsFile), function (prefs) { 355 TestRunner.ignorePrefs = prefs; 356 RunSet.runall(); 357 }); 358 } else { 359 RunSet.runall(); 360 } 361 } 362 363 function hookupTests(testList) { 364 if (testList.length) { 365 gTestList = testList; 366 } else { 367 gTestList = []; 368 for (var obj in testList) { 369 gTestList.push(testList[obj]); 370 } 371 } 372 373 document.getElementById("runtests").onclick = RunSet.reloadAndRunAll; 374 document.getElementById("toggleNonTests").onclick = toggleNonTests; 375 // run automatically if autorun specified 376 if (params.autorun) { 377 getPrefList(); 378 } 379 } 380 381 function getTestManifestURL(path) { 382 // The test manifest url scheme should be the same protocol as the containing 383 // window... unless it's not http(s) 384 if ( 385 window.location.protocol == "http:" || 386 window.location.protocol == "https:" 387 ) { 388 return window.location.protocol + "//" + window.location.host + "/" + path; 389 } 390 return "http://mochi.test:8888/" + path; 391 }