Bug 663291: Improve the SpecialPowers and SimpleTest APIs to make it easier to write mochitests that look at error console output. Update all tests that were using ad-hoc console inspection or the old SimpleTest console handler API. r=ted

This commit is contained in:
Zack Weinberg
2012-11-16 21:53:32 -05:00
parent f532854bf3
commit a70907e535
11 changed files with 309 additions and 334 deletions

View File

@@ -2,4 +2,3 @@
<meta charset=utf-8> <meta charset=utf-8>
<title>Non-UTF form target</title> <title>Non-UTF form target</title>
<body onload="parent.finish();"> <body onload="parent.finish();">

View File

@@ -1,8 +1,7 @@
<!DOCTYPE html> <!doctype html>
<meta charset=windows-1252> <meta charset=windows-1252>
<title>Non-UTF form</title> <title>Non-UTF form</title>
<body onload="document.forms[0].submit();"> <body onload="document.forms[0].submit();">
<form action="file_bug708620-2.html"> <form action="file_bug708620-2.html">
<input name=foo value=bar> <input name=foo value=bar>
</form> </form>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!doctype html>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=513194 https://bugzilla.mozilla.org/show_bug.cgi?id=513194
@@ -6,67 +6,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=513194
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 513194</title> <title>Test for Bug 513194</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head> </head>
<body> <body>
<pre id="test"> <a target="_blank"
<script class="testbody" type="text/javascript"> href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
>Mozilla Bug 513194</a>
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); <script>
// The use of document.write is deliberate. We are testing for the
const Cc = Components.classes; // HTML parser to call the CSS parser once and only once when it
const Ci = Components.interfaces; // encounters a new <style> element.
const Cr = Components.results; SimpleTest.runTestExpectingConsoleMessages(
function () { document.write("<style>qux { foo : bar; }<\/style>") },
var consoleService = [{ errorMessage: /Unknown property/ }]
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); );
var consoleListener = {
seenError: false,
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (this.seenError) {
ok(false, "Seen too many errors!");
}
this.seenError = true;
ok(message.message.indexOf("Unknown property") > -1,
"Wrong message");
},
finish: function() {
ok(this.seenError , "Didn't get message.");
SimpleTest.finish();
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
consoleService.reset();
consoleService.registerListener(consoleListener);
SimpleTest.waitForExplicitFinish();
document.write("<style>qux { foo: bar; }<\/style>");
function done() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleListener.finish();
consoleService.unregisterListener(consoleListener);
}
setTimeout(done, 0);
</script> </script>
</pre>
</body> </body>
</html> </html>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!doctype html>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=631615 https://bugzilla.mozilla.org/show_bug.cgi?id=631615
@@ -6,76 +6,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=631615
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 631615</title> <title>Test for Bug 631615</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head> </head>
<body> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615">Mozilla Bug 631615</a> <a target="_blank"
<pre id="monitor"> href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
</pre> >Mozilla Bug 631615</a>
<script type="application/javascript"> <pre id="monitor"></pre>
<script>
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
var messageCount = 0;
var monitor = document.getElementById("monitor");
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (message.message === "sentinel") {
is(messageCount, 0, "should have been no console messages");
removeListener();
SimpleTest.finish();
} else {
messageCount++;
var err = "" + messageCount + ": " + message.message + "\n";
monitor.appendChild(document.createTextNode(err));
}
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.unregisterListener(listener);
}
function postSentinel() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.logStringMessage("sentinel");
}
SimpleTest.waitForExplicitFinish();
function doTest() { function doTest() {
var monitor = document.getElementById("monitor");
var html = document.documentElement; var html = document.documentElement;
var results; var results;
var matches = html.matchesSelector || html.mozMatchesSelector; var matches = html.matchesSelector || html.mozMatchesSelector;
addListener();
try { try {
results = "return: " + results = "return: " +
matches.call(html, "[test!='']:sizzle") + "\n"; matches.call(html, "[test!='']:sizzle") + "\n";
@@ -85,11 +30,9 @@ function doTest() {
monitor.appendChild(document.createTextNode(results)); monitor.appendChild(document.createTextNode(results));
is(results.slice(0, 6), "throws", "looking for an exception"); is(results.slice(0, 6), "throws", "looking for an exception");
postSentinel();
} }
doTest();
SimpleTest.runTestExpectingConsoleMessages(doTest, []);
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!doctype html>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=708620 https://bugzilla.mozilla.org/show_bug.cgi?id=708620
@@ -6,61 +6,36 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=708620
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 708620</title> <title>Test for Bug 708620</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head> </head>
<body onload="start();"> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620">Mozilla Bug 708620</a> <a target="_blank"
<p id="display"></p> href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620"
<div id="content" style="display: none"> >Mozilla Bug 708620</a>
<iframe></iframe> <iframe></iframe>
</div> <script>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 708620 **/ /** Test for Bug 708620 **/
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "A form was submitted in the windows-1252 encoding "+
"which cannot encode all Unicode characters, so user "+
"input may get corrupted. To avoid this problem, the "+
"page should be changed so that the form is submitted "+
"in the UTF-8 encoding either by changing the encoding "+
"of the page itself to UTF-8 or by specifying "+
"accept-charset=utf-8 on the form element.",
isWarning: true }
]);
var tests = [ window.onload = function () {
"file_bug708620.html" document.getElementsByTagName("iframe")[0].src = "file_bug708620.html";
];
function resolveURL(relative) {
var a = document.createElement('a');
a.href = relative;
return a.href;
}
var resolvedURL = resolveURL(tests[0]);
var expectedErrors = [
'[JavaScript Warning: "A form was submitted in the windows-1252 encoding which cannot encode all Unicode characters, so user input may get corrupted. To avoid this problem, the page should be changed so that the form is submitted in the UTF-8 encoding either by changing the encoding of the page itself to UTF-8 or by specifying accept-charset=utf-8 on the form element." {file: "' + resolvedURL + '" line: 1}]'
];
function consoleError(msg, fileName) {
// Ignore messages not generated by the test
if (fileName !== resolvedURL) {
return;
}
var expected = expectedErrors.shift();
is(msg, expected, "Not the right error message");
}
SpecialPowers.addErrorConsoleListener(consoleError);
function start() {
var url = tests.shift();
document.getElementsByTagName("iframe")[0].src = url;
} }
function finish() { function finish() {
is(expectedErrors.length, 0, "The error supply was not exhausted"); SimpleTest.endMonitorConsole();
SpecialPowers.removeErrorConsoleListener(consoleError);
SimpleTest.finish();
} }
</script> </script>
</pre>
</body> </body>
</html> </html>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!doctype html>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=489671 https://bugzilla.mozilla.org/show_bug.cgi?id=489671
@@ -6,68 +6,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=489671
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 489671</title> <title>Test for Bug 489671</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head> </head>
<body> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671">Mozilla Bug 489671</a> <a target="_blank"
<p id="display" onclick="throw 'Got click'"></p> href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671"
<div id="content" style="display: none"> >Mozilla Bug 489671</a>
<p id="display" onclick="queueNextTest(); throw 'Got click 1';"></p>
</div> <script>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 489671 **/
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(message.QueryInterface(Ci.nsIScriptError).errorMessage,
"uncaught exception: Got click");
SimpleTest.executeSoon(nextTest);
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.unregisterListener(listener);
}
SimpleTest.waitForExplicitFinish();
addListener();
// override window.onerror so it won't see our exceptions // override window.onerror so it won't see our exceptions
window.onerror = function() {} window.onerror = function() {}
var testNum = 0; var testNum = 0;
function nextTest() { function doTest() {
switch(testNum++) { switch(testNum++) {
case 0: case 0:
var event = document.createEvent("MouseEvents"); var event = document.createEvent("MouseEvents");
@@ -77,22 +29,27 @@ function nextTest() {
break; break;
case 1: case 1:
var script = document.createElement("script"); var script = document.createElement("script");
script.textContent = "throw 'Got click'"; script.textContent = "queueNextTest(); throw 'Got click 2'";
document.body.appendChild(script); document.body.appendChild(script);
break; break;
case 2: case 2:
window.setTimeout("throw 'Got click'", 0); window.setTimeout("queueNextTest(); throw 'Got click 3'", 0);
break; break;
case 3: case 3:
removeListener(); SimpleTest.endMonitorConsole();
SimpleTest.finish(); return;
break;
} }
} }
function queueNextTest() { SimpleTest.executeSoon(doTest); }
nextTest(); SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "uncaught exception: Got click 1" },
{ errorMessage: "uncaught exception: Got click 2" },
{ errorMessage: "uncaught exception: Got click 3" }
]);
doTest();
</script> </script>
</pre>
</body> </body>
</html> </html>

