Bug 1006102 - Add mochitest-chrome test related to the Error originAttributes property. draft
authorLuca Greco <lgreco@mozilla.com>
Tue, 31 May 2016 18:31:43 +0200
changeset 375740 b67dee7e2d3f1d049b3524ebecf899b435ec1d55
parent 375739 ac94a30c4c58ee8abbf7c92ec5bcfeea3405c202
child 375741 cacd5541678b70965a2e6ce1e1acfcb2625a4fc4
push id20366
push userluca.greco@alcacoop.it
push dateMon, 06 Jun 2016 15:45:16 +0000
bugs1006102
milestone49.0a1
Bug 1006102 - Add mochitest-chrome test related to the Error originAttributes property. MozReview-Commit-ID: 5HueD4l3Bsr
js/xpconnect/tests/chrome/chrome.ini
js/xpconnect/tests/chrome/test_errorOriginAttributes.html
--- 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>