1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Dictionary mapping a test URL to either the string "all", which means that
8 * all tests in this file are expected to fail, or a dictionary mapping test
9 * names to either the boolean |true|, or the string "debug". The former
10 * means that this test is expected to fail in all builds, and the latter
11 * that it is only expected to fail in debug builds.
13 "expectedFailures": {},
16 * If set to true, we will dump the test failures to the console.
18 "dumpFailures": false,
21 * If dumpFailures is true, this holds a structure like necessary for
22 * expectedFailures, for ease of updating the expectations.
27 * List of test results, needed by TestRunner to update the UI.
32 * Number of unlogged passes, to stop buildbot from truncating the log.
33 * We will print a message every MAX_COLLAPSED_MESSAGES passes.
35 "collapsedMessages": 0,
36 "MAX_COLLAPSED_MESSAGES": 100,
39 * Reference to the TestRunner object in the parent frame if the
40 * test and the parent frame are same-origin. Otherwise, return
41 * a stub object that relays method calls to the parent frame's
42 * TestRunner via postMessage calls.
44 "runner": function() {
47 * If true, these tests are running in cross-origin iframes
49 var xOrigin = function(){
51 void parent.TestRunner;
58 return parent === this ? null : parent.TestRunner || parent.wrappedJSObject.TestRunner;
60 let documentURL = new URL(document.URL);
62 currentTestURL: function() {
63 return documentURL.searchParams.get("currentTestURL");
68 harnessType: "SimpleTest",
69 command: "testFinished",
77 return { closeWhenDone: documentURL.searchParams.get("closeWhenDone") };
80 testStatus(url, subtest, status, expected, diagnostic, stack) {
83 harnessType: "SimpleTest",
84 command: "structuredLogger.testStatus",
86 params: [url, subtest, status, expected, diagnostic, stack],
92 expectAssertions(min, max) {
95 harnessType: "SimpleTest",
96 command: "expectAssertions",
108 * Prefixes for the error logging. Indexed first by int(todo) and second by
109 * int(result). Also contains the test's status, and expected status.
113 {status: 'FAIL', expected: 'PASS', message: "TEST-UNEXPECTED-FAIL"},
114 {status: 'PASS', expected: 'PASS', message: "TEST-PASS"}
117 {status: 'FAIL', expected: 'FAIL', message: "TEST-KNOWN-FAIL"},
118 {status: 'PASS', expected: 'FAIL', message: "TEST-UNEXPECTED-PASS"}
123 * Prefix of the path to parent of the the failures directory.
125 "pathprefix": "/tests/dom/imptests/",
128 * Returns the URL of the current test, relative to the root W3C tests
129 * directory. Used as a key into the expectedFailures dictionary.
131 "getPath": function() {
132 var url = this.getURL();
133 if (!url.startsWith(this.pathprefix)) {
136 return url.substring(this.pathprefix.length);
140 * Returns the root-relative URL of the current test.
142 "getURL": function() {
143 return this.runner ? this.runner.currentTestURL : location.pathname;
147 * Report the results in the tests array.
149 "reportResults": function() {
150 var element = function element(aLocalName) {
151 var xhtmlNS = "http://www.w3.org/1999/xhtml";
152 return document.createElementNS(xhtmlNS, aLocalName);
155 var stylesheet = element("link");
156 stylesheet.setAttribute("rel", "stylesheet");
157 stylesheet.setAttribute("href", "/resources/testharness.css");
158 var heads = document.getElementsByTagName("head");
160 heads[0].appendChild(stylesheet);
163 var log = document.getElementById("log");
167 var section = log.appendChild(element("section"));
168 section.id = "summary";
169 section.appendChild(element("h2")).textContent = "Details";
171 var table = section.appendChild(element("table"));
172 table.id = "results";
174 var tr = table.appendChild(element("thead")).appendChild(element("tr"));
175 for (var header of ["Result", "Test Name", "Message"]) {
176 tr.appendChild(element("th")).textContent = header;
179 ["Unexpected Fail", "Pass"],
180 ["Known Fail", "Unexpected Pass"]
182 var tbody = table.appendChild(element("tbody"));
183 for (var test of this.tests) {
184 tr = tbody.appendChild(element("tr"));
185 tr.className = (test.result === !test.todo ? "pass" : "fail");
186 tr.appendChild(element("td")).textContent =
187 statuses[+test.todo][+test.result];
188 tr.appendChild(element("td")).textContent = test.name;
189 tr.appendChild(element("td")).textContent = test.message;
194 * Returns a printable message based on aTest's 'name' and 'message'
197 "formatTestMessage": function(aTest) {
198 return aTest.name + (aTest.message ? ": " + aTest.message : "");
202 * Lets the test runner know about a test result.
204 "_log": function(test) {
205 var url = this.getURL();
206 var message = this.formatTestMessage(test);
207 var result = this.prefixes[+test.todo][+test.result];
210 this.runner.structuredLogger.testStatus(url,
216 var msg = result.message + " | ";
220 msg += " | " + this.formatTestMessage(test);
226 * Logs a message about collapsed messages (if any), and resets the counter.
228 "_logCollapsedMessages": function() {
229 if (this.collapsedMessages) {
231 "name": document.title,
234 "message": "Elided " + this.collapsedMessages + " passes or known failures."
237 this.collapsedMessages = 0;
241 * Maybe logs a result, eliding up to MAX_COLLAPSED_MESSAGES consecutive
244 "_maybeLog": function(test) {
245 var success = (test.result === !test.todo);
246 if (success && ++this.collapsedMessages < this.MAX_COLLAPSED_MESSAGES) {
249 this._logCollapsedMessages();
254 * Reports a test result. The argument is an object with the following
257 * o message (string): message to be reported
258 * o result (boolean): whether this test failed
259 * o todo (boolean): whether this test is expected to fail
261 "report": function(test) {
262 this.tests.push(test);
263 this._maybeLog(test);
267 * Returns true if this test is expected to fail, and false otherwise.
269 "_todo": function(test) {
270 if (this.expectedFailures === "all") {
273 var value = this.expectedFailures[test.name];
274 return value === true || (value === "debug" && !!SpecialPowers.isDebugBuild);
278 * Callback function for testharness.js. Called when one test in a file
281 "result": function(test) {
282 var url = this.getPath();
285 "message": test.message || "",
286 "result": test.status === test.PASS,
287 "todo": this._todo(test)
289 if (this.dumpFailures && test.status !== test.PASS) {
290 this.failures[test.name] = true;
295 * Callback function for testharness.js. Called when the entire test file
298 "finish": function(tests, status) {
299 var url = this.getPath();
301 "name": "Finished test",
302 "message": "Status: " + status.status,
303 "result": status.status === status.OK,
305 url in this.expectedFailures &&
306 this.expectedFailures[url] === "error"
309 this._logCollapsedMessages();
311 if (this.dumpFailures) {
312 dump("@@@ @@@ Failures\n");
313 dump(url + "@@@" + JSON.stringify(this.failures) + "\n");
316 this.runner.testFinished(this.tests.map(function(aTest) {
318 "message": this.formatTestMessage(aTest),
319 "result": aTest.result,
324 this.reportResults();
329 * Log an unexpected failure. Intended to be used from harness code, not
332 "logFailure": function(aTestName, aMessage) {
342 * Timeout the current test. Intended to be used from harness code, not
345 "timeout": async function() {
346 this.logFailure("Timeout", "Test runner timed us out.");
352 var path = W3CTest.getPath();
354 // Get expected fails. If there aren't any, there will be a 404, which is
355 // fine. Anything else is unexpected.
356 var url = W3CTest.pathprefix + "failures/" + path + ".json";
357 var request = new XMLHttpRequest();
358 request.open("GET", url, false);
360 if (request.status === 200) {
361 W3CTest.expectedFailures = JSON.parse(request.responseText);
362 } else if (request.status !== 404) {
363 W3CTest.logFailure("Fetching failures file", "Request status was " + request.status);
367 add_result_callback(W3CTest.result.bind(W3CTest));
368 add_completion_callback(W3CTest.finish.bind(W3CTest));
370 "output": W3CTest.runner && !W3CTest.runner.getParameterInfo().closeWhenDone,
371 "explicit_timeout": true
374 W3CTest.logFailure("Harness setup", "Unexpected exception: " + e);