View File

@@ -63,6 +63,7 @@ MOCHITEST_FILES = parser_datreader.js \
test_bug655682.html \ test_bug655682.html \
file_bug655682.sjs \ file_bug655682.sjs \
test_bug667533.html \ test_bug667533.html \
test_bug672453.html \
file_bug672453_not_declared.html \ file_bug672453_not_declared.html \
file_bug672453_late_meta.html \ file_bug672453_late_meta.html \
file_bug672453_meta_restart.html \ file_bug672453_meta_restart.html \
@@ -103,7 +104,4 @@ endif
# Disable test due to frequent orange on Mac # Disable test due to frequent orange on Mac
# test_bug534293.html \ # test_bug534293.html \
# Disabled due to frequent orange (bug 739354)
# test_bug672453.html \
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!doctype html>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=672453 https://bugzilla.mozilla.org/show_bug.cgi?id=672453
@@ -6,22 +6,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=672453
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 672453</title> <title>Test for Bug 672453</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head> </head>
<body> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=672453">Mozilla Bug 672453</a> <a target="_blank"
<p id="display"></p> href="https://bugzilla.mozilla.org/show_bug.cgi?id=672453"
<div id="content" style="display: none"> >Mozilla Bug 672453</a>
<iframe onload="runNextTest();"></iframe> <iframe></iframe>
</div> <script>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 672453 **/ /** Test for Bug 672453 **/
SimpleTest.waitForExplicitFinish();
var tests = [ var tests = [
"file_bug672453_not_declared.html", "file_bug672453_not_declared.html",
"file_bug672453_late_meta.html", "file_bug672453_late_meta.html",
@@ -34,35 +29,66 @@ var tests = [
]; ];
var expectedErrors = [ var expectedErrors = [
'[JavaScript Warning: "The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html" line: 0}]', { errorMessage: "The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it.",
'[JavaScript Warning: "The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html" line: 1028}]', sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html",
'[JavaScript Warning: "The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html" line: 1028}]', lineNumber: 0,
'[JavaScript Error: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html" line: 1}]', isWarning: true,
'[JavaScript Error: "An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html" line: 0}]', isException: false },
'[JavaScript Error: "Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html" line: 0}]', { errorMessage: "The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
'[JavaScript Error: "A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html" line: 1}]', sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html",
'[JavaScript Error: "A meta tag was used to declare a character encoding the does not encode the Basic Latin range roughly like US-ASCII. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html" line: 1}]' lineNumber: 1028,
isWarning: true,
isException: false },
{ errorMessage: "The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html",
lineNumber: 1028,
isWarning: true,
isException: false },
{ errorMessage: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html",
lineNumber: 1,
isWarning: false,
isException: false },
{ errorMessage: "An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html",
lineNumber: 0,
isWarning: false,
isException: false },
{ errorMessage: "Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html",
lineNumber: 0,
isWarning: false,
isException: false },
{ errorMessage: "A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html",
lineNumber: 1,
isWarning: false,
isException: false },
{ errorMessage: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html",
lineNumber: 1,
isWarning: false,
isException: false }
]; ];
function consoleError(msg) { SimpleTest.waitForExplicitFinish();
var expected = expectedErrors.shift();
is(msg, expected, "Not the right error message");
}
SpecialPowers.addErrorConsoleListener(consoleError); window.onload = function() {
var iframe = document.getElementsByTagName("iframe")[0];
function runNextTest() { function runNextTest() {
var url = tests.shift(); var url = tests.shift();
if (!url) { if (!url) {
is(expectedErrors.length, 0, "The error supply was not exhausted"); SimpleTest.endMonitorConsole();
SpecialPowers.removeErrorConsoleListener(consoleError);
SimpleTest.finish();
return; return;
} }
document.getElementsByTagName("iframe")[0].src = url; iframe.src = url;
} }
iframe.onload = runNextTest;
SimpleTest.monitorConsole(SimpleTest.finish, expectedErrors);
runNextTest();
}
</script> </script>
</pre>
</body> </body>
</html> </html>

View File

@@ -693,6 +693,89 @@ SimpleTest.finish = function () {
} }
}; };
/**
* Monitor console output from now until endMonitorConsole is called.
*
* Expect to receive as many console messages as there are elements of
* |msgs|, an array; each element is an object which may have any
* number of the following properties:
* message, errorMessage, sourceName, sourceLine, category:
* string or regexp
* lineNumber, columnNumber: number
* isScriptError, isWarning, isException, isStrict: boolean
* Strings, numbers, and booleans must compare equal to the named
* property of the Nth console message. Regexps must match. Any
* fields present in the message but not in the pattern object are ignored.
*
* After endMonitorConsole is called, |continuation| will be called
* asynchronously. (Normally, you will want to pass |SimpleTest.finish| here.)
*
* It is incorrect to use this function in a test which has not called
* SimpleTest.waitForExplicitFinish.
*/
SimpleTest.monitorConsole = function (continuation, msgs) {
if (SimpleTest._stopOnLoad) {
ok(false, "Console monitoring requires use of waitForExplicitFinish.");
}
var counter = 0;
function listener(msg) {
if (msg.message === "SENTINEL" && !msg.isScriptError) {
is(counter, msgs.length, "monitorConsole | number of messages");
SimpleTest.executeSoon(continuation);
} else if (counter >= msgs.length) {
ok(false, "monitorConsole | extra message | " + JSON.stringify(msg));
} else {
var pat = msgs[counter];
for (k in pat) {
ok(k in msg, "monitorConsole | [" + counter + "]." + k + " present");
if (k in msg) {
if (pat[k] instanceof RegExp && typeof(msg[k]) === 'string') {
ok(pat[k].test(msg[k]),
"monitorConsole | [" + counter + "]." + k + " value - " +
msg[k].quote() + " contains /" + pat[k].source + "/");
} else {
ise(msg[k], pat[k],
"monitorConsole | [" + counter + "]." + k + " value");
}
}
}
counter++;
}
}
SpecialPowers.registerConsoleListener(listener);
};
/**
* Stop monitoring console output.
*/
SimpleTest.endMonitorConsole = function () {
SpecialPowers.postConsoleSentinel();
};
/**
* Run |testfn| synchronously, and monitor its console output.
*
* |msgs| is handled as described above for monitorConsole.
*
* After |testfn| returns, console monitoring will stop, and
* |continuation| will be called asynchronously.
*/
SimpleTest.expectConsoleMessages = function (testfn, msgs, continuation) {
SimpleTest.monitorConsole(continuation, msgs);
testfn();
SimpleTest.executeSoon(SimpleTest.endMonitorConsole);
};
/**
* Wrapper around |expectConsoleMessages| for the case where the test has
* only one |testfn| to run.
*/
SimpleTest.runTestExpectingConsoleMessages = function(testfn, msgs) {
SimpleTest.waitForExplicitFinish();
SimpleTest.expectConsoleMessages(testfn, msgs, SimpleTest.finish);
};
/** /**
* Indicates to the test framework that the current test expects one or * Indicates to the test framework that the current test expects one or
* more crashes (from plugins or IPC documents), and that the minidumps from * more crashes (from plugins or IPC documents), and that the minidumps from

View File

@@ -11,15 +11,16 @@ function SpecialPowers(window) {
this._unexpectedCrashDumpFiles = { }; this._unexpectedCrashDumpFiles = { };
this._crashDumpDir = null; this._crashDumpDir = null;
this.DOMWindowUtils = bindDOMWindowUtils(window); this.DOMWindowUtils = bindDOMWindowUtils(window);
Object.defineProperty(this, 'Components', { configurable: true, enumerable: true, Object.defineProperty(this, 'Components', {
get: function() { var win = this.window.get(); configurable: true, enumerable: true, get: function() {
var win = this.window.get();
if (!win) if (!win)
return null; return null;
return getRawComponents(win); } }); return getRawComponents(win);
}});
this._pongHandlers = []; this._pongHandlers = [];
this._messageListener = this._messageReceived.bind(this); this._messageListener = this._messageReceived.bind(this);
addMessageListener("SPPingService", this._messageListener); addMessageListener("SPPingService", this._messageListener);
this._consoleListeners = [];
} }
SpecialPowers.prototype = new SpecialPowersAPI(); SpecialPowers.prototype = new SpecialPowersAPI();

View File

@@ -9,10 +9,11 @@ var Ci = Components.interfaces;
var Cc = Components.classes; var Cc = Components.classes;
var Cu = Components.utils; var Cu = Components.utils;
Components.utils.import("resource://specialpowers/MockFilePicker.jsm"); Cu.import("resource://specialpowers/MockFilePicker.jsm");
Components.utils.import("resource://specialpowers/MockPermissionPrompt.jsm"); Cu.import("resource://specialpowers/MockPermissionPrompt.jsm");
Components.utils.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function SpecialPowersAPI() { function SpecialPowersAPI() {
this._consoleListeners = []; this._consoleListeners = [];
@@ -379,6 +380,58 @@ SpecialPowersHandler.prototype.enumerate = function() {
return this.getPropertyNames().filter(filt); return this.getPropertyNames().filter(filt);
}; };
// SPConsoleListener reflects nsIConsoleMessage objects into JS in a
// tidy, XPCOM-hiding way. Messages that are nsIScriptError objects
// have their properties exposed in detail. It also auto-unregisters
// itself when it receives a "sentinel" message.
function SPConsoleListener(callback) {
this.callback = callback;
}
SPConsoleListener.prototype = {
observe: function(msg) {
let m = { message: msg.message,
errorMessage: null,
sourceName: null,
sourceLine: null,
lineNumber: null,
columnNumber: null,
category: null,
windowID: null,
isScriptError: false,
isWarning: false,
isException: false,
isStrict: false };
if (msg instanceof Ci.nsIScriptError) {
m.errorMessage = msg.errorMessage;
m.sourceName = msg.sourceName;
m.sourceLine = msg.sourceLine;
m.lineNumber = msg.lineNumber;
m.columnNumber = msg.columnNumber;
m.category = msg.category;
m.windowID = msg.outerWindowID;
m.isScriptError = true;
m.isWarning = ((msg.flags & Ci.nsIScriptError.warningFlag) === 1);
m.isException = ((msg.flags & Ci.nsIScriptError.exceptionFlag) === 1);
m.isStrict = ((msg.flags & Ci.nsIScriptError.strictFlag) === 1);
}
// expose all props of 'm' as read-only
let expose = {};
for (let prop in m)
expose[prop] = 'r';
m.__exposedProps__ = expose;
Object.freeze(m);
this.callback.call(undefined, m);
if (!m.isScriptError && m.message === "SENTINEL")
Services.console.unregisterListener(this);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener])
};
SpecialPowersAPI.prototype = { SpecialPowersAPI.prototype = {
/* /*
@@ -749,6 +802,15 @@ SpecialPowersAPI.prototype = {
return(this._sendSyncMessage('SPPrefService', msg)[0]); return(this._sendSyncMessage('SPPrefService', msg)[0]);
}, },
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
//XXX: these APIs really ought to be removed, they're not e10s-safe. //XXX: these APIs really ought to be removed, they're not e10s-safe.
// (also they're pretty Firefox-specific) // (also they're pretty Firefox-specific)
_getTopChromeWindow: function(window) { _getTopChromeWindow: function(window) {
@@ -760,15 +822,6 @@ SpecialPowersAPI.prototype = {
.getInterface(Ci.nsIDOMWindow) .getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow); .QueryInterface(Ci.nsIDOMChromeWindow);
}, },
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
_getAutoCompletePopup: function(window) { _getAutoCompletePopup: function(window) {
return this._getTopChromeWindow(window).document return this._getTopChromeWindow(window).document
.getElementById("PopupAutoComplete"); .getElementById("PopupAutoComplete");
@@ -800,6 +853,7 @@ SpecialPowersAPI.prototype = {
.getElementById("Browser:Back") .getElementById("Browser:Back")
.hasAttribute("disabled"); .hasAttribute("disabled");
}, },
//XXX end of problematic APIs
addChromeEventListener: function(type, listener, capture, allowUntrusted) { addChromeEventListener: function(type, listener, capture, allowUntrusted) {
addEventListener(type, listener, capture, allowUntrusted); addEventListener(type, listener, capture, allowUntrusted);
@@ -808,36 +862,21 @@ SpecialPowersAPI.prototype = {
removeEventListener(type, listener, capture); removeEventListener(type, listener, capture);
}, },
addErrorConsoleListener: function(listener) { // Note: each call to registerConsoleListener MUST be paired with a
var consoleListener = { // call to postConsoleSentinel; when the callback receives the
userListener: listener, // sentinel it will unregister itself (_after_ calling the
observe: function(consoleMessage) { // callback). SimpleTest.expectConsoleMessages does this for you.
var fileName; // If you register more than one console listener, a call to
try { // postConsoleSentinel will zap all of them.
fileName = consoleMessage.QueryInterface(Ci.nsIScriptError) registerConsoleListener: function(callback) {
.sourceName; let listener = new SPConsoleListener(callback);
} catch (e) { Services.console.registerListener(listener);
}
this.userListener(consoleMessage.message, fileName);
}
};
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.registerListener(consoleListener);
this._consoleListeners.push(consoleListener);
}, },
postConsoleSentinel: function() {
removeErrorConsoleListener: function(listener) { Services.console.logStringMessage("SENTINEL");
for (var index in this._consoleListeners) { },
var consoleListener = this._consoleListeners[index]; resetConsole: function() {
if (consoleListener.userListener == listener) { Services.console.reset();
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.unregisterListener(consoleListener);
this._consoleListeners = this._consoleListeners.splice(index, 1);
break;
}
}
}, },
getMaxLineBoxWidth: function(window) { getMaxLineBoxWidth: function(window) {
@@ -899,11 +938,11 @@ SpecialPowersAPI.prototype = {
}, },
forceGC: function() { forceGC: function() {
Components.utils.forceGC(); Cu.forceGC();
}, },
forceCC: function() { forceCC: function() {
Components.utils.forceCC(); Cu.forceCC();
}, },
exactGC: function(win, callback) { exactGC: function(win, callback) {
@@ -921,14 +960,14 @@ SpecialPowersAPI.prototype = {
} }
} }
Components.utils.schedulePreciseGC(scheduledGCCallback); Cu.schedulePreciseGC(scheduledGCCallback);
} }
doPreciseGCandCC(); doPreciseGCandCC();
}, },
setGCZeal: function(zeal) { setGCZeal: function(zeal) {
Components.utils.setGCZeal(zeal); Cu.setGCZeal(zeal);
}, },
isMainProcess: function() { isMainProcess: function() {
@@ -1202,7 +1241,7 @@ SpecialPowersAPI.prototype = {
} else if (arg.manifestURL) { } else if (arg.manifestURL) {
// It's a thing representing an app. // It's a thing representing an app.
let tmp = {}; let tmp = {};
Components.utils.import("resource://gre/modules/Webapps.jsm", tmp); Cu.import("resource://gre/modules/Webapps.jsm", tmp);
let app = tmp.DOMApplicationRegistry.getAppByManifestURL(arg.manifestURL); let app = tmp.DOMApplicationRegistry.getAppByManifestURL(arg.manifestURL);
if (!app) { if (!app) {