Bug 1006102 - Add mochitest-chrome test related to the Error originAttributes property.
MozReview-Commit-ID: 5HueD4l3Bsr
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -122,8 +122,9 @@ skip-if = buildapp == 'mulet'
[test_wrappers.xul]
[test_weakmaps.xul]
[test_wrappers-2.xul]
# Disabled until this test gets updated to test the new proxy based wrappers.
skip-if = true
[test_watchpoints.xul]
[test_nsScriptErrorWithStack.html]
[test_windowProxyDeadWrapper.html]
+[test_errorOriginAttributes.html]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_errorOriginAttributes.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for 1036625</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<div id="log"></div>
+<script>
+ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+ Cu.import("resource://gre/modules/Services.jsm");
+
+ SimpleTest.waitForExplicitFinish();
+
+ const FAKE_ADDON_ID = "test-webext-addon@mozilla.org";
+ const numOfExpectedErrors = 5;
+ let collectedErrors = [];
+
+ function checkCollectedErrors(errors) {
+ ok(errors.every((err) => err.originAttributes),
+ "All the collected errors has defined origin attributes");
+
+ let errorOnScriptTag;
+ let errorOnSetTimeout;
+ let errorOnWindowEval;
+ let errorOnAPIListener;
+ let errorOnAPIMethod;
+
+ errors.forEach((error) => {
+ if (/scriptTagError/.test(error.message)) {
+ errorOnScriptTag = error;
+ } else if (/setTimeoutError/.test(error.message)) {
+ errorOnSetTimeout = error;
+ } else if (/windowEvalError/.test(error.message)) {
+ errorOnWindowEval = error;
+ } else if (/registeredListenerError/.test(error.message)) {
+ errorOnAPIListener = error;
+ } else if (/APIMethodError/.test(error.message)) {
+ errorOnAPIMethod = error;
+ }
+ });
+
+ ok(errorOnScriptTag, "Got an error which happened on script tag loading");
+ is(errorOnScriptTag.originAttributes.addonId, FAKE_ADDON_ID,
+ "Got the expected addonId on errors which happen on script tag loading");
+
+ ok(errorOnSetTimeout, "Got an error which happened in a setTimeout event listener");
+ is(errorOnSetTimeout.originAttributes.addonId, FAKE_ADDON_ID,
+ "Got the expected addonId on errors which happen in a setTimeout event listener");
+
+ ok(errorOnAPIMethod, "Got an error which happened in an API Method call");
+ is(errorOnAPIMethod.originAttributes.addonId, FAKE_ADDON_ID,
+ "Got the expected addonId on errors replayed from a API listener exception");
+
+ ok(errorOnWindowEval, "Got an error which happened in a catched and replayed window.eval exception");
+ is(errorOnWindowEval.originAttributes.addonId, FAKE_ADDON_ID,
+ "Got the expected addonId on errors replayed from a window.eval exception");
+
+ ok(errorOnAPIListener, "Got an error which happened in a catched and replayed API Listener");
+ is(errorOnAPIListener.originAttributes.addonId, FAKE_ADDON_ID,
+ "Got the expected addonId on errors replayed from a API listener exception");
+ }
+
+ var TestObserver = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+
+ observe: function test_observe(aSubject)
+ {
+ if (!(aSubject instanceof Ci.nsIScriptError)) {
+ return;
+ }
+
+ collectedErrors.push(aSubject);
+
+ let {originAttributes, innerWindowID, outerWindowID} = aSubject;
+ let {fileName, lineNumber, columnNumber} = aSubject;
+
+ if (collectedErrors.length == numOfExpectedErrors) {
+ Services.console.unregisterListener(TestObserver);
+ checkCollectedErrors(collectedErrors);
+ SimpleTest.finish();
+ }
+ }
+ };
+
+ Services.console.registerListener(TestObserver);
+
+ let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+ let uuid = uuidGenerator.generateUUID().number;
+ uuid = uuid.slice(1, -1); // Strip { and } off the UUID.
+ let baseURI = Services.io.newURI("about:blank", null, null);
+ let originAttributes = {addonId: FAKE_ADDON_ID};
+ let principal = Services.scriptSecurityManager
+ .createCodebasePrincipal(baseURI, originAttributes);
+
+ let chromeWebNav = Services.appShell.createWindowlessBrowser(true);
+ let interfaceRequestor = chromeWebNav.QueryInterface(Ci.nsIInterfaceRequestor);
+ let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
+ docShell.createAboutBlankContentViewer(principal);
+
+ SimpleTest.registerCleanupFunction(function() {
+ if (chromeWebNav) {
+ chromeWebNav.close();
+ chromeWebNav = null;
+ }
+ });
+
+ info("fake webextension docShell created");
+ let win = docShell.contentViewer.DOMDocument.defaultView;
+
+ let script = win.document.createElement("script");
+ script.textContent = "scriptTagError();";
+ win.document.head.appendChild(script);
+
+ win.eval(`window.setTimeout(() => setTimeoutError(), 0);`);
+
+ // Errors raised from an API method
+ let APIMethod = function () {
+ throw win.Error("APIMethodError: Missing mandatory parameter");
+ }
+ Cu.exportFunction(APIMethod, win, {defineAs: "APIMethod"});
+ let script3 = win.document.createElement("script");
+ script3.textContent = "APIMethod();";
+ win.document.head.appendChild(script3);
+
+ // The following are scenarios recognized as executed from the mochitest window
+ // (and it can be verified by looking at its outerWindowID and innerWindowId)
+ // which contains the test code and it is not going to contain the addonId
+ // in its error object, but we can catch & replay the error correctly.
+
+ // Example catchAndLogErrorAsWindow helper
+ function catchAndLogErrorAsWindow(cb, targetWin) {
+ try {
+ cb();
+ } catch(e) {
+ //let frame = Components.stack.caller;
+ let innerWindowID = targetWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+ let scriptError = Cc["@mozilla.org/scripterror;1"]
+ .createInstance(Ci.nsIScriptError);
+ scriptError.initWithWindowID(e.message, e.fileName, null,
+ e.lineNumber, e.columnNumber,
+ Ci.nsIScriptError.errorFlag,
+ "content javascript", innerWindowID);
+ let consoleService = Cc["@mozilla.org/consoleservice;1"]
+ .getService(Ci.nsIConsoleService);
+ consoleService.logMessage(scriptError);
+ }
+ }
+
+ // replay window.eval errors
+ catchAndLogErrorAsWindow(() => {
+ win.eval(`windowEvalError();`);
+ }, win);
+
+ // replay API callback errors
+ let addListener = function (cb) {
+ catchAndLogErrorAsWindow(cb, win);
+ }
+ Cu.exportFunction(addListener, win, {defineAs: "addListener"});
+ let script2 = win.document.createElement("script");
+ script2.textContent = "addListener(() => registeredListenerError());";
+ win.document.head.appendChild(script2);
+</script>